All of lore.kernel.org
 help / color / mirror / Atom feed
* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-12 10:53 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-12 10:53 UTC (permalink / raw)
  To: linux-kernel, linux-input
  Cc: tammy0524, 曾婷葳 (tammy_tseng)

Hi,
This package of patch is to add support for multitouch behavior for SiS touch products.
The patch of SiS i2c multitouch driver is in input/touchscreen.

Signed-off-by: Tammy Tseng <tammy_tseng@sis.com>

---
diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index e1d8003..edc8e27 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,18 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default y
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
+config FW_SUPPORT_POWERMODE
+		default n
+        bool "SiS FW support power mode"
+        depends on TOUCHSCREEN_SIS_I2C
+        help
+          This enables support power mode provided by SiS firmwave
+
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index 090e61c..e316477 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -6,6 +6,10 @@
 
 wm97xx-ts-y := wm97xx-core.o
 
+ifdef CONFIG_TOUCHSCREEN_SIS_I2C
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
+endif
+
 obj-$(CONFIG_OF_TOUCHSCREEN)		+= of_touchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..2e6fc1a
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1725 @@
+/* drivers/input/touchscreen/sis_i2c.c - I2C Touch panel driver for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2012/11/13
+ * Version:	Android_v2.05.00-A639-1113
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/irq.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major = 0;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class = NULL;
+#endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
+static struct workqueue_struct *sis_wq;
+struct sis_ts_data *ts_bak = 0;
+struct sisTP_driver_data *TPInfo = NULL;
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h);
+static void sis_ts_late_resume(struct early_suspend *h);
+#endif
+
+#ifdef CONFIG_X86
+//static const struct i2c_client_address_data addr_data;
+/* Insmod parameters */
+static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
+#endif
+
+#ifdef _CHECK_CRC
+uint16_t cal_crc (char* cmd, int start, int end);
+#endif
+
+void PrintBuffer(int start, int length, char* buf)
+{
+	int i;
+	for ( i = start; i < length; i++ )
+	{
+		printk("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			printk("\n");
+	}
+	printk("\n");	
+}
+
+int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
+{
+    int ret = -1;
+    struct i2c_msg msg[1];
+
+    msg[0].addr = client->addr;
+    msg[0].flags = 0; //Write
+    msg[0].len = wlength;
+    msg[0].buf = (unsigned char *)wdata;
+
+    ret = i2c_transfer(client->adapter, msg, 1);
+
+    return ret;
+}
+
+int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
+{
+    int ret = -1;
+    struct i2c_msg msg[1];
+
+    msg[0].addr = client->addr;
+    msg[0].flags = I2C_M_RD; //Read
+    msg[0].len = rlength;
+    msg[0].buf = rdata;
+
+    ret = i2c_transfer(client->adapter, msg, 1);
+
+    return ret;
+}
+
+int sis_cul_unit(uint8_t report_id)
+{
+	int basic = 6;
+	int area = 2;
+	int pressure = 1;
+	int ret = basic;
+	
+	if (report_id != ALL_IN_ONE_PACKAGE)
+	{
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+		{
+			ret += area;
+		}
+		if (IS_PRESSURE(report_id))
+		{
+			ret += pressure;
+		}
+	}
+	
+	return ret;	
+}
+
+int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
+{
+	uint8_t tmpbuf[MAX_BYTE] = {0};	//MAX_BYTE = 64;
+#ifdef _CHECK_CRC
+	uint16_t buf_crc = 0;
+	uint16_t package_crc = 0;
+	int l_package_crc = 0;
+	int crc_end = 0;
+#endif
+    int ret = -1;
+    int touchnum = 0;
+    int p_count = 0;
+    int touc_formate_id = 0;
+    int locate = 0;
+    bool read_first = true;
+    
+/*
+		New i2c format 
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
+	* buf[touch num * 6 + 3] = Touch numbers
+	* 
+	* One touch point information include 6 bytes, the order is 
+	* 
+	* 1. status = touch down or touch up
+	* 2. id = finger id 
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	* 
+*/
+	do
+	{
+		if (locate >= PACKET_BUFFER_SIZE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
+			return -1;
+		}
+		
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+
+#ifdef _DEBUG_PACKAGE
+		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+		PrintBuffer(0, 64, tmpbuf);	
+#endif			
+
+		if(ret < 0 )
+		{
+			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		// error package length of receiving data
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
+			return -1;	
+		}
+		
+		if (read_first)
+		{
+#ifdef _SUPPORT_BUTTON_TOUCH
+			// access BUTTON TOUCH event and BUTTON NO TOUCH event
+			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
+			{
+				memcpy(&buf[0], &tmpbuf[0], 7);
+				return touchnum; 	//touchnum is 0
+			}
+#endif 
+			// access NO TOUCH event unless BUTTON NO TOUCH event
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+			{
+				return touchnum;	//touchnum is 0
+			}
+		}
+
+		//skip parsing data when two devices are registered at the same slave address
+		//parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
+			return -1;		
+		}
+		
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	//start from 0
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
+		{
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_I2C;	//delete 2 byte crc
+			}
+			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_HIDI2C;
+			}
+			else	//should not be happen
+			{
+				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
+				return -1;
+			}
+
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_SCANTIME;
+			}
+		}
+		//else {}    						// For ALL_IN_ONE_PACKAGE
+		
+		if (read_first)
+		{
+			touchnum = tmpbuf[p_count]; 	
+		}
+		else
+		{
+			if (tmpbuf[p_count] != 0)
+			{
+				printk(KERN_ERR "sis_ReadPacket: get error package\n");
+				return -1;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		buf_crc = cal_crc(tmpbuf, 2, crc_end); //sub bytecount (2 byte)
+		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		package_crc = ((tmpbuf[l_package_crc] & 0xff) | ((tmpbuf[l_package_crc + 1] & 0xff) << 8));
+			
+		if (buf_crc != package_crc)
+		{
+			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
+			return -1;
+		}
+#endif	
+		memcpy(&buf[locate], &tmpbuf[0], 64);	//Buf_Data [0~63] [64~128]
+		locate += 64;
+		read_first = false;
+		
+	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
+
+	return touchnum;
+}	
+
+
+int check_gpio_interrupt(void)
+{
+    int ret = 0;
+    //TODO
+    //CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING.
+    ret = gpio_get_value(GPIO_IRQ);
+    return ret;
+}
+
+void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
+{
+	int i = 0;
+	uint8_t diff_keybit_state= 0x0; //check keybit_state is difference with pre_keybit_state
+	uint8_t key_value = 0x0; //button location for binary
+	uint8_t  key_pressed = 0x0; //button is up or down
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts)
+	{
+		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state)
+	{
+		for (i = 0; i < BUTTON_KEY_COUNT; i++)
+		{
+		    if ((diff_keybit_state >> i) & 0x01)
+			{
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value)
+				{
+					case MSK_COMP:
+						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
+						printk(KERN_ERR "%s : MSK_COMP %d \n", __func__ , key_pressed);
+						break;
+					case MSK_BACK:
+						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
+						printk(KERN_ERR "%s : MSK_BACK %d \n", __func__ , key_pressed);
+						break;
+					case MSK_MENU:
+						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
+						printk(KERN_ERR "%s : MSK_MENU %d \n", __func__ , key_pressed);
+						break;
+					case MSK_HOME:
+						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
+						printk(KERN_ERR "%s : MSK_HOME %d \n", __func__ , key_pressed);
+						break;
+					case MSK_NOBTN:
+						//Release the button if it touched.
+					default:
+						break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+
+
+static void sis_ts_work_func(struct work_struct *work)
+{
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+    int ret = -1;
+    int point_unit;  
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+    uint8_t p_preasure = 0;
+#ifdef _SUPPORT_BUTTON_TOUCH	
+	int button_key;
+	uint8_t button_buf[10] = {0};
+#endif
+
+#ifdef _ANDROID_4
+	bool all_touch_up = true;
+#endif
+	
+	mutex_lock(&ts->mutex_wq); 
+
+    /* I2C or SMBUS block data read */
+    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+#ifdef _DEBUG_PACKAGE_WORKFUNC
+	printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+	PrintBuffer(0, 64, buf);			
+	if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (ret > 5))
+	{
+		printk(KERN_INFO "chaoban test: Buf_Data [64~125] \n");
+		PrintBuffer(64, 128, buf);	
+	}
+#endif
+
+// add 
+#ifdef _SUPPORT_BUTTON_TOUCH
+	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
+#endif
+
+	if (ret < 0) // Error Number
+	{
+	    printk(KERN_INFO "chaoban test: ret = -1\n");
+		goto err_free_allocate;
+	}
+#ifdef _SUPPORT_BUTTON_TOUCH
+	// access BUTTON TOUCH event and BUTTON NO TOUCH even
+	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
+	{
+		//fingers = 0; //modify
+		button_key = ((button_buf[BUTTON_STATE] & 0xff) | ((button_buf[BUTTON_STATE + 1] & 0xff)<< 8));		
+		ts_report_key(ts->client, button_key);
+		//goto err_free_allocate; //modify
+	}
+#endif
+	// access NO TOUCH event unless BUTTON NO TOUCH event
+	else if (ret == 0)
+	{
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;  //need to report input_mt_sync()
+	}
+	
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+	
+	/* Parser and Get the sis9200 data */
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+	
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+	
+	for (i = 0; i < fingers; i++) // fingers 10 =  0 ~ 9
+	{
+        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
+        {
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	// Calc point status
+			pstatus += 64;
+		}
+		else 
+		{
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	// Calc point status
+		}
+
+	    px = pstatus + 2;                   			// Calc point x_coord
+	    py = px + 2;                        			// Calc point y_coord
+
+		if ((buf[pstatus]) == TOUCHUP)
+		{
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		}
+		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
+		{
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;			
+		}
+		else if ((buf[pstatus]) == TOUCHDOWN)
+		{	
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+
+			//area		
+			if (IS_AREA(buf[P_REPORT_ID]))
+			{
+				TPInfo->pt[i].Width = buf[p_area] & 0xff;
+				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
+			}
+			else 
+			{
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			//preasure
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else 
+				TPInfo->pt[i].Pressure = 1;				
+		}
+		else
+		{
+			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
+        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
+	}
+		
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+	{
+		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
+	}
+#endif
+
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+#ifdef _ANDROID_4	
+	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
+	{
+		if(TPInfo->pt[i].Pressure)
+		{
+			TPInfo->pt[i].Width *= AREA_UNIT;	
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);     //Android 2.3
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		
+		if (i == (TPInfo->fingers -1) && all_touch_up == true)
+		{
+			input_mt_sync(ts->input_dev);
+		}
+	}
+
+	if(TPInfo->fingers == 0)
+	{
+		input_mt_sync(ts->input_dev);
+	}
+#else
+	i = 0;
+	do
+	{
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);		//Android 2.3
+		input_mt_sync(ts->input_dev);
+		i++;
+	}
+	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
+#endif
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+    if (ts->use_irq)
+    {
+#ifdef _INT_MODE_1 //case 1 mode
+	    //TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high
+	    ret = check_gpio_interrupt();	//interrupt pin is still LOW, read data until interrupt pin is released.
+	    if (!ret)
+	    {
+	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	    }
+	    else
+	    {
+			if (TPInfo->pre_keybit_state)
+			{
+				ts_report_key(ts->client, 0x0);	//clear for interrupt
+			}
+			
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+        	{
+				enable_irq(ts->client->irq);
+			}
+	    }
+#else // case 2 mode
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(ts->client->irq);
+		}
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+    return;
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
+{
+	int i = 0;
+	for(i = 0; i < max; i++)
+	{
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
+{
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)
+	{	// For Polling mode
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	}
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+	struct sis_ts_data *ts = dev_id;
+	
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+	{
+		disable_irq_nosync(ts->client->irq);
+	}
+	queue_work(sis_wq, &ts->work);
+		
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	/* TODO */
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");	// ex. GPIO_133 for interrupt mode
+	if (ret < 0)
+	{
+		// Set Active Low. Please reference the file include/linux/interrupt.h
+		printk(KERN_ERR "sis_ts_probe: Failed to gpio_request\n");
+		printk(KERN_ERR "sis_ts_probe: Fail : gpio_request was called before this driver call\n");
+	}	
+	/* setting gpio direction here OR boardinfo file*/
+	/* TODO */
+#else
+	ret = -1;
+#endif
+	return ret;
+}
+
+uint16_t cal_crc (char* cmd, int start, int end)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
+	}
+	return crc;
+}
+
+uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
+	}
+	return crc;
+}
+
+void write_crc (unsigned char *buf, int start, int end)
+{
+	uint16_t crc = 0;
+	crc = cal_crc (buf, start , end);
+	buf[end+1] = (crc >> 8)& 0xff;
+	buf[end+2] = crc & 0xff;
+}
+
+/*
+ * When you will send commad to chip, you should use this function on 
+ * the first time.
+ * 
+ * Return:If switch success return ture, else return false.
+ */
+bool sis_switch_to_cmd_mode(struct i2c_client *client)
+{
+	int ret = -1;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
+		0x00, 0x85, 0x0d, 0x51, 0x09};
+	uint8_t sis817_cmd_enable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
+		0x00, 0x09, 0x00, 0x85, 0x5c, 0x21, 0x01};
+	
+	
+	
+	//Send 85 CMD - PWR_CMD_ACTIVE
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}
+	
+	msleep(100);
+	memset(tmpbuf, 0, sizeof(tmpbuf));
+	
+	//Send 85 CMD - ENABLE_DIAGNOSIS_MODE
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_enable_diagnosis), sis817_cmd_enable_diagnosis);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	msleep(50);
+	return true;	
+}
+
+/*
+ * When chip in the command mode will switch to work, you should use 
+ * this function.
+ * 
+ * Return:If switch success return ture, else return false.
+ */
+bool sis_switch_to_work_mode(struct i2c_client *client)
+{
+	int ret = -1;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
+		0x00, 0x85, 0x3c, 0x50, 0x09};
+	uint8_t sis817_cmd_disable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
+		0x00, 0x09, 0x00, 0x85, 0x6d, 0x20, 0x01};
+	
+	
+	//Send 85 CMD - PWR_CMD_FW_CTRL
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}
+
+	memset(tmpbuf, 0, sizeof(tmpbuf));
+	
+	//Send 85 CMD - DISABLE_DIAGNOSIS_MODE
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_disable_diagnosis), sis817_cmd_disable_diagnosis);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	msleep(50);
+	return true;
+}
+
+/*
+ * Use this function get FW ID.
+ */
+bool sis_get_fw_id(struct i2c_client *client)
+{
+  	int ret = 0;
+  	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_get_FW_ID[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
+		0x00, 0x86, 0x00, 0x0c, 0xc0, 0x00, 0xa0, 0x04, 0x00};
+	
+	sis817_cmd_get_FW_ID[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_get_FW_ID, 8, 13, 0x86));
+
+	if(!sis_switch_to_cmd_mode(client)){
+		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
+		return false;
+	}
+	
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_get_FW_ID), sis817_cmd_get_FW_ID);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
+	}
+
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	printk(KERN_INFO "SiS FW ID : ");
+	PrintBuffer(8, 12, tmpbuf);	
+
+	if(!sis_switch_to_work_mode(client)){
+		printk(KERN_ERR "SiS Switch to Work mode error.\n");
+		return false;
+	}
+	
+	if(ret < 0) return false;
+	return true;
+		
+}
+
+/*
+ * Use this function check chip status.
+ * 
+ * Return:Ture is chip on the work function, else is chip not ready.
+ */
+bool sis_check_fw_ready(struct i2c_client *client)
+{
+  	int ret = 0;
+  	int check_num = 10;
+  	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_check_ready[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
+		0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
+	
+	
+	sis817_cmd_check_ready[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_ready, 8, 13, 0x86));
+	
+
+	if(!sis_switch_to_cmd_mode(client)){
+		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
+		return false;
+	}
+	
+	while(check_num--){
+		printk(KERN_ERR "SiS Check FW Ready.\n");
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_check_ready), sis817_cmd_check_ready);
+		if(ret < 0){
+			printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
+		}
+		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+		if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return NACK\n");
+		}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return Unknow\n");
+		}else{
+			if(tmpbuf[9] == 1){
+				printk(KERN_ERR "SiS FW READY.\n");
+				break;
+			}
+		}
+		printk(KERN_ERR "SiS CHECK FW READY - Retry:%d.\n", (10-check_num));	
+		msleep(50);
+	}
+	
+	if(!sis_switch_to_work_mode(client)){
+		printk(KERN_ERR "SiS Switch to Work mode error.\n");
+		return false;
+	}
+	
+	if(check_num == 0) return false;
+	return true;
+		
+}
+
+/*
+ * Use this function to change chip power mode. 
+ * 
+ * mode:POWER_MODE_FWCTRL, power control by FW.
+ * 		POWER_MODE_ACTIVE, chip always work on time.
+ * 		POWER_MODE_SLEEP,  chip on the sleep mode.
+ * 
+ * Return:Ture is change power mode success.
+ */
+bool sis_change_fw_mode(struct i2c_client *client, enum SIS_817_POWER_MODE mode)
+{
+	int ret = -1;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x3c, 0x50, 0x09};
+	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x0d, 0x51, 0x09};
+	uint8_t sis817_cmd_sleep[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x5e, 0x52, 0x09};
+	
+	
+	switch(mode)
+	{
+	case POWER_MODE_FWCTRL:
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
+		break;
+	case POWER_MODE_ACTIVE:
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
+		break;
+	case POWER_MODE_SLEEP:
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_sleep), sis817_cmd_sleep);
+		break;
+	default:
+		return false;
+		break;
+	}
+
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Power CMD Faile - 85\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Power CMD Faile - 85\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Power CMD Return NACK - 85\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Power CMD Return Unknow- 85\n");
+		return false;
+	}
+	
+	msleep(100);
+	
+	return true;
+}
+
+/*
+ * Use this function to get chip work status. 
+ * 
+ * Return:-1 is get firmware work status error.
+ * 		  POWER_MODE_FWCTRL, power control by FW.
+ * 		  POWER_MODE_ACTIVE, chip always work on time.
+ * 		  POWER_MODE_SLEEP,  chip on the sleep mode.
+ */
+enum SIS_817_POWER_MODE sis_get_fw_mode(struct i2c_client *client)
+{
+	int ret;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_check_power_mode[14] = {0x04, 0x00, 0x0c, 0x00, 
+		0x09, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
+
+	printk(KERN_INFO "SiS Get FW Mode.\n");	
+	sis817_cmd_check_power_mode[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_power_mode, 8, 13, 0x86));
+	
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_check_power_mode), sis817_cmd_check_power_mode);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Get FW Mode CMD Faile - 86\n");
+	}else{
+		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+		if(ret < 0){
+			printk(KERN_ERR "SiS READ Get FW Mode CMD Faile - 86\n");
+		}else{
+			if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return NACK\n");
+			}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return Unknow\n");
+				PrintBuffer(0, sizeof(tmpbuf), tmpbuf);
+			}
+		}
+	}
+	
+	switch(tmpbuf[10])
+	{
+	case POWER_MODE_FWCTRL:
+		return POWER_MODE_FWCTRL;
+	case POWER_MODE_ACTIVE:
+		return POWER_MODE_ACTIVE;
+	case POWER_MODE_SLEEP:
+		return POWER_MODE_SLEEP;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+/*
+ * Use this function to reset chip. 
+ */
+void sis_fw_softreset(struct i2c_client *client)
+{
+
+	int ret = 0;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_reset[8] = {0x04, 0x00, 0x06, 0x00, 0x09, 0x00, 0x82, 0x00};
+	
+
+	sis817_cmd_reset[BUF_CRC_PLACE] = (0xFF & cal_crc(sis817_cmd_reset, 6, 6));
+
+	printk(KERN_ERR "SiS Software Reset.\n");
+	if(!sis_switch_to_cmd_mode(client)){
+		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
+		return;
+	}
+	
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_reset), sis817_cmd_reset);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Reset CMD Faile - 82\n");
+	}
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Reset CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Reset CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
+	}	
+	msleep(2000);
+}
+
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 
+	 printk(KERN_INFO "sis_cdev_write.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     } 
+#if 0
+	PrintBuffer(0, count, kdata);
+#endif
+		
+	cmd = kdata[6];
+
+    printk(KERN_INFO "io cmd=%02x\n", cmd);
+
+//Write & Read
+    ret = sis_command_for_write(ts_bak->client, count, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+//for get system time
+static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 int i;
+	 printk(KERN_INFO "sis_cdev_read.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }    
+#if 0
+    PrintBuffer(0, count, kdata);
+#endif
+	 cmd = kdata[6];
+	 //for making sure AP communicates with SiS driver
+    if(cmd == 0xa2)
+    {
+		kdata[0] = 5;
+		kdata[1] = 0;
+		kdata[3] = 'S';
+		kdata[4] = 'i';
+		kdata[5] = 'S';
+		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+		{
+			printk(KERN_ERR "copy_to_user fail\n" );
+			kfree( kdata );
+			return -19;
+		}
+
+		kfree( kdata );
+		return 3;	
+	}
+//Write & Read
+    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+	ret = kdata[0] | (kdata[1] << 8);
+
+/*
+    for ( i = 0; i < BUFFER_SIZE - 1; i++ ) {
+	    kdata[i] = kdata[i+1];
+    }
+*/
+
+    printk(KERN_INFO "%d\n", ret);
+
+    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
+    {
+        printk("%02x ", kdata[i]);
+    }
+
+    printk( "\n" );
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_open.\n");
+	if ( ts_bak == 0 )
+    	return -13;
+
+	msleep(200);
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif	
+		{
+			disable_irq(ts_bak->client->irq);
+		}
+		else
+		{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
+#else
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
+#endif	
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+
+	flush_workqueue(sis_wq); 	   // only flush sis_wq
+    
+    msleep(200);
+
+	return 0; /* success */
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_release.\n");
+	 msleep(200);
+    if (ts_bak == 0)
+    	return -13;
+
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif	
+		{
+			enable_irq(ts_bak->client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+    return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts)
+{
+	
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int alloc_ret = 0;
+	int cdev_err = 0;
+	int input_err = 0;
+	struct device *class_dev = NULL;
+	void *ptr_err;
+	
+	printk("sis_setup_chardev.\n");
+	
+	if (ts == NULL) 
+	{
+	  input_err = -ENOMEM;
+	  goto error;
+	} 
+	 // dynamic allocate driver handle
+	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
+	if (alloc_ret)
+		goto error;
+		
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
+	
+	if (cdev_err) 
+		goto error;
+	
+	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
+	
+	// register class
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+	
+	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
+	
+	if(IS_ERR(ptr_err = class_dev)) 
+	{
+		goto err;
+	}
+	
+	return 0;
+error:
+	if (cdev_err == 0)
+		cdev_del(&sis_char_cdev);
+	if (alloc_ret == 0)
+		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
+	if(input_err != 0)
+	{
+		printk("sis_ts_bak error!\n");
+	}
+err:
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+err2:
+	class_destroy(sis_char_class);
+	return -1;
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+    printk(KERN_INFO "sis_ts_probe\n");
+
+    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+    if (TPInfo == NULL) 
+    {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) 
+	{
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts_bak = ts;
+
+	mutex_init(&ts->mutex_wq);
+	
+	//1. Init Work queue and necessary buffers
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+    pdata = client->dev.platform_data;
+
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) 
+	{
+		ret = ts->power(1);
+		if (ret < 0) 
+		{
+			printk(KERN_ERR "sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+
+	//2. Allocate input device
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) 
+	{
+		ret = -ENOMEM;
+		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+
+	//This input device name should be the same to IDC file name.
+	ts->input_dev->name = "sis_touch";//"SiS9200-i2c-touchscreen";
+
+	sis_get_fw_id(client);
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+		//sis_check_fw_ready(client);
+#endif
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+
+#ifdef _ANDROID_4
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
+#else
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
+#endif
+
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
+	
+    /* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+
+	//3. Register input device to core
+	ret = input_register_device(ts->input_dev);
+
+	if (ret) 
+	{
+		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	
+	//4. irq or timer setup
+	ret = initial_irq();
+	if (ret < 0) 
+	{
+
+	}
+	else
+	{
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0) 
+		{
+		   ts->use_irq = 1;
+		}
+		else 
+		{
+			dev_err(&client->dev, "request_irq failed\n");
+		}
+	}
+
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+
+	if (!ts->use_irq) 
+	{
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+	
+	if (ts->use_irq)
+	{
+#ifdef _INT_MODE_1
+		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
+#else
+		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
+#endif
+	}
+	
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if(ret)
+	{
+		printk( KERN_INFO"sis_setup_chardev fail\n");
+	}
+#endif
+
+	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+
+	return 0;
+
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client)
+{
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+	int retry = 5;
+#endif
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+		{
+			disable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_cancel(&ts->timer);
+	flush_workqueue(sis_wq); 	   		// only flush sis_wq
+//	flush_scheduled_work(); 		   	// flush all of workqueue in kernel
+//	ret = cancel_work_sync(&ts->work); 	// only cancel one work(sis_ts_work_func), 
+										// but there maybe are others in workqueue.
+/*
+	// For cancel_work_sync()
+	if (ret && ts->use_irq) //if work was pending disable-count is now 2
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+*/
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+		while ((sis_get_fw_mode(client) != POWER_MODE_SLEEP))
+		{
+			
+			if(sis_change_fw_mode(client, POWER_MODE_SLEEP)){
+				printk(KERN_ERR "sis_ts_suspend: change mode retry - %d\n", 5-retry);
+			}
+
+			if (retry == 0){
+				printk(KERN_ERR "sis_ts_suspend: change mode failed\n");
+				break;
+			}
+
+			retry--;
+			msleep(50);
+		}
+#endif
+
+
+#if 0
+	/* Turn off SiS Chip*/
+	/* TODO */
+	gpio_direction_output(TOUCH_RESET_PIN, 0);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
+//	msleep(5);
+	gpio_direction_output(TOUCH_POWER_PIN, 0);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power off\n");
+#endif
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_suspend power off failed\n");
+	}
+	
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+	int retry = 5;
+#endif
+
+	if (ts->power)
+	{
+		ret = ts->power(1);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_resume power on failed\n");
+	}
+
+#if 0
+	/* Turn on SiS Chip*/
+	/* TODO */
+	gpio_direction_output(TOUCH_POWER_PIN, 1);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power on\n");
+	msleep(5);
+	gpio_direction_output(TOUCH_RESET_PIN, 1);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
+	msleep(5);
+	gpio_direction_output(TOUCH_RESET_PIN, 0);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
+	msleep(5);
+	gpio_direction_output(TOUCH_RESET_PIN, 1);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
+#endif
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+		while ((sis_get_fw_mode(client) != POWER_MODE_FWCTRL))
+		{
+			
+			if(sis_change_fw_mode(client, POWER_MODE_FWCTRL)){
+				printk(KERN_ERR "sis_ts_resume: change mode retry - %d\n", 5-retry);
+			}
+
+			if (retry == 0){
+				printk(KERN_ERR "sis_ts_resume: change mode failed\n");
+				break;
+			}
+				
+			retry--;
+			msleep(50);
+		}
+#endif
+		//sis_fw_softreset(client);
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void sis_ts_late_resume(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+    .class      = I2C_CLASS_HWMON,
+    .detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __devinit sis_ts_init(void)
+{
+	printk( KERN_INFO "sis_ts_init\n" );
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+	return i2c_add_driver(&sis_ts_driver);
+}
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+    printk(KERN_INFO "sis_ts_detect\n");
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	return 0;
+}
+#endif
+
+static void __exit sis_ts_exit(void)
+{
+#ifdef _STD_RW_IO
+	dev_t dev;
+#endif
+
+	printk(KERN_INFO "sis_ts_exit\n");
+	i2c_del_driver(&sis_ts_driver);
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+
+#ifdef _STD_RW_IO
+	dev = MKDEV(sis_char_major, 0);
+	cdev_del(&sis_char_cdev);
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+	class_destroy(sis_char_class);
+#endif
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..1ace42a
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,229 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2012/11/13
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+#define TIMER_NS    					10000000 //10ms
+#define MAX_FINGERS						10
+
+
+/* For Android 4.0 							*/
+/* Only for Linux kernel 2.6.34 and later 	*/
+#define _ANDROID_4					//  ON/OFF
+
+/* For standard R/W IO*/
+#define _STD_RW_IO						//  ON/OFF
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					//  ON/OFF
+#define GPIO_IRQ 						133
+
+/*  Enable if use interrupt case 1 mode.  */
+/* 	Disable if use interrupt case 2 mode. */
+//#define _INT_MODE_1					//	ON/OFF
+
+/* IRQ STATUS */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+#define IRQ_STATUS_DISABLED				0x200  
+#else
+#define IRQ_STATUS_DISABLED				(1<<16)
+#endif
+#define IRQ_STATUS_ENABLED				0x0
+
+/* Resolution mode */
+// Constant value 
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE  					8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE       		0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID	                		0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+#ifdef _ANDROID_4
+#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
+#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
+#define AREA_UNIT						(5792/32)
+#else
+#define AREA_LENGTH_LONGER				31
+#define AREA_LENGTH_SHORT				31
+#endif
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0 
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					(x & 0x6)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+//#define _DEBUG_PACKAGE				//  ON/OFF
+//#define _DEBUG_PACKAGE_WORKFUNC		//  ON/OFF
+//#define _DEBUG_REPORT					//  ON/OFF
+
+#ifdef OLD_FORMAT_AEGIS
+#define TOUCH_NUM						1
+#define BUTTON_KEY_COUNT				8
+#define BUTTON_TOUCH					0x05
+#define BUTTON_TOUCH_ONE_POINT			0x0A
+#define BUTTON_TOUCH_MULTI_TOUCH		0x0F
+#define MSK_BUTTON_POINT				0xf0
+#define BUTTON_TOUCH_SERIAL				0x70
+#define BUTTON_STATE					(CMD_BASE + 1)
+
+#else
+//#define _CHECK_CRC					//  ON/OFF
+//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+#endif
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+#endif /* _LINUX_SIS_I2C_H */
+
+enum SIS_817_POWER_MODE{
+	POWER_MODE_FWCTRL = 0x50,
+	POWER_MODE_ACTIVE = 0x51,
+	POWER_MODE_SLEEP  = 0x52
+};
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+static const unsigned short crc16tab[256]= {
+		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;   	// uint16_t ?
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;	
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
+static int sis_ts_resume(struct i2c_client *client);

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-12 10:53 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-12 10:53 UTC (permalink / raw)
  To: linux-kernel, linux-input
  Cc: tammy0524, 曾婷葳 (tammy_tseng)

Hi,
This package of patch is to add support for multitouch behavior for SiS touch products.
The patch of SiS i2c multitouch driver is in input/touchscreen.

Signed-off-by: Tammy Tseng <tammy_tseng@sis.com>

---
diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index e1d8003..edc8e27 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,18 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default y
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
+config FW_SUPPORT_POWERMODE
+		default n
+        bool "SiS FW support power mode"
+        depends on TOUCHSCREEN_SIS_I2C
+        help
+          This enables support power mode provided by SiS firmwave
+
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index 090e61c..e316477 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -6,6 +6,10 @@
 
 wm97xx-ts-y := wm97xx-core.o
 
+ifdef CONFIG_TOUCHSCREEN_SIS_I2C
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
+endif
+
 obj-$(CONFIG_OF_TOUCHSCREEN)		+= of_touchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..2e6fc1a
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1725 @@
+/* drivers/input/touchscreen/sis_i2c.c - I2C Touch panel driver for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2012/11/13
+ * Version:	Android_v2.05.00-A639-1113
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/irq.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major = 0;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class = NULL;
+#endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
+static struct workqueue_struct *sis_wq;
+struct sis_ts_data *ts_bak = 0;
+struct sisTP_driver_data *TPInfo = NULL;
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h);
+static void sis_ts_late_resume(struct early_suspend *h);
+#endif
+
+#ifdef CONFIG_X86
+//static const struct i2c_client_address_data addr_data;
+/* Insmod parameters */
+static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
+#endif
+
+#ifdef _CHECK_CRC
+uint16_t cal_crc (char* cmd, int start, int end);
+#endif
+
+void PrintBuffer(int start, int length, char* buf)
+{
+	int i;
+	for ( i = start; i < length; i++ )
+	{
+		printk("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			printk("\n");
+	}
+	printk("\n");	
+}
+
+int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
+{
+    int ret = -1;
+    struct i2c_msg msg[1];
+
+    msg[0].addr = client->addr;
+    msg[0].flags = 0; //Write
+    msg[0].len = wlength;
+    msg[0].buf = (unsigned char *)wdata;
+
+    ret = i2c_transfer(client->adapter, msg, 1);
+
+    return ret;
+}
+
+int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
+{
+    int ret = -1;
+    struct i2c_msg msg[1];
+
+    msg[0].addr = client->addr;
+    msg[0].flags = I2C_M_RD; //Read
+    msg[0].len = rlength;
+    msg[0].buf = rdata;
+
+    ret = i2c_transfer(client->adapter, msg, 1);
+
+    return ret;
+}
+
+int sis_cul_unit(uint8_t report_id)
+{
+	int basic = 6;
+	int area = 2;
+	int pressure = 1;
+	int ret = basic;
+	
+	if (report_id != ALL_IN_ONE_PACKAGE)
+	{
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+		{
+			ret += area;
+		}
+		if (IS_PRESSURE(report_id))
+		{
+			ret += pressure;
+		}
+	}
+	
+	return ret;	
+}
+
+int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
+{
+	uint8_t tmpbuf[MAX_BYTE] = {0};	//MAX_BYTE = 64;
+#ifdef _CHECK_CRC
+	uint16_t buf_crc = 0;
+	uint16_t package_crc = 0;
+	int l_package_crc = 0;
+	int crc_end = 0;
+#endif
+    int ret = -1;
+    int touchnum = 0;
+    int p_count = 0;
+    int touc_formate_id = 0;
+    int locate = 0;
+    bool read_first = true;
+    
+/*
+		New i2c format 
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
+	* buf[touch num * 6 + 3] = Touch numbers
+	* 
+	* One touch point information include 6 bytes, the order is 
+	* 
+	* 1. status = touch down or touch up
+	* 2. id = finger id 
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	* 
+*/
+	do
+	{
+		if (locate >= PACKET_BUFFER_SIZE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
+			return -1;
+		}
+		
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+
+#ifdef _DEBUG_PACKAGE
+		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+		PrintBuffer(0, 64, tmpbuf);	
+#endif			
+
+		if(ret < 0 )
+		{
+			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		// error package length of receiving data
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
+			return -1;	
+		}
+		
+		if (read_first)
+		{
+#ifdef _SUPPORT_BUTTON_TOUCH
+			// access BUTTON TOUCH event and BUTTON NO TOUCH event
+			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
+			{
+				memcpy(&buf[0], &tmpbuf[0], 7);
+				return touchnum; 	//touchnum is 0
+			}
+#endif 
+			// access NO TOUCH event unless BUTTON NO TOUCH event
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+			{
+				return touchnum;	//touchnum is 0
+			}
+		}
+
+		//skip parsing data when two devices are registered at the same slave address
+		//parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
+			return -1;		
+		}
+		
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	//start from 0
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
+		{
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_I2C;	//delete 2 byte crc
+			}
+			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_HIDI2C;
+			}
+			else	//should not be happen
+			{
+				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
+				return -1;
+			}
+
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_SCANTIME;
+			}
+		}
+		//else {}    						// For ALL_IN_ONE_PACKAGE
+		
+		if (read_first)
+		{
+			touchnum = tmpbuf[p_count]; 	
+		}
+		else
+		{
+			if (tmpbuf[p_count] != 0)
+			{
+				printk(KERN_ERR "sis_ReadPacket: get error package\n");
+				return -1;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		buf_crc = cal_crc(tmpbuf, 2, crc_end); //sub bytecount (2 byte)
+		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		package_crc = ((tmpbuf[l_package_crc] & 0xff) | ((tmpbuf[l_package_crc + 1] & 0xff) << 8));
+			
+		if (buf_crc != package_crc)
+		{
+			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
+			return -1;
+		}
+#endif	
+		memcpy(&buf[locate], &tmpbuf[0], 64);	//Buf_Data [0~63] [64~128]
+		locate += 64;
+		read_first = false;
+		
+	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
+
+	return touchnum;
+}	
+
+
+int check_gpio_interrupt(void)
+{
+    int ret = 0;
+    //TODO
+    //CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING.
+    ret = gpio_get_value(GPIO_IRQ);
+    return ret;
+}
+
+void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
+{
+	int i = 0;
+	uint8_t diff_keybit_state= 0x0; //check keybit_state is difference with pre_keybit_state
+	uint8_t key_value = 0x0; //button location for binary
+	uint8_t  key_pressed = 0x0; //button is up or down
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts)
+	{
+		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state)
+	{
+		for (i = 0; i < BUTTON_KEY_COUNT; i++)
+		{
+		    if ((diff_keybit_state >> i) & 0x01)
+			{
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value)
+				{
+					case MSK_COMP:
+						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
+						printk(KERN_ERR "%s : MSK_COMP %d \n", __func__ , key_pressed);
+						break;
+					case MSK_BACK:
+						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
+						printk(KERN_ERR "%s : MSK_BACK %d \n", __func__ , key_pressed);
+						break;
+					case MSK_MENU:
+						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
+						printk(KERN_ERR "%s : MSK_MENU %d \n", __func__ , key_pressed);
+						break;
+					case MSK_HOME:
+						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
+						printk(KERN_ERR "%s : MSK_HOME %d \n", __func__ , key_pressed);
+						break;
+					case MSK_NOBTN:
+						//Release the button if it touched.
+					default:
+						break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+
+
+static void sis_ts_work_func(struct work_struct *work)
+{
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+    int ret = -1;
+    int point_unit;  
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+    uint8_t p_preasure = 0;
+#ifdef _SUPPORT_BUTTON_TOUCH	
+	int button_key;
+	uint8_t button_buf[10] = {0};
+#endif
+
+#ifdef _ANDROID_4
+	bool all_touch_up = true;
+#endif
+	
+	mutex_lock(&ts->mutex_wq); 
+
+    /* I2C or SMBUS block data read */
+    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+#ifdef _DEBUG_PACKAGE_WORKFUNC
+	printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+	PrintBuffer(0, 64, buf);			
+	if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (ret > 5))
+	{
+		printk(KERN_INFO "chaoban test: Buf_Data [64~125] \n");
+		PrintBuffer(64, 128, buf);	
+	}
+#endif
+
+// add 
+#ifdef _SUPPORT_BUTTON_TOUCH
+	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
+#endif
+
+	if (ret < 0) // Error Number
+	{
+	    printk(KERN_INFO "chaoban test: ret = -1\n");
+		goto err_free_allocate;
+	}
+#ifdef _SUPPORT_BUTTON_TOUCH
+	// access BUTTON TOUCH event and BUTTON NO TOUCH even
+	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
+	{
+		//fingers = 0; //modify
+		button_key = ((button_buf[BUTTON_STATE] & 0xff) | ((button_buf[BUTTON_STATE + 1] & 0xff)<< 8));		
+		ts_report_key(ts->client, button_key);
+		//goto err_free_allocate; //modify
+	}
+#endif
+	// access NO TOUCH event unless BUTTON NO TOUCH event
+	else if (ret == 0)
+	{
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;  //need to report input_mt_sync()
+	}
+	
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+	
+	/* Parser and Get the sis9200 data */
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+	
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+	
+	for (i = 0; i < fingers; i++) // fingers 10 =  0 ~ 9
+	{
+        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
+        {
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	// Calc point status
+			pstatus += 64;
+		}
+		else 
+		{
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	// Calc point status
+		}
+
+	    px = pstatus + 2;                   			// Calc point x_coord
+	    py = px + 2;                        			// Calc point y_coord
+
+		if ((buf[pstatus]) == TOUCHUP)
+		{
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		}
+		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
+		{
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;			
+		}
+		else if ((buf[pstatus]) == TOUCHDOWN)
+		{	
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+
+			//area		
+			if (IS_AREA(buf[P_REPORT_ID]))
+			{
+				TPInfo->pt[i].Width = buf[p_area] & 0xff;
+				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
+			}
+			else 
+			{
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			//preasure
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else 
+				TPInfo->pt[i].Pressure = 1;				
+		}
+		else
+		{
+			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
+        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
+	}
+		
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+	{
+		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
+	}
+#endif
+
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+#ifdef _ANDROID_4	
+	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
+	{
+		if(TPInfo->pt[i].Pressure)
+		{
+			TPInfo->pt[i].Width *= AREA_UNIT;	
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);     //Android 2.3
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		
+		if (i == (TPInfo->fingers -1) && all_touch_up == true)
+		{
+			input_mt_sync(ts->input_dev);
+		}
+	}
+
+	if(TPInfo->fingers == 0)
+	{
+		input_mt_sync(ts->input_dev);
+	}
+#else
+	i = 0;
+	do
+	{
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);		//Android 2.3
+		input_mt_sync(ts->input_dev);
+		i++;
+	}
+	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
+#endif
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+    if (ts->use_irq)
+    {
+#ifdef _INT_MODE_1 //case 1 mode
+	    //TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high
+	    ret = check_gpio_interrupt();	//interrupt pin is still LOW, read data until interrupt pin is released.
+	    if (!ret)
+	    {
+	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	    }
+	    else
+	    {
+			if (TPInfo->pre_keybit_state)
+			{
+				ts_report_key(ts->client, 0x0);	//clear for interrupt
+			}
+			
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+        	{
+				enable_irq(ts->client->irq);
+			}
+	    }
+#else // case 2 mode
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(ts->client->irq);
+		}
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+    return;
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
+{
+	int i = 0;
+	for(i = 0; i < max; i++)
+	{
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
+{
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)
+	{	// For Polling mode
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	}
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+	struct sis_ts_data *ts = dev_id;
+	
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+	{
+		disable_irq_nosync(ts->client->irq);
+	}
+	queue_work(sis_wq, &ts->work);
+		
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	/* TODO */
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");	// ex. GPIO_133 for interrupt mode
+	if (ret < 0)
+	{
+		// Set Active Low. Please reference the file include/linux/interrupt.h
+		printk(KERN_ERR "sis_ts_probe: Failed to gpio_request\n");
+		printk(KERN_ERR "sis_ts_probe: Fail : gpio_request was called before this driver call\n");
+	}	
+	/* setting gpio direction here OR boardinfo file*/
+	/* TODO */
+#else
+	ret = -1;
+#endif
+	return ret;
+}
+
+uint16_t cal_crc (char* cmd, int start, int end)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
+	}
+	return crc;
+}
+
+uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
+	}
+	return crc;
+}
+
+void write_crc (unsigned char *buf, int start, int end)
+{
+	uint16_t crc = 0;
+	crc = cal_crc (buf, start , end);
+	buf[end+1] = (crc >> 8)& 0xff;
+	buf[end+2] = crc & 0xff;
+}
+
+/*
+ * When you will send commad to chip, you should use this function on 
+ * the first time.
+ * 
+ * Return:If switch success return ture, else return false.
+ */
+bool sis_switch_to_cmd_mode(struct i2c_client *client)
+{
+	int ret = -1;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
+		0x00, 0x85, 0x0d, 0x51, 0x09};
+	uint8_t sis817_cmd_enable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
+		0x00, 0x09, 0x00, 0x85, 0x5c, 0x21, 0x01};
+	
+	
+	
+	//Send 85 CMD - PWR_CMD_ACTIVE
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_ACTIVE)\n");
+		return false;
+	}
+	
+	msleep(100);
+	memset(tmpbuf, 0, sizeof(tmpbuf));
+	
+	//Send 85 CMD - ENABLE_DIAGNOSIS_MODE
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_enable_diagnosis), sis817_cmd_enable_diagnosis);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(ENABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	msleep(50);
+	return true;	
+}
+
+/*
+ * When chip in the command mode will switch to work, you should use 
+ * this function.
+ * 
+ * Return:If switch success return ture, else return false.
+ */
+bool sis_switch_to_work_mode(struct i2c_client *client)
+{
+	int ret = -1;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
+		0x00, 0x85, 0x3c, 0x50, 0x09};
+	uint8_t sis817_cmd_disable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
+		0x00, 0x09, 0x00, 0x85, 0x6d, 0x20, 0x01};
+	
+	
+	//Send 85 CMD - PWR_CMD_FW_CTRL
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_FW_CTRL)\n");
+		return false;
+	}
+
+	memset(tmpbuf, 0, sizeof(tmpbuf));
+	
+	//Send 85 CMD - DISABLE_DIAGNOSIS_MODE
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_disable_diagnosis), sis817_cmd_disable_diagnosis);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
+		return false;
+	}
+	
+	msleep(50);
+	return true;
+}
+
+/*
+ * Use this function get FW ID.
+ */
+bool sis_get_fw_id(struct i2c_client *client)
+{
+  	int ret = 0;
+  	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_get_FW_ID[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
+		0x00, 0x86, 0x00, 0x0c, 0xc0, 0x00, 0xa0, 0x04, 0x00};
+	
+	sis817_cmd_get_FW_ID[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_get_FW_ID, 8, 13, 0x86));
+
+	if(!sis_switch_to_cmd_mode(client)){
+		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
+		return false;
+	}
+	
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_get_FW_ID), sis817_cmd_get_FW_ID);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
+	}
+
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	printk(KERN_INFO "SiS FW ID : ");
+	PrintBuffer(8, 12, tmpbuf);	
+
+	if(!sis_switch_to_work_mode(client)){
+		printk(KERN_ERR "SiS Switch to Work mode error.\n");
+		return false;
+	}
+	
+	if(ret < 0) return false;
+	return true;
+		
+}
+
+/*
+ * Use this function check chip status.
+ * 
+ * Return:Ture is chip on the work function, else is chip not ready.
+ */
+bool sis_check_fw_ready(struct i2c_client *client)
+{
+  	int ret = 0;
+  	int check_num = 10;
+  	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_check_ready[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
+		0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
+	
+	
+	sis817_cmd_check_ready[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_ready, 8, 13, 0x86));
+	
+
+	if(!sis_switch_to_cmd_mode(client)){
+		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
+		return false;
+	}
+	
+	while(check_num--){
+		printk(KERN_ERR "SiS Check FW Ready.\n");
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_check_ready), sis817_cmd_check_ready);
+		if(ret < 0){
+			printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
+		}
+		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+		if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return NACK\n");
+		}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return Unknow\n");
+		}else{
+			if(tmpbuf[9] == 1){
+				printk(KERN_ERR "SiS FW READY.\n");
+				break;
+			}
+		}
+		printk(KERN_ERR "SiS CHECK FW READY - Retry:%d.\n", (10-check_num));	
+		msleep(50);
+	}
+	
+	if(!sis_switch_to_work_mode(client)){
+		printk(KERN_ERR "SiS Switch to Work mode error.\n");
+		return false;
+	}
+	
+	if(check_num == 0) return false;
+	return true;
+		
+}
+
+/*
+ * Use this function to change chip power mode. 
+ * 
+ * mode:POWER_MODE_FWCTRL, power control by FW.
+ * 		POWER_MODE_ACTIVE, chip always work on time.
+ * 		POWER_MODE_SLEEP,  chip on the sleep mode.
+ * 
+ * Return:Ture is change power mode success.
+ */
+bool sis_change_fw_mode(struct i2c_client *client, enum SIS_817_POWER_MODE mode)
+{
+	int ret = -1;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x3c, 0x50, 0x09};
+	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x0d, 0x51, 0x09};
+	uint8_t sis817_cmd_sleep[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x5e, 0x52, 0x09};
+	
+	
+	switch(mode)
+	{
+	case POWER_MODE_FWCTRL:
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
+		break;
+	case POWER_MODE_ACTIVE:
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
+		break;
+	case POWER_MODE_SLEEP:
+		ret = sis_command_for_write(client, sizeof(sis817_cmd_sleep), sis817_cmd_sleep);
+		break;
+	default:
+		return false;
+		break;
+	}
+
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Power CMD Faile - 85\n");
+		return false;
+	}
+	
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if(ret < 0){
+		printk(KERN_ERR "SiS READ Power CMD Faile - 85\n");
+		return false;
+	}
+	
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Power CMD Return NACK - 85\n");
+		return false;
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Power CMD Return Unknow- 85\n");
+		return false;
+	}
+	
+	msleep(100);
+	
+	return true;
+}
+
+/*
+ * Use this function to get chip work status. 
+ * 
+ * Return:-1 is get firmware work status error.
+ * 		  POWER_MODE_FWCTRL, power control by FW.
+ * 		  POWER_MODE_ACTIVE, chip always work on time.
+ * 		  POWER_MODE_SLEEP,  chip on the sleep mode.
+ */
+enum SIS_817_POWER_MODE sis_get_fw_mode(struct i2c_client *client)
+{
+	int ret;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_check_power_mode[14] = {0x04, 0x00, 0x0c, 0x00, 
+		0x09, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
+
+	printk(KERN_INFO "SiS Get FW Mode.\n");	
+	sis817_cmd_check_power_mode[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_power_mode, 8, 13, 0x86));
+	
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_check_power_mode), sis817_cmd_check_power_mode);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Get FW Mode CMD Faile - 86\n");
+	}else{
+		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+		if(ret < 0){
+			printk(KERN_ERR "SiS READ Get FW Mode CMD Faile - 86\n");
+		}else{
+			if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return NACK\n");
+			}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return Unknow\n");
+				PrintBuffer(0, sizeof(tmpbuf), tmpbuf);
+			}
+		}
+	}
+	
+	switch(tmpbuf[10])
+	{
+	case POWER_MODE_FWCTRL:
+		return POWER_MODE_FWCTRL;
+	case POWER_MODE_ACTIVE:
+		return POWER_MODE_ACTIVE;
+	case POWER_MODE_SLEEP:
+		return POWER_MODE_SLEEP;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+/*
+ * Use this function to reset chip. 
+ */
+void sis_fw_softreset(struct i2c_client *client)
+{
+
+	int ret = 0;
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+	uint8_t sis817_cmd_reset[8] = {0x04, 0x00, 0x06, 0x00, 0x09, 0x00, 0x82, 0x00};
+	
+
+	sis817_cmd_reset[BUF_CRC_PLACE] = (0xFF & cal_crc(sis817_cmd_reset, 6, 6));
+
+	printk(KERN_ERR "SiS Software Reset.\n");
+	if(!sis_switch_to_cmd_mode(client)){
+		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
+		return;
+	}
+	
+	ret = sis_command_for_write(client, sizeof(sis817_cmd_reset), sis817_cmd_reset);
+	if(ret < 0){
+		printk(KERN_ERR "SiS SEND Reset CMD Faile - 82\n");
+	}
+	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
+	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
+		printk(KERN_ERR "SiS SEND Reset CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
+	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
+		printk(KERN_ERR "SiS SEND Reset CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
+	}	
+	msleep(2000);
+}
+
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 
+	 printk(KERN_INFO "sis_cdev_write.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     } 
+#if 0
+	PrintBuffer(0, count, kdata);
+#endif
+		
+	cmd = kdata[6];
+
+    printk(KERN_INFO "io cmd=%02x\n", cmd);
+
+//Write & Read
+    ret = sis_command_for_write(ts_bak->client, count, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+//for get system time
+static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 int i;
+	 printk(KERN_INFO "sis_cdev_read.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }    
+#if 0
+    PrintBuffer(0, count, kdata);
+#endif
+	 cmd = kdata[6];
+	 //for making sure AP communicates with SiS driver
+    if(cmd == 0xa2)
+    {
+		kdata[0] = 5;
+		kdata[1] = 0;
+		kdata[3] = 'S';
+		kdata[4] = 'i';
+		kdata[5] = 'S';
+		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+		{
+			printk(KERN_ERR "copy_to_user fail\n" );
+			kfree( kdata );
+			return -19;
+		}
+
+		kfree( kdata );
+		return 3;	
+	}
+//Write & Read
+    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+	ret = kdata[0] | (kdata[1] << 8);
+
+/*
+    for ( i = 0; i < BUFFER_SIZE - 1; i++ ) {
+	    kdata[i] = kdata[i+1];
+    }
+*/
+
+    printk(KERN_INFO "%d\n", ret);
+
+    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
+    {
+        printk("%02x ", kdata[i]);
+    }
+
+    printk( "\n" );
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_open.\n");
+	if ( ts_bak == 0 )
+    	return -13;
+
+	msleep(200);
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif	
+		{
+			disable_irq(ts_bak->client->irq);
+		}
+		else
+		{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
+#else
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
+#endif	
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+
+	flush_workqueue(sis_wq); 	   // only flush sis_wq
+    
+    msleep(200);
+
+	return 0; /* success */
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_release.\n");
+	 msleep(200);
+    if (ts_bak == 0)
+    	return -13;
+
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif	
+		{
+			enable_irq(ts_bak->client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+    return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts)
+{
+	
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int alloc_ret = 0;
+	int cdev_err = 0;
+	int input_err = 0;
+	struct device *class_dev = NULL;
+	void *ptr_err;
+	
+	printk("sis_setup_chardev.\n");
+	
+	if (ts == NULL) 
+	{
+	  input_err = -ENOMEM;
+	  goto error;
+	} 
+	 // dynamic allocate driver handle
+	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
+	if (alloc_ret)
+		goto error;
+		
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
+	
+	if (cdev_err) 
+		goto error;
+	
+	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
+	
+	// register class
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+	
+	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
+	
+	if(IS_ERR(ptr_err = class_dev)) 
+	{
+		goto err;
+	}
+	
+	return 0;
+error:
+	if (cdev_err == 0)
+		cdev_del(&sis_char_cdev);
+	if (alloc_ret == 0)
+		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
+	if(input_err != 0)
+	{
+		printk("sis_ts_bak error!\n");
+	}
+err:
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+err2:
+	class_destroy(sis_char_class);
+	return -1;
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+    printk(KERN_INFO "sis_ts_probe\n");
+
+    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+    if (TPInfo == NULL) 
+    {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) 
+	{
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts_bak = ts;
+
+	mutex_init(&ts->mutex_wq);
+	
+	//1. Init Work queue and necessary buffers
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+    pdata = client->dev.platform_data;
+
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) 
+	{
+		ret = ts->power(1);
+		if (ret < 0) 
+		{
+			printk(KERN_ERR "sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+
+	//2. Allocate input device
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) 
+	{
+		ret = -ENOMEM;
+		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+
+	//This input device name should be the same to IDC file name.
+	ts->input_dev->name = "sis_touch";//"SiS9200-i2c-touchscreen";
+
+	sis_get_fw_id(client);
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+		//sis_check_fw_ready(client);
+#endif
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+
+#ifdef _ANDROID_4
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
+#else
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
+#endif
+
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
+	
+    /* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+
+	//3. Register input device to core
+	ret = input_register_device(ts->input_dev);
+
+	if (ret) 
+	{
+		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	
+	//4. irq or timer setup
+	ret = initial_irq();
+	if (ret < 0) 
+	{
+
+	}
+	else
+	{
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0) 
+		{
+		   ts->use_irq = 1;
+		}
+		else 
+		{
+			dev_err(&client->dev, "request_irq failed\n");
+		}
+	}
+
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+
+	if (!ts->use_irq) 
+	{
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+	
+	if (ts->use_irq)
+	{
+#ifdef _INT_MODE_1
+		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
+#else
+		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
+#endif
+	}
+	
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if(ret)
+	{
+		printk( KERN_INFO"sis_setup_chardev fail\n");
+	}
+#endif
+
+	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+
+	return 0;
+
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client)
+{
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+	int retry = 5;
+#endif
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+		{
+			disable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_cancel(&ts->timer);
+	flush_workqueue(sis_wq); 	   		// only flush sis_wq
+//	flush_scheduled_work(); 		   	// flush all of workqueue in kernel
+//	ret = cancel_work_sync(&ts->work); 	// only cancel one work(sis_ts_work_func), 
+										// but there maybe are others in workqueue.
+/*
+	// For cancel_work_sync()
+	if (ret && ts->use_irq) //if work was pending disable-count is now 2
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+*/
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+		while ((sis_get_fw_mode(client) != POWER_MODE_SLEEP))
+		{
+			
+			if(sis_change_fw_mode(client, POWER_MODE_SLEEP)){
+				printk(KERN_ERR "sis_ts_suspend: change mode retry - %d\n", 5-retry);
+			}
+
+			if (retry == 0){
+				printk(KERN_ERR "sis_ts_suspend: change mode failed\n");
+				break;
+			}
+
+			retry--;
+			msleep(50);
+		}
+#endif
+
+
+#if 0
+	/* Turn off SiS Chip*/
+	/* TODO */
+	gpio_direction_output(TOUCH_RESET_PIN, 0);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
+//	msleep(5);
+	gpio_direction_output(TOUCH_POWER_PIN, 0);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power off\n");
+#endif
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_suspend power off failed\n");
+	}
+	
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+	int retry = 5;
+#endif
+
+	if (ts->power)
+	{
+		ret = ts->power(1);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_resume power on failed\n");
+	}
+
+#if 0
+	/* Turn on SiS Chip*/
+	/* TODO */
+	gpio_direction_output(TOUCH_POWER_PIN, 1);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power on\n");
+	msleep(5);
+	gpio_direction_output(TOUCH_RESET_PIN, 1);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
+	msleep(5);
+	gpio_direction_output(TOUCH_RESET_PIN, 0);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
+	msleep(5);
+	gpio_direction_output(TOUCH_RESET_PIN, 1);
+	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
+#endif
+
+#ifdef CONFIG_FW_SUPPORT_POWERMODE
+		while ((sis_get_fw_mode(client) != POWER_MODE_FWCTRL))
+		{
+			
+			if(sis_change_fw_mode(client, POWER_MODE_FWCTRL)){
+				printk(KERN_ERR "sis_ts_resume: change mode retry - %d\n", 5-retry);
+			}
+
+			if (retry == 0){
+				printk(KERN_ERR "sis_ts_resume: change mode failed\n");
+				break;
+			}
+				
+			retry--;
+			msleep(50);
+		}
+#endif
+		//sis_fw_softreset(client);
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void sis_ts_late_resume(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+    .class      = I2C_CLASS_HWMON,
+    .detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __devinit sis_ts_init(void)
+{
+	printk( KERN_INFO "sis_ts_init\n" );
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+	return i2c_add_driver(&sis_ts_driver);
+}
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+    printk(KERN_INFO "sis_ts_detect\n");
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	return 0;
+}
+#endif
+
+static void __exit sis_ts_exit(void)
+{
+#ifdef _STD_RW_IO
+	dev_t dev;
+#endif
+
+	printk(KERN_INFO "sis_ts_exit\n");
+	i2c_del_driver(&sis_ts_driver);
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+
+#ifdef _STD_RW_IO
+	dev = MKDEV(sis_char_major, 0);
+	cdev_del(&sis_char_cdev);
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+	class_destroy(sis_char_class);
+#endif
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..1ace42a
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,229 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2012/11/13
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+#define TIMER_NS    					10000000 //10ms
+#define MAX_FINGERS						10
+
+
+/* For Android 4.0 							*/
+/* Only for Linux kernel 2.6.34 and later 	*/
+#define _ANDROID_4					//  ON/OFF
+
+/* For standard R/W IO*/
+#define _STD_RW_IO						//  ON/OFF
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					//  ON/OFF
+#define GPIO_IRQ 						133
+
+/*  Enable if use interrupt case 1 mode.  */
+/* 	Disable if use interrupt case 2 mode. */
+//#define _INT_MODE_1					//	ON/OFF
+
+/* IRQ STATUS */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+#define IRQ_STATUS_DISABLED				0x200  
+#else
+#define IRQ_STATUS_DISABLED				(1<<16)
+#endif
+#define IRQ_STATUS_ENABLED				0x0
+
+/* Resolution mode */
+// Constant value 
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE  					8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE       		0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID	                		0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+#ifdef _ANDROID_4
+#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
+#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
+#define AREA_UNIT						(5792/32)
+#else
+#define AREA_LENGTH_LONGER				31
+#define AREA_LENGTH_SHORT				31
+#endif
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0 
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					(x & 0x6)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+//#define _DEBUG_PACKAGE				//  ON/OFF
+//#define _DEBUG_PACKAGE_WORKFUNC		//  ON/OFF
+//#define _DEBUG_REPORT					//  ON/OFF
+
+#ifdef OLD_FORMAT_AEGIS
+#define TOUCH_NUM						1
+#define BUTTON_KEY_COUNT				8
+#define BUTTON_TOUCH					0x05
+#define BUTTON_TOUCH_ONE_POINT			0x0A
+#define BUTTON_TOUCH_MULTI_TOUCH		0x0F
+#define MSK_BUTTON_POINT				0xf0
+#define BUTTON_TOUCH_SERIAL				0x70
+#define BUTTON_STATE					(CMD_BASE + 1)
+
+#else
+//#define _CHECK_CRC					//  ON/OFF
+//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+#endif
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+#endif /* _LINUX_SIS_I2C_H */
+
+enum SIS_817_POWER_MODE{
+	POWER_MODE_FWCTRL = 0x50,
+	POWER_MODE_ACTIVE = 0x51,
+	POWER_MODE_SLEEP  = 0x52
+};
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+static const unsigned short crc16tab[256]= {
+		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;   	// uint16_t ?
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;	
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
+static int sis_ts_resume(struct i2c_client *client);

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
  2015-01-12 10:53 ` 曾婷葳 (tammy_tseng)
  (?)
@ 2015-01-12 11:50 ` Oliver Neukum
       [not found]   ` <CAKR5kVFXy4GdZdHFnW2AAjqkcHfgfM5b0NhkOa079bftOoKqUQ@mail.gmail.com>
  -1 siblings, 1 reply; 21+ messages in thread
From: Oliver Neukum @ 2015-01-12 11:50 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: linux-kernel, linux-input, tammy0524

On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> Hi,
> This package of patch is to add support for multitouch behavior for SiS touch products.
> The patch of SiS i2c multitouch driver is in input/touchscreen.
> 
> Signed-off-by: Tammy Tseng <tammy_tseng@sis.com>
> 
> ---
> diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
> index e1d8003..edc8e27 100644
> --- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
> +++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
> @@ -962,4 +962,18 @@ config TOUCHSCREEN_ZFORCE
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called zforce_ts.
>  
> +config TOUCHSCREEN_SIS_I2C
> +	tristate "SiS 9200 family I2C touchscreen driver"
> +	depends on I2C
> +	default y

Why that default? The majority of systems will not feature this
touchscreens.

> +	help
> +	  This enables support for SiS 9200 family over I2C based touchscreens.
> +
> +config FW_SUPPORT_POWERMODE
> +		default n
> +        bool "SiS FW support power mode"
> +        depends on TOUCHSCREEN_SIS_I2C
> +        help
> +          This enables support power mode provided by SiS firmwave

What does this mode do? The help should be more extensive to be
helpful.

> +
>  endif
> diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
> index 090e61c..e316477 100644
> --- a/linux-3.18.1/drivers/input/touchscreen/Makefile
> +++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
> @@ -6,6 +6,10 @@
>  
>  wm97xx-ts-y := wm97xx-core.o
>  
> +ifdef CONFIG_TOUCHSCREEN_SIS_I2C
> +obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
> +endif
> +
>  obj-$(CONFIG_OF_TOUCHSCREEN)		+= of_touchscreen.o
>  obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
> diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
> new file mode 100644
> index 0000000..2e6fc1a
> --- /dev/null
> +++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
> @@ -0,0 +1,1725 @@
> +/* drivers/input/touchscreen/sis_i2c.c - I2C Touch panel driver for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * Date: 2012/11/13
> + * Version:	Android_v2.05.00-A639-1113
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif

Conditional includes should be avoided if possible.

> +#include <linux/hrtimer.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include "sis_i2c.h"
> +#include <linux/linkage.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <asm/uaccess.h>
> +#include <linux/irq.h>
> +
> +#ifdef _STD_RW_IO

???

> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#define DEVICE_NAME "sis_aegis_touch_device"
> +static int sis_char_devs_count = 1;        /* device count */

Why start with 1 ?
> +static int sis_char_major = 0;
> +static struct cdev sis_char_cdev;
> +static struct class *sis_char_class = NULL;
> +#endif
> +
> +/* Addresses to scan */
> +static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
> +static struct workqueue_struct *sis_wq;
> +struct sis_ts_data *ts_bak = 0;
> +struct sisTP_driver_data *TPInfo = NULL;

Are you really sure you are limited to a single device?
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h);
> +static void sis_ts_late_resume(struct early_suspend *h);
> +#endif
> +
> +#ifdef CONFIG_X86
> +//static const struct i2c_client_address_data addr_data;
> +/* Insmod parameters */
> +static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
> +#endif
> +
> +#ifdef _CHECK_CRC
> +uint16_t cal_crc (char* cmd, int start, int end);
> +#endif
> +
> +void PrintBuffer(int start, int length, char* buf)

Polluting the name space like this is really nasty.
Could you check which of your declarations can be
declared "static"?

> +{
> +	int i;
> +	for ( i = start; i < length; i++ )
> +	{
> +		printk("%02x ", buf[i]);
> +		if (i != 0 && i % 30 == 0)
> +			printk("\n");
> +	}
> +	printk("\n");	
> +}
> +
> +int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
> +{
> +    int ret = -1;
> +    struct i2c_msg msg[1];

Why on earth an array of a single element?

> +
> +    msg[0].addr = client->addr;
> +    msg[0].flags = 0; //Write
> +    msg[0].len = wlength;
> +    msg[0].buf = (unsigned char *)wdata;
> +
> +    ret = i2c_transfer(client->adapter, msg, 1);
> +
> +    return ret;
> +}
> +
> +int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
> +{
> +    int ret = -1;
> +    struct i2c_msg msg[1];

Likewise

> +
> +    msg[0].addr = client->addr;
> +    msg[0].flags = I2C_M_RD; //Read
> +    msg[0].len = rlength;
> +    msg[0].buf = rdata;
> +
> +    ret = i2c_transfer(client->adapter, msg, 1);
> +
> +    return ret;
> +}
> +
> +int sis_cul_unit(uint8_t report_id)
> +{
> +	int basic = 6;
> +	int area = 2;
> +	int pressure = 1;
> +	int ret = basic;

Why ???
> +	
> +	if (report_id != ALL_IN_ONE_PACKAGE)
> +	{
> +		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
> +		{
> +			ret += area;
> +		}
> +		if (IS_PRESSURE(report_id))
> +		{
> +			ret += pressure;
> +		}
> +	}
> +	
> +	return ret;	
> +}
> +
> +int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
> +{
> +	uint8_t tmpbuf[MAX_BYTE] = {0};	//MAX_BYTE = 64;
> +#ifdef _CHECK_CRC
> +	uint16_t buf_crc = 0;
> +	uint16_t package_crc = 0;
> +	int l_package_crc = 0;
> +	int crc_end = 0;
> +#endif
> +    int ret = -1;
> +    int touchnum = 0;
> +    int p_count = 0;
> +    int touc_formate_id = 0;
> +    int locate = 0;
> +    bool read_first = true;
> +    
> +/*
> +		New i2c format 
> +	* buf[0] = Low 8 bits of byte count value
> +	* buf[1] = High 8 bits of byte counte value
> +	* buf[2] = Report ID
> +	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
> +	* buf[touch num * 6 + 3] = Touch numbers
> +	* 
> +	* One touch point information include 6 bytes, the order is 
> +	* 
> +	* 1. status = touch down or touch up
> +	* 2. id = finger id 
> +	* 3. x axis low 8 bits
> +	* 4. x axis high 8 bits
> +	* 5. y axis low 8 bits
> +	* 6. y axis high 8 bits
> +	* 
> +*/
> +	do
> +	{
> +		if (locate >= PACKET_BUFFER_SIZE)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
> +			return -1;
> +		}
> +		
> +		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
> +
> +#ifdef _DEBUG_PACKAGE
> +		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
> +		PrintBuffer(0, 64, tmpbuf);	
> +#endif			
> +
> +		if(ret < 0 )
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");

It would be nicer to use the debug methods defined for devices, so that
you get device identification in the log for free.

> +			return ret;
> +		}
> +		// error package length of receiving data
> +		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)

This looks like a bug. You are checking only the lower byte.

> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
> +			return -1;	
> +		}
> +		
> +		if (read_first)
> +		{
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +			// access BUTTON TOUCH event and BUTTON NO TOUCH event
> +			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
> +			{
> +				memcpy(&buf[0], &tmpbuf[0], 7);
> +				return touchnum; 	//touchnum is 0

So why not return 0 ?

> +			}
> +#endif 
> +			// access NO TOUCH event unless BUTTON NO TOUCH event
> +			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
> +			{
> +				return touchnum;	//touchnum is 0
> +			}
> +		}
> +
> +		//skip parsing data when two devices are registered at the same slave address
> +		//parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
> +		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
> +		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
> +			return -1;		
> +		}
> +		
> +		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	//start from 0
> +		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
> +		{
> +			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_CRC_I2C;	//delete 2 byte crc
> +			}
> +			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_CRC_HIDI2C;
> +			}
> +			else	//should not be happen
> +			{
> +				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
> +				return -1;
> +			}
> +
> +			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_SCANTIME;
> +			}
> +		}
> +		//else {}    						// For ALL_IN_ONE_PACKAGE
> +		
> +		if (read_first)
> +		{
> +			touchnum = tmpbuf[p_count]; 	
> +		}
> +		else
> +		{
> +			if (tmpbuf[p_count] != 0)
> +			{
> +				printk(KERN_ERR "sis_ReadPacket: get error package\n");
> +				return -1;
> +			}
> +		}
> +
> +#ifdef _CHECK_CRC
> +		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
> +		buf_crc = cal_crc(tmpbuf, 2, crc_end); //sub bytecount (2 byte)
> +		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
> +		package_crc = ((tmpbuf[l_package_crc] & 0xff) | ((tmpbuf[l_package_crc + 1] & 0xff) << 8));

We have macros to read data in a defined endianness

> +			
> +		if (buf_crc != package_crc)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
> +			return -1;
> +		}
> +#endif	
> +		memcpy(&buf[locate], &tmpbuf[0], 64);	//Buf_Data [0~63] [64~128]
> +		locate += 64;
> +		read_first = false;
> +		
> +	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
> +
> +	return touchnum;
> +}	
> +
> +
> +int check_gpio_interrupt(void)
> +{
> +    int ret = 0;
> +    //TODO
> +    //CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING.
> +    ret = gpio_get_value(GPIO_IRQ);
> +    return ret;
> +}
> +
> +void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
> +{
> +	int i = 0;
> +	uint8_t diff_keybit_state= 0x0; //check keybit_state is difference with pre_keybit_state
> +	uint8_t key_value = 0x0; //button location for binary
> +	uint8_t  key_pressed = 0x0; //button is up or down
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (!ts)
> +	{
> +		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
> +		return;
> +	}
> +
> +	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
> +
> +	if (diff_keybit_state)
> +	{
> +		for (i = 0; i < BUTTON_KEY_COUNT; i++)
> +		{
> +		    if ((diff_keybit_state >> i) & 0x01)
> +			{
> +				key_value = diff_keybit_state & (0x01 << i);
> +				key_pressed = (keybit_state >> i) & 0x01;
> +				switch (key_value)
> +				{
> +					case MSK_COMP:
> +						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
> +						printk(KERN_ERR "%s : MSK_COMP %d \n", __func__ , key_pressed);
> +						break;
> +					case MSK_BACK:
> +						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
> +						printk(KERN_ERR "%s : MSK_BACK %d \n", __func__ , key_pressed);
> +						break;
> +					case MSK_MENU:
> +						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
> +						printk(KERN_ERR "%s : MSK_MENU %d \n", __func__ , key_pressed);
> +						break;
> +					case MSK_HOME:
> +						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
> +						printk(KERN_ERR "%s : MSK_HOME %d \n", __func__ , key_pressed);
> +						break;
> +					case MSK_NOBTN:
> +						//Release the button if it touched.
> +					default:
> +						break;
> +				}
> +			}
> +		}
> +		TPInfo->pre_keybit_state = keybit_state;
> +	}
> +}
> +
> +
> +static void sis_ts_work_func(struct work_struct *work)
> +{
> +	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
> +    int ret = -1;
> +    int point_unit;  
> +	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
> +	uint8_t i = 0, fingers = 0;
> +	uint8_t px = 0, py = 0, pstatus = 0;
> +	uint8_t p_area = 0;
> +    uint8_t p_preasure = 0;
> +#ifdef _SUPPORT_BUTTON_TOUCH	
> +	int button_key;
> +	uint8_t button_buf[10] = {0};
> +#endif
> +
> +#ifdef _ANDROID_4
> +	bool all_touch_up = true;
> +#endif
> +	
> +	mutex_lock(&ts->mutex_wq); 
> +
> +    /* I2C or SMBUS block data read */
> +    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
> +#ifdef _DEBUG_PACKAGE_WORKFUNC
> +	printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
> +	PrintBuffer(0, 64, buf);			
> +	if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (ret > 5))
> +	{
> +		printk(KERN_INFO "chaoban test: Buf_Data [64~125] \n");
> +		PrintBuffer(64, 128, buf);	
> +	}
> +#endif
> +
> +// add 
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
> +#endif
> +
> +	if (ret < 0) // Error Number
> +	{
> +	    printk(KERN_INFO "chaoban test: ret = -1\n");
> +		goto err_free_allocate;
> +	}
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +	// access BUTTON TOUCH event and BUTTON NO TOUCH even
> +	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
> +	{
> +		//fingers = 0; //modify
> +		button_key = ((button_buf[BUTTON_STATE] & 0xff) | ((button_buf[BUTTON_STATE + 1] & 0xff)<< 8));	

Again macros for endianness

And the driver has a great number of conditional compilations are they
really needed? The driver as is has a number of issues and is hard to
review due to the use of "//" for comments and a lot of conditional
compilation and unnecessary variables used for constants. Could you
fix this up and resubmit?

	Regards
		Oliver




^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
       [not found]     ` <8322374EB97AA24A95D0DDBFC8F1CA1DBF9DE5@SISMBEV01.sis.com.tw>
@ 2015-01-16 10:59         ` 曾婷葳 (tammy_tseng)
  2015-01-16 11:19         ` 曾婷葳 (tammy_tseng)
  1 sibling, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-16 10:59 UTC (permalink / raw)
  To: linux-kernel, linux-input, Oliver Neukum; +Cc: tammy0524

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 41312 bytes --]

Hey, Oliver

On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > (Skip the code diff...)
> 
> Again macros for endianness
> 
> And the driver has a great number of conditional compilations are they 
> really needed? The driver as is has a number of issues and is hard to 
> review due to the use of "//" for comments and a lot of conditional 
> compilation and unnecessary variables used for constants. Could you 
> fix this up and resubmit?

Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
Please help check them if anything needs to fix.
Thanks.

Tammy

---
diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index e1d8003..401cd8b 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,12 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default n
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
+
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index 090e61c..67137af 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   	+= sis_i2c.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..157f991
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1267 @@
+/*
+ * SiS 9200 family I2C Touch Screen Controller Driver
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major = 0;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class = NULL;
+#endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
+static struct workqueue_struct *sis_wq;
+struct sis_ts_data *ts_bak = 0;
+struct sisTP_driver_data *TPInfo = NULL;
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h);
+static void sis_ts_late_resume(struct early_suspend *h);
+#endif
+
+#ifdef CONFIG_X86
+/* static const struct i2c_client_address_data addr_data; */
+/* Insmod parameters */
+static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
+#endif
+
+#ifdef _CHECK_CRC
+uint16_t cal_crc (char* cmd, int start, int end);
+#endif
+
+static void PrintBuffer(int start, int length, char* buf)
+{
+	int i;
+	for ( i = start; i < length; i++ )
+	{
+		printk("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			printk("\n");
+	}
+	printk("\n");	
+}
+
+int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
+{
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Write */
+    msg.flags = 0;
+    msg.len = wlength;
+    msg.buf = (unsigned char *)wdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
+{
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Read */
+    msg.flags = I2C_M_RD;
+    msg.len = rlength;
+    msg.buf = rdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_cul_unit(uint8_t report_id)
+{
+	int ret = NORMAL_LEN_PER_POINT;
+	
+	if (report_id != ALL_IN_ONE_PACKAGE)
+	{
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+		{
+			ret += AREA_LEN_PER_POINT;
+		}
+		if (IS_PRESSURE(report_id))
+		{
+			ret += PRESSURE_LEN_PER_POINT;
+		}
+	}
+	
+	return ret;	
+}
+
+int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
+{
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+#ifdef _CHECK_CRC
+	uint16_t buf_crc = 0;
+	uint16_t package_crc = 0;
+	int l_package_crc = 0;
+	int crc_end = 0;
+#endif
+    int ret = -1;
+    int touchnum = 0;
+    int p_count = 0;
+    int touc_formate_id = 0;
+    int locate = 0;
+    bool read_first = true;
+    
+/*
+		New i2c format 
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
+	* buf[touch num * 6 + 3] = Touch numbers
+	* 
+	* One touch point information include 6 bytes, the order is 
+	* 
+	* 1. status = touch down or touch up
+	* 2. id = finger id 
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	* 
+*/
+	do
+	{
+		if (locate >= PACKET_BUFFER_SIZE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
+			return -1;
+		}
+		
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+
+#ifdef _DEBUG_PACKAGE
+		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+		PrintBuffer(0, 64, tmpbuf);	
+#endif			
+
+		if(ret < 0 )
+		{
+			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		/* error package length of receiving data */
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
+			return -1;	
+		}
+		
+		if (read_first)
+		{
+#ifdef _SUPPORT_BUTTON_TOUCH
+			/* access BUTTON TOUCH event and BUTTON NO TOUCH event */
+			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
+			{
+				memcpy(&buf[0], &tmpbuf[0], 7);
+				return 0; 	/* touchnum is 0 */
+			}
+#endif 
+			/* access NO TOUCH event unless BUTTON NO TOUCH event */
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+			{
+				return 0;	/* touchnum is 0 */
+			}
+		}
+
+		/* skip parsing data when two devices are registered at the same slave address
+		 * parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
+		 */  
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
+			return -1;		
+		}
+		
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/* start from 0 */
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
+		{
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_I2C;	/* delete 2 byte crc */
+			}
+			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_HIDI2C;
+			}
+			else	/* should not be happen */
+			{
+				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
+				return -1;
+			}
+
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_SCANTIME;
+			}
+		}
+		/* else {}    						 For ALL_IN_ONE_PACKAGE */
+		
+		if (read_first)
+		{
+			touchnum = tmpbuf[p_count]; 	
+		}
+		else
+		{
+			if (tmpbuf[p_count] != 0)
+			{
+				printk(KERN_ERR "sis_ReadPacket: get error package\n");
+				return -1;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		buf_crc = cal_crc(tmpbuf, 2, crc_end); /* sub bytecount (2 byte) */
+		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		package_crc = get_unaligned_le16(&tmpbuf[l_package_crc]);
+			
+		if (buf_crc != package_crc)
+		{
+			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
+			return -1;
+		}
+#endif	
+		memcpy(&buf[locate], &tmpbuf[0], 64);	/* Buf_Data [0~63] [64~128] */
+		locate += 64;
+		read_first = false;
+		
+	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
+
+	return touchnum;
+}	
+
+
+int check_gpio_interrupt(void)
+{
+    int ret = 0;
+
+    /* CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING. */
+    ret = gpio_get_value(GPIO_IRQ);
+	
+    return ret;
+}
+
+void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
+{
+	int i = 0;
+	uint8_t diff_keybit_state= 0x0; /* check keybit_state is difference with pre_keybit_state */
+	uint8_t key_value = 0x0; 		/* button location for binary */
+	uint8_t  key_pressed = 0x0; 	/* button is up or down */
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts)
+	{
+		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state)
+	{
+		for (i = 0; i < BUTTON_KEY_COUNT; i++)
+		{
+		    if ((diff_keybit_state >> i) & 0x01)
+			{
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value)
+				{
+					case MSK_COMP:
+						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
+						break;
+					case MSK_BACK:
+						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
+						break;
+					case MSK_MENU:
+						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
+						break;
+					case MSK_HOME:
+						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
+						break;
+					case MSK_NOBTN:
+						/* Release the button if it touched. */
+					default:
+						break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+
+
+static void sis_ts_work_func(struct work_struct *work)
+{
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+    int ret = -1;
+    int point_unit;  
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+    uint8_t p_preasure = 0;
+#ifdef _SUPPORT_BUTTON_TOUCH	
+	int button_key;
+	uint8_t button_buf[10] = {0};
+#endif
+
+#ifdef _ANDROID_4
+	bool all_touch_up = true;
+#endif
+	
+	mutex_lock(&ts->mutex_wq); 
+
+    /* I2C or SMBUS block data read */
+    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+ 
+#ifdef _SUPPORT_BUTTON_TOUCH
+	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
+#endif
+
+	/* Error Number */
+	if (ret < 0) 
+	{
+		goto err_free_allocate;
+	}
+#ifdef _SUPPORT_BUTTON_TOUCH
+	/* access BUTTON TOUCH event and BUTTON NO TOUCH even */
+	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
+	{
+		button_key = get_unaligned_le16(&button_buf[BUTTON_STATE]);		
+		ts_report_key(ts->client, button_key);
+	}
+#endif
+	/* access NO TOUCH event unless BUTTON NO TOUCH event */
+	else if (ret == 0)
+	{
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;  /* need to report input_mt_sync() */
+	}
+	
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+	
+	/* Parser and Get the sis9200 data */
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+	
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+	
+	/* fingers 10 =  0 ~ 9 */
+	for (i = 0; i < fingers; i++) 
+	{
+        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
+        { /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	
+			pstatus += 64;
+		}
+		else 
+		{ /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	
+		}
+
+	    px = pstatus + 2;	/* Calc point x_coord */
+	    py = px + 2;		/* Calc point y_coord */
+
+		if ((buf[pstatus]) == TOUCHUP)
+		{
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		}
+		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
+		{
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;			
+		}
+		else if ((buf[pstatus]) == TOUCHDOWN)
+		{	
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+
+			/* area */
+			if (IS_AREA(buf[P_REPORT_ID]))
+			{
+				TPInfo->pt[i].Width = buf[p_area] & 0xff;
+				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
+			}
+			else 
+			{
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			/* preasure */
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else 
+				TPInfo->pt[i].Pressure = 1;				
+		}
+		else
+		{
+			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
+        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
+	}
+		
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+	{
+		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
+	}
+#endif
+
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+#ifdef _ANDROID_4	
+	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
+	{
+		if(TPInfo->pt[i].Pressure)
+		{
+			TPInfo->pt[i].Width *= AREA_UNIT;	
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		
+		if (i == (TPInfo->fingers -1) && all_touch_up == true)
+		{
+			input_mt_sync(ts->input_dev);
+		}
+	}
+
+	if(TPInfo->fingers == 0)
+	{
+		input_mt_sync(ts->input_dev);
+	}
+#else
+	i = 0;
+	do
+	{
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id); /* Android 2.3 */
+		input_mt_sync(ts->input_dev);
+		i++;
+	}
+	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
+#endif
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+    if (ts->use_irq)
+    {
+/* case 1 mode */
+#ifdef _INT_MODE_1 
+	    /*TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high */
+	    ret = check_gpio_interrupt();	/* interrupt pin is still LOW, read data until interrupt pin is released. */
+	    if (!ret)
+	    {
+	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	    }
+	    else
+	    {
+			if (TPInfo->pre_keybit_state)
+			{
+				ts_report_key(ts->client, 0x0);	/* clear for interrupt */
+			}
+			
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+        	{
+				enable_irq(ts->client->irq);
+			}
+	    }
+/* case 2 mode */
+#else
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(ts->client->irq);
+		}
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+    return;
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
+{
+	int i = 0;
+	for(i = 0; i < max; i++)
+	{
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
+{
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)
+	{	/* For Polling mode */
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	}
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+	struct sis_ts_data *ts = dev_id;
+	
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+	{
+		disable_irq_nosync(ts->client->irq);
+	}
+	queue_work(sis_wq, &ts->work);
+		
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");	/* ex. GPIO_133 for interrupt mode */
+	if (ret < 0)
+	{
+		/* Set Active Low. Please reference the file include/linux/interrupt.h */
+	}
+	/* setting gpio direction here OR boardinfo file*/
+
+#else
+	ret = -1;
+#endif
+	return ret;
+}
+
+uint16_t cal_crc (char* cmd, int start, int end)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+void write_crc (unsigned char *buf, int start, int end)
+{
+	uint16_t crc = 0;
+	
+	crc = cal_crc (buf, start , end);
+	buf[end+1] = (crc >> 8)& 0xff;
+	buf[end+2] = crc & 0xff;
+}
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 
+	 printk(KERN_INFO "sis_cdev_write.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     } 
+#if 0
+	PrintBuffer(0, count, kdata);
+#endif
+		
+	cmd = kdata[6];
+
+/* Write & Read */
+    ret = sis_command_for_write(ts_bak->client, count, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+/* for get system time */
+static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 int i;
+	 
+	 printk(KERN_INFO "sis_cdev_read.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }    
+#if 0
+    PrintBuffer(0, count, kdata);
+#endif
+	 cmd = kdata[6];
+	 /* for making sure AP communicates with SiS driver */
+    if(cmd == 0xa2)
+    {
+		kdata[0] = 5;
+		kdata[1] = 0;
+		kdata[3] = 'S';
+		kdata[4] = 'i';
+		kdata[5] = 'S';
+		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+		{
+			printk(KERN_ERR "copy_to_user fail\n" );
+			kfree( kdata );
+			return -19;
+		}
+
+		kfree( kdata );
+		return 3;	
+	}
+/* Write & Read */
+    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+	ret = kdata[0] | (kdata[1] << 8);
+
+    printk(KERN_INFO "%d\n", ret);
+
+    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
+    {
+        printk("%02x ", kdata[i]);
+    }
+
+    printk( "\n" );
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_open.\n");
+	if ( ts_bak == 0 )
+    	return -13;
+
+	msleep(200);
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif	
+		{
+			disable_irq(ts_bak->client->irq);
+		}
+		else
+		{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
+#else
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
+#endif	
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   
+    
+    msleep(200);
+
+	return 0; /* success */
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_release.\n");
+	
+	msleep(200);
+	
+    if (ts_bak == 0)
+    	return -13;
+
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif	
+		{
+			enable_irq(ts_bak->client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+    return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts)
+{
+	
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int alloc_ret = 0;
+	int cdev_err = 0;
+	int input_err = 0;
+	struct device *class_dev = NULL;
+	void *ptr_err;
+	
+	printk("sis_setup_chardev.\n");
+	
+	if (ts == NULL) 
+	{
+	  input_err = -ENOMEM;
+	  goto error;
+	} 
+	/* dynamic allocate driver handle */
+	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
+	if (alloc_ret)
+		goto error;
+		
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
+	
+	if (cdev_err) 
+		goto error;
+	
+	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
+	
+	/* register class */
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+	
+	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
+	
+	if(IS_ERR(ptr_err = class_dev)) 
+	{
+		goto err;
+	}
+	
+	return 0;
+error:
+	if (cdev_err == 0)
+		cdev_del(&sis_char_cdev);
+	if (alloc_ret == 0)
+		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
+	if(input_err != 0)
+	{
+		printk("sis_ts_bak error!\n");
+	}
+err:
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+err2:
+	class_destroy(sis_char_class);
+	return -1;
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+    printk(KERN_INFO "sis_ts_probe\n");
+
+    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+    if (TPInfo == NULL) 
+    {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) 
+	{
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts_bak = ts;
+
+	mutex_init(&ts->mutex_wq);
+	
+	/* 1. Init Work queue and necessary buffers */
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+    pdata = client->dev.platform_data;
+
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) 
+	{
+		ret = ts->power(1);
+		if (ret < 0) 
+		{
+			printk(KERN_ERR "sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+
+	/* 2. Allocate input device */
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) 
+	{
+		ret = -ENOMEM;
+		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+
+	/* This input device name should be the same to IDC file name. */
+	ts->input_dev->name = "sis_touch";
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+
+#ifdef _ANDROID_4
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
+#else
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
+#endif
+
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
+	
+    /* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+
+	/* 3. Register input device to core */
+	ret = input_register_device(ts->input_dev);
+
+	if (ret) 
+	{
+		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	
+	/* 4. irq or timer setup */
+	ret = initial_irq();
+	if (ret < 0) 
+	{
+
+	}
+	else
+	{
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0) 
+		{
+		   ts->use_irq = 1;
+		}
+		else 
+		{
+			dev_err(&client->dev, "request_irq failed\n");
+		}
+	}
+
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+
+	if (!ts->use_irq) 
+	{
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+	
+	if (ts->use_irq)
+	{
+#ifdef _INT_MODE_1
+		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
+#else
+		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
+#endif
+	}
+	
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if(ret)
+	{
+		printk( KERN_INFO"sis_setup_chardev fail\n");
+	}
+#endif
+
+	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+
+	return 0;
+
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client)
+{
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+	
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+		{
+			disable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_cancel(&ts->timer);
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   		
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_suspend power off failed\n");
+	}
+	
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power)
+	{
+		ret = ts->power(1);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_resume power on failed\n");
+	}
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void sis_ts_late_resume(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+    .class      = I2C_CLASS_HWMON,
+    .detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __init sis_ts_init(void)
+{
+	printk( KERN_INFO "sis_ts_init\n" );
+	
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+		
+	return i2c_add_driver(&sis_ts_driver);
+}
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+	
+    printk(KERN_INFO "sis_ts_detect\n");
+	
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	
+	return 0;
+}
+#endif
+
+static void __exit sis_ts_exit(void)
+{
+#ifdef _STD_RW_IO
+	dev_t dev;
+#endif
+
+	printk(KERN_INFO "sis_ts_exit\n");
+	
+	i2c_del_driver(&sis_ts_driver);
+	
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+
+#ifdef _STD_RW_IO
+	dev = MKDEV(sis_char_major, 0);
+	cdev_del(&sis_char_cdev);
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+	class_destroy(sis_char_class);
+#endif
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..c1d65c4
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,215 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2015/01/15
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+#define TIMER_NS    					10000000 //10ms
+#define MAX_FINGERS						10
+
+
+/* For Android 4.0 							*/
+/* Only for Linux kernel 2.6.34 and later 	*/
+#define _ANDROID_4					//  ON/OFF
+
+/* For standard R/W IO*/
+#define _STD_RW_IO						//  ON/OFF
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					//  ON/OFF
+#define GPIO_IRQ 						133
+
+/*  Enable if use interrupt case 1 mode.  */
+/* 	Disable if use interrupt case 2 mode. */
+//#define _INT_MODE_1					//	ON/OFF
+
+/* IRQ STATUS */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+#define IRQ_STATUS_DISABLED				0x200  
+#else
+#define IRQ_STATUS_DISABLED				(1<<16)
+#endif
+#define IRQ_STATUS_ENABLED				0x0
+
+/* Resolution mode */
+// Constant value 
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE  					8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE       		0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID	                		0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+#ifdef _ANDROID_4
+#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
+#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
+#define AREA_UNIT						(5792/32)
+#else
+#define AREA_LENGTH_LONGER				31
+#define AREA_LENGTH_SHORT				31
+#endif
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0 
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					(x & 0x6)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+//#define _DEBUG_PACKAGE				//  ON/OFF
+//#define _DEBUG_REPORT					//  ON/OFF
+#define NORMAL_LEN_PER_POINT			6
+#define AREA_LEN_PER_POINT				2
+#define PRESSURE_LEN_PER_POINT			1
+
+//#define _CHECK_CRC					//  ON/OFF
+//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+static const unsigned short crc16tab[256]= {
+		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;   	// uint16_t ?
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;	
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
+static int sis_ts_resume(struct i2c_client *client);
+
+#endif /* _LINUX_SIS_I2C_H */
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-16 10:59         ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-16 10:59 UTC (permalink / raw)
  To: linux-kernel, linux-input, Oliver Neukum; +Cc: tammy0524

Hey, Oliver

On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > (Skip the code diff...)
> 
> Again macros for endianness
> 
> And the driver has a great number of conditional compilations are they 
> really needed? The driver as is has a number of issues and is hard to 
> review due to the use of "//" for comments and a lot of conditional 
> compilation and unnecessary variables used for constants. Could you 
> fix this up and resubmit?

Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
Please help check them if anything needs to fix.
Thanks.

Tammy

---
diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index e1d8003..401cd8b 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,12 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default n
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
+
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index 090e61c..67137af 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   	+= sis_i2c.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..157f991
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1267 @@
+/*
+ * SiS 9200 family I2C Touch Screen Controller Driver
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major = 0;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class = NULL;
+#endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
+static struct workqueue_struct *sis_wq;
+struct sis_ts_data *ts_bak = 0;
+struct sisTP_driver_data *TPInfo = NULL;
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h);
+static void sis_ts_late_resume(struct early_suspend *h);
+#endif
+
+#ifdef CONFIG_X86
+/* static const struct i2c_client_address_data addr_data; */
+/* Insmod parameters */
+static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
+#endif
+
+#ifdef _CHECK_CRC
+uint16_t cal_crc (char* cmd, int start, int end);
+#endif
+
+static void PrintBuffer(int start, int length, char* buf)
+{
+	int i;
+	for ( i = start; i < length; i++ )
+	{
+		printk("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			printk("\n");
+	}
+	printk("\n");	
+}
+
+int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
+{
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Write */
+    msg.flags = 0;
+    msg.len = wlength;
+    msg.buf = (unsigned char *)wdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
+{
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Read */
+    msg.flags = I2C_M_RD;
+    msg.len = rlength;
+    msg.buf = rdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_cul_unit(uint8_t report_id)
+{
+	int ret = NORMAL_LEN_PER_POINT;
+	
+	if (report_id != ALL_IN_ONE_PACKAGE)
+	{
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+		{
+			ret += AREA_LEN_PER_POINT;
+		}
+		if (IS_PRESSURE(report_id))
+		{
+			ret += PRESSURE_LEN_PER_POINT;
+		}
+	}
+	
+	return ret;	
+}
+
+int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
+{
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+#ifdef _CHECK_CRC
+	uint16_t buf_crc = 0;
+	uint16_t package_crc = 0;
+	int l_package_crc = 0;
+	int crc_end = 0;
+#endif
+    int ret = -1;
+    int touchnum = 0;
+    int p_count = 0;
+    int touc_formate_id = 0;
+    int locate = 0;
+    bool read_first = true;
+    
+/*
+		New i2c format 
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
+	* buf[touch num * 6 + 3] = Touch numbers
+	* 
+	* One touch point information include 6 bytes, the order is 
+	* 
+	* 1. status = touch down or touch up
+	* 2. id = finger id 
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	* 
+*/
+	do
+	{
+		if (locate >= PACKET_BUFFER_SIZE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
+			return -1;
+		}
+		
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+
+#ifdef _DEBUG_PACKAGE
+		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+		PrintBuffer(0, 64, tmpbuf);	
+#endif			
+
+		if(ret < 0 )
+		{
+			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		/* error package length of receiving data */
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
+			return -1;	
+		}
+		
+		if (read_first)
+		{
+#ifdef _SUPPORT_BUTTON_TOUCH
+			/* access BUTTON TOUCH event and BUTTON NO TOUCH event */
+			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
+			{
+				memcpy(&buf[0], &tmpbuf[0], 7);
+				return 0; 	/* touchnum is 0 */
+			}
+#endif 
+			/* access NO TOUCH event unless BUTTON NO TOUCH event */
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+			{
+				return 0;	/* touchnum is 0 */
+			}
+		}
+
+		/* skip parsing data when two devices are registered at the same slave address
+		 * parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
+		 */  
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
+			return -1;		
+		}
+		
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/* start from 0 */
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
+		{
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_I2C;	/* delete 2 byte crc */
+			}
+			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_HIDI2C;
+			}
+			else	/* should not be happen */
+			{
+				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
+				return -1;
+			}
+
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_SCANTIME;
+			}
+		}
+		/* else {}    						 For ALL_IN_ONE_PACKAGE */
+		
+		if (read_first)
+		{
+			touchnum = tmpbuf[p_count]; 	
+		}
+		else
+		{
+			if (tmpbuf[p_count] != 0)
+			{
+				printk(KERN_ERR "sis_ReadPacket: get error package\n");
+				return -1;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		buf_crc = cal_crc(tmpbuf, 2, crc_end); /* sub bytecount (2 byte) */
+		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		package_crc = get_unaligned_le16(&tmpbuf[l_package_crc]);
+			
+		if (buf_crc != package_crc)
+		{
+			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
+			return -1;
+		}
+#endif	
+		memcpy(&buf[locate], &tmpbuf[0], 64);	/* Buf_Data [0~63] [64~128] */
+		locate += 64;
+		read_first = false;
+		
+	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
+
+	return touchnum;
+}	
+
+
+int check_gpio_interrupt(void)
+{
+    int ret = 0;
+
+    /* CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING. */
+    ret = gpio_get_value(GPIO_IRQ);
+	
+    return ret;
+}
+
+void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
+{
+	int i = 0;
+	uint8_t diff_keybit_state= 0x0; /* check keybit_state is difference with pre_keybit_state */
+	uint8_t key_value = 0x0; 		/* button location for binary */
+	uint8_t  key_pressed = 0x0; 	/* button is up or down */
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts)
+	{
+		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state)
+	{
+		for (i = 0; i < BUTTON_KEY_COUNT; i++)
+		{
+		    if ((diff_keybit_state >> i) & 0x01)
+			{
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value)
+				{
+					case MSK_COMP:
+						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
+						break;
+					case MSK_BACK:
+						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
+						break;
+					case MSK_MENU:
+						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
+						break;
+					case MSK_HOME:
+						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
+						break;
+					case MSK_NOBTN:
+						/* Release the button if it touched. */
+					default:
+						break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+
+
+static void sis_ts_work_func(struct work_struct *work)
+{
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+    int ret = -1;
+    int point_unit;  
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+    uint8_t p_preasure = 0;
+#ifdef _SUPPORT_BUTTON_TOUCH	
+	int button_key;
+	uint8_t button_buf[10] = {0};
+#endif
+
+#ifdef _ANDROID_4
+	bool all_touch_up = true;
+#endif
+	
+	mutex_lock(&ts->mutex_wq); 
+
+    /* I2C or SMBUS block data read */
+    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+ 
+#ifdef _SUPPORT_BUTTON_TOUCH
+	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
+#endif
+
+	/* Error Number */
+	if (ret < 0) 
+	{
+		goto err_free_allocate;
+	}
+#ifdef _SUPPORT_BUTTON_TOUCH
+	/* access BUTTON TOUCH event and BUTTON NO TOUCH even */
+	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
+	{
+		button_key = get_unaligned_le16(&button_buf[BUTTON_STATE]);		
+		ts_report_key(ts->client, button_key);
+	}
+#endif
+	/* access NO TOUCH event unless BUTTON NO TOUCH event */
+	else if (ret == 0)
+	{
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;  /* need to report input_mt_sync() */
+	}
+	
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+	
+	/* Parser and Get the sis9200 data */
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+	
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+	
+	/* fingers 10 =  0 ~ 9 */
+	for (i = 0; i < fingers; i++) 
+	{
+        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
+        { /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	
+			pstatus += 64;
+		}
+		else 
+		{ /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	
+		}
+
+	    px = pstatus + 2;	/* Calc point x_coord */
+	    py = px + 2;		/* Calc point y_coord */
+
+		if ((buf[pstatus]) == TOUCHUP)
+		{
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		}
+		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
+		{
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;			
+		}
+		else if ((buf[pstatus]) == TOUCHDOWN)
+		{	
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+
+			/* area */
+			if (IS_AREA(buf[P_REPORT_ID]))
+			{
+				TPInfo->pt[i].Width = buf[p_area] & 0xff;
+				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
+			}
+			else 
+			{
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			/* preasure */
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else 
+				TPInfo->pt[i].Pressure = 1;				
+		}
+		else
+		{
+			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
+        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
+	}
+		
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+	{
+		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
+	}
+#endif
+
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+#ifdef _ANDROID_4	
+	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
+	{
+		if(TPInfo->pt[i].Pressure)
+		{
+			TPInfo->pt[i].Width *= AREA_UNIT;	
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		
+		if (i == (TPInfo->fingers -1) && all_touch_up == true)
+		{
+			input_mt_sync(ts->input_dev);
+		}
+	}
+
+	if(TPInfo->fingers == 0)
+	{
+		input_mt_sync(ts->input_dev);
+	}
+#else
+	i = 0;
+	do
+	{
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id); /* Android 2.3 */
+		input_mt_sync(ts->input_dev);
+		i++;
+	}
+	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
+#endif
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+    if (ts->use_irq)
+    {
+/* case 1 mode */
+#ifdef _INT_MODE_1 
+	    /*TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high */
+	    ret = check_gpio_interrupt();	/* interrupt pin is still LOW, read data until interrupt pin is released. */
+	    if (!ret)
+	    {
+	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	    }
+	    else
+	    {
+			if (TPInfo->pre_keybit_state)
+			{
+				ts_report_key(ts->client, 0x0);	/* clear for interrupt */
+			}
+			
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+        	{
+				enable_irq(ts->client->irq);
+			}
+	    }
+/* case 2 mode */
+#else
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(ts->client->irq);
+		}
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+    return;
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
+{
+	int i = 0;
+	for(i = 0; i < max; i++)
+	{
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
+{
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)
+	{	/* For Polling mode */
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	}
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+	struct sis_ts_data *ts = dev_id;
+	
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+	{
+		disable_irq_nosync(ts->client->irq);
+	}
+	queue_work(sis_wq, &ts->work);
+		
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");	/* ex. GPIO_133 for interrupt mode */
+	if (ret < 0)
+	{
+		/* Set Active Low. Please reference the file include/linux/interrupt.h */
+	}
+	/* setting gpio direction here OR boardinfo file*/
+
+#else
+	ret = -1;
+#endif
+	return ret;
+}
+
+uint16_t cal_crc (char* cmd, int start, int end)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+void write_crc (unsigned char *buf, int start, int end)
+{
+	uint16_t crc = 0;
+	
+	crc = cal_crc (buf, start , end);
+	buf[end+1] = (crc >> 8)& 0xff;
+	buf[end+2] = crc & 0xff;
+}
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 
+	 printk(KERN_INFO "sis_cdev_write.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     } 
+#if 0
+	PrintBuffer(0, count, kdata);
+#endif
+		
+	cmd = kdata[6];
+
+/* Write & Read */
+    ret = sis_command_for_write(ts_bak->client, count, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+/* for get system time */
+static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
+{
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 int i;
+	 
+	 printk(KERN_INFO "sis_cdev_read.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }    
+#if 0
+    PrintBuffer(0, count, kdata);
+#endif
+	 cmd = kdata[6];
+	 /* for making sure AP communicates with SiS driver */
+    if(cmd == 0xa2)
+    {
+		kdata[0] = 5;
+		kdata[1] = 0;
+		kdata[3] = 'S';
+		kdata[4] = 'i';
+		kdata[5] = 'S';
+		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+		{
+			printk(KERN_ERR "copy_to_user fail\n" );
+			kfree( kdata );
+			return -19;
+		}
+
+		kfree( kdata );
+		return 3;	
+	}
+/* Write & Read */
+    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+	ret = kdata[0] | (kdata[1] << 8);
+
+    printk(KERN_INFO "%d\n", ret);
+
+    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
+    {
+        printk("%02x ", kdata[i]);
+    }
+
+    printk( "\n" );
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_open.\n");
+	if ( ts_bak == 0 )
+    	return -13;
+
+	msleep(200);
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif	
+		{
+			disable_irq(ts_bak->client->irq);
+		}
+		else
+		{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
+#else
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
+#endif	
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   
+    
+    msleep(200);
+
+	return 0; /* success */
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	printk(KERN_INFO "sis_cdev_release.\n");
+	
+	msleep(200);
+	
+    if (ts_bak == 0)
+    	return -13;
+
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif	
+		{
+			enable_irq(ts_bak->client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+    return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts)
+{
+	
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int alloc_ret = 0;
+	int cdev_err = 0;
+	int input_err = 0;
+	struct device *class_dev = NULL;
+	void *ptr_err;
+	
+	printk("sis_setup_chardev.\n");
+	
+	if (ts == NULL) 
+	{
+	  input_err = -ENOMEM;
+	  goto error;
+	} 
+	/* dynamic allocate driver handle */
+	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
+	if (alloc_ret)
+		goto error;
+		
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
+	
+	if (cdev_err) 
+		goto error;
+	
+	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
+	
+	/* register class */
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+	
+	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
+	
+	if(IS_ERR(ptr_err = class_dev)) 
+	{
+		goto err;
+	}
+	
+	return 0;
+error:
+	if (cdev_err == 0)
+		cdev_del(&sis_char_cdev);
+	if (alloc_ret == 0)
+		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
+	if(input_err != 0)
+	{
+		printk("sis_ts_bak error!\n");
+	}
+err:
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+err2:
+	class_destroy(sis_char_class);
+	return -1;
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+    printk(KERN_INFO "sis_ts_probe\n");
+
+    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+    if (TPInfo == NULL) 
+    {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) 
+	{
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts_bak = ts;
+
+	mutex_init(&ts->mutex_wq);
+	
+	/* 1. Init Work queue and necessary buffers */
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+    pdata = client->dev.platform_data;
+
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) 
+	{
+		ret = ts->power(1);
+		if (ret < 0) 
+		{
+			printk(KERN_ERR "sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+
+	/* 2. Allocate input device */
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) 
+	{
+		ret = -ENOMEM;
+		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+
+	/* This input device name should be the same to IDC file name. */
+	ts->input_dev->name = "sis_touch";
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+
+#ifdef _ANDROID_4
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
+#else
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
+#endif
+
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
+	
+    /* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+
+	/* 3. Register input device to core */
+	ret = input_register_device(ts->input_dev);
+
+	if (ret) 
+	{
+		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	
+	/* 4. irq or timer setup */
+	ret = initial_irq();
+	if (ret < 0) 
+	{
+
+	}
+	else
+	{
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0) 
+		{
+		   ts->use_irq = 1;
+		}
+		else 
+		{
+			dev_err(&client->dev, "request_irq failed\n");
+		}
+	}
+
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+
+	if (!ts->use_irq) 
+	{
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+	
+	if (ts->use_irq)
+	{
+#ifdef _INT_MODE_1
+		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
+#else
+		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
+#endif
+	}
+	
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if(ret)
+	{
+		printk( KERN_INFO"sis_setup_chardev fail\n");
+	}
+#endif
+
+	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+
+	return 0;
+
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client)
+{
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+	
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif
+		{
+			disable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_cancel(&ts->timer);
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   		
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_suspend power off failed\n");
+	}
+	
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power)
+	{
+		ret = ts->power(1);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_resume power on failed\n");
+	}
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void sis_ts_late_resume(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+	
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+    .class      = I2C_CLASS_HWMON,
+    .detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __init sis_ts_init(void)
+{
+	printk( KERN_INFO "sis_ts_init\n" );
+	
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+		
+	return i2c_add_driver(&sis_ts_driver);
+}
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+	
+    printk(KERN_INFO "sis_ts_detect\n");
+	
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	
+	return 0;
+}
+#endif
+
+static void __exit sis_ts_exit(void)
+{
+#ifdef _STD_RW_IO
+	dev_t dev;
+#endif
+
+	printk(KERN_INFO "sis_ts_exit\n");
+	
+	i2c_del_driver(&sis_ts_driver);
+	
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+
+#ifdef _STD_RW_IO
+	dev = MKDEV(sis_char_major, 0);
+	cdev_del(&sis_char_cdev);
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+	class_destroy(sis_char_class);
+#endif
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..c1d65c4
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,215 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2015/01/15
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+#define TIMER_NS    					10000000 //10ms
+#define MAX_FINGERS						10
+
+
+/* For Android 4.0 							*/
+/* Only for Linux kernel 2.6.34 and later 	*/
+#define _ANDROID_4					//  ON/OFF
+
+/* For standard R/W IO*/
+#define _STD_RW_IO						//  ON/OFF
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					//  ON/OFF
+#define GPIO_IRQ 						133
+
+/*  Enable if use interrupt case 1 mode.  */
+/* 	Disable if use interrupt case 2 mode. */
+//#define _INT_MODE_1					//	ON/OFF
+
+/* IRQ STATUS */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+#define IRQ_STATUS_DISABLED				0x200  
+#else
+#define IRQ_STATUS_DISABLED				(1<<16)
+#endif
+#define IRQ_STATUS_ENABLED				0x0
+
+/* Resolution mode */
+// Constant value 
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE  					8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE       		0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID	                		0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+#ifdef _ANDROID_4
+#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
+#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
+#define AREA_UNIT						(5792/32)
+#else
+#define AREA_LENGTH_LONGER				31
+#define AREA_LENGTH_SHORT				31
+#endif
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0 
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					(x & 0x6)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+//#define _DEBUG_PACKAGE				//  ON/OFF
+//#define _DEBUG_REPORT					//  ON/OFF
+#define NORMAL_LEN_PER_POINT			6
+#define AREA_LEN_PER_POINT				2
+#define PRESSURE_LEN_PER_POINT			1
+
+//#define _CHECK_CRC					//  ON/OFF
+//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+static const unsigned short crc16tab[256]= {
+		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;   	// uint16_t ?
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;	
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
+static int sis_ts_resume(struct i2c_client *client);
+
+#endif /* _LINUX_SIS_I2C_H */

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
       [not found]     ` <8322374EB97AA24A95D0DDBFC8F1CA1DBF9DE5@SISMBEV01.sis.com.tw>
@ 2015-01-16 11:19         ` 曾婷葳 (tammy_tseng)
  2015-01-16 11:19         ` 曾婷葳 (tammy_tseng)
  1 sibling, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-16 11:19 UTC (permalink / raw)
  To: Oliver Neukum, linux-kernel, linux-input; +Cc: tammy0524

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 41323 bytes --]

Hey, Oliver

On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > (Skip the code diff...)
> 
> Again macros for endianness
> 
> And the driver has a great number of conditional compilations are they 
> really needed? The driver as is has a number of issues and is hard to 
> review due to the use of "//" for comments and a lot of conditional 
> compilation and unnecessary variables used for constants. Could you 
> fix this up and resubmit?

Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
Please help check them if anything needs to fix.
Thanks.

Tammy

---
diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index e1d8003..401cd8b 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,12 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default n
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
+
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index 090e61c..67137af 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   	+= sis_i2c.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..157f991
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1267 @@
+/*
+ * SiS 9200 family I2C Touch Screen Controller Driver
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major = 0;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class = NULL; #endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, 
+I2C_CLIENT_END }; static struct workqueue_struct *sis_wq; struct 
+sis_ts_data *ts_bak = 0; struct sisTP_driver_data *TPInfo = NULL; 
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int 
+max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h); static void 
+sis_ts_late_resume(struct early_suspend *h); #endif
+
+#ifdef CONFIG_X86
+/* static const struct i2c_client_address_data addr_data; */
+/* Insmod parameters */
+static int sis_ts_detect(struct i2c_client *client, struct 
+i2c_board_info *info); #endif
+
+#ifdef _CHECK_CRC
+uint16_t cal_crc (char* cmd, int start, int end); #endif
+
+static void PrintBuffer(int start, int length, char* buf) {
+	int i;
+	for ( i = start; i < length; i++ )
+	{
+		printk("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			printk("\n");
+	}
+	printk("\n");	
+}
+
+int sis_command_for_write(struct i2c_client *client, int wlength, 
+unsigned char *wdata) {
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Write */
+    msg.flags = 0;
+    msg.len = wlength;
+    msg.buf = (unsigned char *)wdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_command_for_read(struct i2c_client *client, int rlength, 
+unsigned char *rdata) {
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Read */
+    msg.flags = I2C_M_RD;
+    msg.len = rlength;
+    msg.buf = rdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_cul_unit(uint8_t report_id)
+{
+	int ret = NORMAL_LEN_PER_POINT;
+	
+	if (report_id != ALL_IN_ONE_PACKAGE)
+	{
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+		{
+			ret += AREA_LEN_PER_POINT;
+		}
+		if (IS_PRESSURE(report_id))
+		{
+			ret += PRESSURE_LEN_PER_POINT;
+		}
+	}
+	
+	return ret;	
+}
+
+int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* 
+buf) {
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+#ifdef _CHECK_CRC
+	uint16_t buf_crc = 0;
+	uint16_t package_crc = 0;
+	int l_package_crc = 0;
+	int crc_end = 0;
+#endif
+    int ret = -1;
+    int touchnum = 0;
+    int p_count = 0;
+    int touc_formate_id = 0;
+    int locate = 0;
+    bool read_first = true;
+    
+/*
+		New i2c format 
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
+	* buf[touch num * 6 + 3] = Touch numbers
+	* 
+	* One touch point information include 6 bytes, the order is 
+	* 
+	* 1. status = touch down or touch up
+	* 2. id = finger id 
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	*
+*/
+	do
+	{
+		if (locate >= PACKET_BUFFER_SIZE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
+			return -1;
+		}
+		
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+
+#ifdef _DEBUG_PACKAGE
+		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+		PrintBuffer(0, 64, tmpbuf);	
+#endif			
+
+		if(ret < 0 )
+		{
+			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		/* error package length of receiving data */
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
+			return -1;	
+		}
+		
+		if (read_first)
+		{
+#ifdef _SUPPORT_BUTTON_TOUCH
+			/* access BUTTON TOUCH event and BUTTON NO TOUCH event */
+			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
+			{
+				memcpy(&buf[0], &tmpbuf[0], 7);
+				return 0; 	/* touchnum is 0 */
+			}
+#endif 
+			/* access NO TOUCH event unless BUTTON NO TOUCH event */
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+			{
+				return 0;	/* touchnum is 0 */
+			}
+		}
+
+		/* skip parsing data when two devices are registered at the same slave address
+		 * parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
+		 */  
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
+			return -1;		
+		}
+		
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/* start from 0 */
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
+		{
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_I2C;	/* delete 2 byte crc */
+			}
+			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_HIDI2C;
+			}
+			else	/* should not be happen */
+			{
+				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
+				return -1;
+			}
+
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_SCANTIME;
+			}
+		}
+		/* else {}    						 For ALL_IN_ONE_PACKAGE */
+		
+		if (read_first)
+		{
+			touchnum = tmpbuf[p_count]; 	
+		}
+		else
+		{
+			if (tmpbuf[p_count] != 0)
+			{
+				printk(KERN_ERR "sis_ReadPacket: get error package\n");
+				return -1;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		buf_crc = cal_crc(tmpbuf, 2, crc_end); /* sub bytecount (2 byte) */
+		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		package_crc = get_unaligned_le16(&tmpbuf[l_package_crc]);
+			
+		if (buf_crc != package_crc)
+		{
+			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
+			return -1;
+		}
+#endif	
+		memcpy(&buf[locate], &tmpbuf[0], 64);	/* Buf_Data [0~63] [64~128] */
+		locate += 64;
+		read_first = false;
+		
+	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] 
+> 5);
+
+	return touchnum;
+}	
+
+
+int check_gpio_interrupt(void)
+{
+    int ret = 0;
+
+    /* CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING. */
+    ret = gpio_get_value(GPIO_IRQ);
+	
+    return ret;
+}
+
+void ts_report_key(struct i2c_client *client, uint8_t keybit_state) {
+	int i = 0;
+	uint8_t diff_keybit_state= 0x0; /* check keybit_state is difference with pre_keybit_state */
+	uint8_t key_value = 0x0; 		/* button location for binary */
+	uint8_t  key_pressed = 0x0; 	/* button is up or down */
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts)
+	{
+		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state)
+	{
+		for (i = 0; i < BUTTON_KEY_COUNT; i++)
+		{
+		    if ((diff_keybit_state >> i) & 0x01)
+			{
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value)
+				{
+					case MSK_COMP:
+						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
+						break;
+					case MSK_BACK:
+						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
+						break;
+					case MSK_MENU:
+						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
+						break;
+					case MSK_HOME:
+						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
+						break;
+					case MSK_NOBTN:
+						/* Release the button if it touched. */
+					default:
+						break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+
+
+static void sis_ts_work_func(struct work_struct *work) {
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+    int ret = -1;
+    int point_unit;  
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+    uint8_t p_preasure = 0;
+#ifdef _SUPPORT_BUTTON_TOUCH	
+	int button_key;
+	uint8_t button_buf[10] = {0};
+#endif
+
+#ifdef _ANDROID_4
+	bool all_touch_up = true;
+#endif
+	
+	mutex_lock(&ts->mutex_wq);
+
+    /* I2C or SMBUS block data read */
+    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+ 
+#ifdef _SUPPORT_BUTTON_TOUCH
+	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf); #endif
+
+	/* Error Number */
+	if (ret < 0) 
+	{
+		goto err_free_allocate;
+	}
+#ifdef _SUPPORT_BUTTON_TOUCH
+	/* access BUTTON TOUCH event and BUTTON NO TOUCH even */
+	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
+	{
+		button_key = get_unaligned_le16(&button_buf[BUTTON_STATE]);		
+		ts_report_key(ts->client, button_key);
+	}
+#endif
+	/* access NO TOUCH event unless BUTTON NO TOUCH event */
+	else if (ret == 0)
+	{
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;  /* need to report input_mt_sync() */
+	}
+	
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+	
+	/* Parser and Get the sis9200 data */
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+	
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+	
+	/* fingers 10 =  0 ~ 9 */
+	for (i = 0; i < fingers; i++) 
+	{
+        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
+        { /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	
+			pstatus += 64;
+		}
+		else 
+		{ /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	
+		}
+
+	    px = pstatus + 2;	/* Calc point x_coord */
+	    py = px + 2;		/* Calc point y_coord */
+
+		if ((buf[pstatus]) == TOUCHUP)
+		{
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		}
+		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
+		{
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;			
+		}
+		else if ((buf[pstatus]) == TOUCHDOWN)
+		{	
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+
+			/* area */
+			if (IS_AREA(buf[P_REPORT_ID]))
+			{
+				TPInfo->pt[i].Width = buf[p_area] & 0xff;
+				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
+			}
+			else 
+			{
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			/* preasure */
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else 
+				TPInfo->pt[i].Pressure = 1;				
+		}
+		else
+		{
+			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
+        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
+	}
+		
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+	{
+		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
+	}
+#endif
+
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+#ifdef _ANDROID_4	
+	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
+	{
+		if(TPInfo->pt[i].Pressure)
+		{
+			TPInfo->pt[i].Width *= AREA_UNIT;	
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		
+		if (i == (TPInfo->fingers -1) && all_touch_up == true)
+		{
+			input_mt_sync(ts->input_dev);
+		}
+	}
+
+	if(TPInfo->fingers == 0)
+	{
+		input_mt_sync(ts->input_dev);
+	}
+#else
+	i = 0;
+	do
+	{
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id); /* Android 2.3 */
+		input_mt_sync(ts->input_dev);
+		i++;
+	}
+	while ((i < TPInfo->fingers) && (i < MAX_FINGERS)); #endif
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+    if (ts->use_irq)
+    {
+/* case 1 mode */
+#ifdef _INT_MODE_1 
+	    /*TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high */
+	    ret = check_gpio_interrupt();	/* interrupt pin is still LOW, read data until interrupt pin is released. */
+	    if (!ret)
+	    {
+	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	    }
+	    else
+	    {
+			if (TPInfo->pre_keybit_state)
+			{
+				ts_report_key(ts->client, 0x0);	/* clear for interrupt */
+			}
+			
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED) 
+#else
+        	if ((ts->desc->irq_data.state_use_accessors & 
+IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED) #endif
+        	{
+				enable_irq(ts->client->irq);
+			}
+	    }
+/* case 2 mode */
+#else
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED) #else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_DISABLED) #endif
+		{
+			enable_irq(ts->client->irq);
+		}
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+    return;
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max) 
+{
+	int i = 0;
+	for(i = 0; i < max; i++)
+	{
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer) {
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)
+	{	/* For Polling mode */
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	}
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id) {
+	struct sis_ts_data *ts = dev_id;
+	
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED) #else
+	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_ENABLED) #endif
+	{
+		disable_irq_nosync(ts->client->irq);
+	}
+	queue_work(sis_wq, &ts->work);
+		
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");	/* ex. GPIO_133 for interrupt mode */
+	if (ret < 0)
+	{
+		/* Set Active Low. Please reference the file include/linux/interrupt.h */
+	}
+	/* setting gpio direction here OR boardinfo file*/
+
+#else
+	ret = -1;
+#endif
+	return ret;
+}
+
+uint16_t cal_crc (char* cmd, int start, int end) {
+	int i = 0;
+	uint16_t crc = 0;
+	
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd) 
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+void write_crc (unsigned char *buf, int start, int end) {
+	uint16_t crc = 0;
+	
+	crc = cal_crc (buf, start , end);
+	buf[end+1] = (crc >> 8)& 0xff;
+	buf[end+2] = crc & 0xff;
+}
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write( struct file *file, const char __user 
+*buf, size_t count, loff_t *f_pos ) {
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 
+	 printk(KERN_INFO "sis_cdev_write.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }
+#if 0
+	PrintBuffer(0, count, kdata);
+#endif
+		
+	cmd = kdata[6];
+
+/* Write & Read */
+    ret = sis_command_for_write(ts_bak->client, count, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+/* for get system time */
+static ssize_t sis_cdev_read( struct file *file, char __user *buf, 
+size_t count, loff_t *f_pos ) {
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 int i;
+	 
+	 printk(KERN_INFO "sis_cdev_read.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }    
+#if 0
+    PrintBuffer(0, count, kdata);
+#endif
+	 cmd = kdata[6];
+	 /* for making sure AP communicates with SiS driver */
+    if(cmd == 0xa2)
+    {
+		kdata[0] = 5;
+		kdata[1] = 0;
+		kdata[3] = 'S';
+		kdata[4] = 'i';
+		kdata[5] = 'S';
+		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+		{
+			printk(KERN_ERR "copy_to_user fail\n" );
+			kfree( kdata );
+			return -19;
+		}
+
+		kfree( kdata );
+		return 3;	
+	}
+/* Write & Read */
+    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+	ret = kdata[0] | (kdata[1] << 8);
+
+    printk(KERN_INFO "%d\n", ret);
+
+    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
+    {
+        printk("%02x ", kdata[i]);
+    }
+
+    printk( "\n" );
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp) {
+	printk(KERN_INFO "sis_cdev_open.\n");
+	if ( ts_bak == 0 )
+    	return -13;
+
+	msleep(200);
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == 
+IRQ_STATUS_ENABLED) #else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif	
+		{
+			disable_irq(ts_bak->client->irq);
+		}
+		else
+		{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: 
+%x\n",(ts_bak->desc->status & IRQ_DISABLED)); #else
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
+#endif	
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   
+    
+    msleep(200);
+
+	return 0; /* success */
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp) {
+	printk(KERN_INFO "sis_cdev_release.\n");
+	
+	msleep(200);
+	
+    if (ts_bak == 0)
+    	return -13;
+
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == 
+IRQ_STATUS_DISABLED) #else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif	
+		{
+			enable_irq(ts_bak->client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+    return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts) {
+	
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int alloc_ret = 0;
+	int cdev_err = 0;
+	int input_err = 0;
+	struct device *class_dev = NULL;
+	void *ptr_err;
+	
+	printk("sis_setup_chardev.\n");
+	
+	if (ts == NULL) 
+	{
+	  input_err = -ENOMEM;
+	  goto error;
+	} 
+	/* dynamic allocate driver handle */
+	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
+	if (alloc_ret)
+		goto error;
+		
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), 
+sis_char_devs_count);
+	
+	if (cdev_err) 
+		goto error;
+	
+	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, 
+sis_char_major);
+	
+	/* register class */
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+	
+	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 
+0), NULL, DEVICE_NAME);
+	
+	if(IS_ERR(ptr_err = class_dev)) 
+	{
+		goto err;
+	}
+	
+	return 0;
+error:
+	if (cdev_err == 0)
+		cdev_del(&sis_char_cdev);
+	if (alloc_ret == 0)
+		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
+	if(input_err != 0)
+	{
+		printk("sis_ts_bak error!\n");
+	}
+err:
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+err2:
+	class_destroy(sis_char_class);
+	return -1;
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id) {
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+    printk(KERN_INFO "sis_ts_probe\n");
+
+    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+    if (TPInfo == NULL) 
+    {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) 
+	{
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts_bak = ts;
+
+	mutex_init(&ts->mutex_wq);
+	
+	/* 1. Init Work queue and necessary buffers */
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+    pdata = client->dev.platform_data;
+
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) 
+	{
+		ret = ts->power(1);
+		if (ret < 0) 
+		{
+			printk(KERN_ERR "sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+
+	/* 2. Allocate input device */
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) 
+	{
+		ret = -ENOMEM;
+		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+
+	/* This input device name should be the same to IDC file name. */
+	ts->input_dev->name = "sis_touch";
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+
+#ifdef _ANDROID_4
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
+#else
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, 
+AREA_LENGTH_SHORT, 0, 0); #endif
+
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 
+ 0);
+	
+    /* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+
+	/* 3. Register input device to core */
+	ret = input_register_device(ts->input_dev);
+
+	if (ret) 
+	{
+		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	
+	/* 4. irq or timer setup */
+	ret = initial_irq();
+	if (ret < 0) 
+	{
+
+	}
+	else
+	{
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0) 
+		{
+		   ts->use_irq = 1;
+		}
+		else 
+		{
+			dev_err(&client->dev, "request_irq failed\n");
+		}
+	}
+
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+
+	if (!ts->use_irq) 
+	{
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", 
+ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+	
+	if (ts->use_irq)
+	{
+#ifdef _INT_MODE_1
+		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n"); #else
+		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n"); #endif
+	}
+	
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if(ret)
+	{
+		printk( KERN_INFO"sis_setup_chardev fail\n");
+	}
+#endif
+
+	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+
+	return 0;
+
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client) {
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+	
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg) 
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED) #else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_ENABLED) #endif
+		{
+			disable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_cancel(&ts->timer);
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   		
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_suspend power off failed\n");
+	}
+	
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client) {
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power)
+	{
+		ret = ts->power(1);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_resume power on failed\n");
+	}
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED) #else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_DISABLED) #endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h) {
+	struct sis_ts_data *ts;
+	
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND); }
+
+static void sis_ts_late_resume(struct early_suspend *h) {
+	struct sis_ts_data *ts;
+	
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+    .class      = I2C_CLASS_HWMON,
+    .detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __init sis_ts_init(void)
+{
+	printk( KERN_INFO "sis_ts_init\n" );
+	
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+		
+	return i2c_add_driver(&sis_ts_driver); }
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */ static int 
+sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+	
+    printk(KERN_INFO "sis_ts_detect\n");
+	
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	
+	return 0;
+}
+#endif
+
+static void __exit sis_ts_exit(void)
+{
+#ifdef _STD_RW_IO
+	dev_t dev;
+#endif
+
+	printk(KERN_INFO "sis_ts_exit\n");
+	
+	i2c_del_driver(&sis_ts_driver);
+	
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+
+#ifdef _STD_RW_IO
+	dev = MKDEV(sis_char_major, 0);
+	cdev_del(&sis_char_cdev);
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+	class_destroy(sis_char_class);
+#endif
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver"); 
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..c1d65c4
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,215 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 
+family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2015/01/15
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+#define TIMER_NS    					10000000 //10ms
+#define MAX_FINGERS						10
+
+
+/* For Android 4.0 							*/
+/* Only for Linux kernel 2.6.34 and later 	*/
+#define _ANDROID_4					//  ON/OFF
+
+/* For standard R/W IO*/
+#define _STD_RW_IO						//  ON/OFF
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					//  ON/OFF
+#define GPIO_IRQ 						133
+
+/*  Enable if use interrupt case 1 mode.  */
+/* 	Disable if use interrupt case 2 mode. */
+//#define _INT_MODE_1					//	ON/OFF
+
+/* IRQ STATUS */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+#define IRQ_STATUS_DISABLED				0x200  
+#else
+#define IRQ_STATUS_DISABLED				(1<<16)
+#endif
+#define IRQ_STATUS_ENABLED				0x0
+
+/* Resolution mode */
+// Constant value 
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE  					8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE       		0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID	                		0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+#ifdef _ANDROID_4
+#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
+#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
+#define AREA_UNIT						(5792/32)
+#else
+#define AREA_LENGTH_LONGER				31
+#define AREA_LENGTH_SHORT				31
+#endif
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0 
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					(x & 0x6)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+//#define _DEBUG_PACKAGE				//  ON/OFF
+//#define _DEBUG_REPORT					//  ON/OFF
+#define NORMAL_LEN_PER_POINT			6
+#define AREA_LEN_PER_POINT				2
+#define PRESSURE_LEN_PER_POINT			1
+
+//#define _CHECK_CRC					//  ON/OFF
+//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+static const unsigned short crc16tab[256]= {
+		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;   	// uint16_t ?
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;	
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t 
+mesg); static int sis_ts_resume(struct i2c_client *client);
+
+#endif /* _LINUX_SIS_I2C_H */
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-16 11:19         ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-16 11:19 UTC (permalink / raw)
  To: Oliver Neukum, linux-kernel, linux-input; +Cc: tammy0524

Hey, Oliver

On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > (Skip the code diff...)
> 
> Again macros for endianness
> 
> And the driver has a great number of conditional compilations are they 
> really needed? The driver as is has a number of issues and is hard to 
> review due to the use of "//" for comments and a lot of conditional 
> compilation and unnecessary variables used for constants. Could you 
> fix this up and resubmit?

Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
Please help check them if anything needs to fix.
Thanks.

Tammy

---
diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index e1d8003..401cd8b 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,12 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default n
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
+
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index 090e61c..67137af 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   	+= sis_i2c.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..157f991
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1267 @@
+/*
+ * SiS 9200 family I2C Touch Screen Controller Driver
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major = 0;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class = NULL; #endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, 
+I2C_CLIENT_END }; static struct workqueue_struct *sis_wq; struct 
+sis_ts_data *ts_bak = 0; struct sisTP_driver_data *TPInfo = NULL; 
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int 
+max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h); static void 
+sis_ts_late_resume(struct early_suspend *h); #endif
+
+#ifdef CONFIG_X86
+/* static const struct i2c_client_address_data addr_data; */
+/* Insmod parameters */
+static int sis_ts_detect(struct i2c_client *client, struct 
+i2c_board_info *info); #endif
+
+#ifdef _CHECK_CRC
+uint16_t cal_crc (char* cmd, int start, int end); #endif
+
+static void PrintBuffer(int start, int length, char* buf) {
+	int i;
+	for ( i = start; i < length; i++ )
+	{
+		printk("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			printk("\n");
+	}
+	printk("\n");	
+}
+
+int sis_command_for_write(struct i2c_client *client, int wlength, 
+unsigned char *wdata) {
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Write */
+    msg.flags = 0;
+    msg.len = wlength;
+    msg.buf = (unsigned char *)wdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_command_for_read(struct i2c_client *client, int rlength, 
+unsigned char *rdata) {
+    int ret = -1;
+    struct i2c_msg msg;
+
+    msg.addr = client->addr;
+    /* Read */
+    msg.flags = I2C_M_RD;
+    msg.len = rlength;
+    msg.buf = rdata;
+
+    ret = i2c_transfer(client->adapter, &msg, 1);
+
+    return ret;
+}
+
+int sis_cul_unit(uint8_t report_id)
+{
+	int ret = NORMAL_LEN_PER_POINT;
+	
+	if (report_id != ALL_IN_ONE_PACKAGE)
+	{
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+		{
+			ret += AREA_LEN_PER_POINT;
+		}
+		if (IS_PRESSURE(report_id))
+		{
+			ret += PRESSURE_LEN_PER_POINT;
+		}
+	}
+	
+	return ret;	
+}
+
+int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* 
+buf) {
+	uint8_t tmpbuf[MAX_BYTE] = {0};
+#ifdef _CHECK_CRC
+	uint16_t buf_crc = 0;
+	uint16_t package_crc = 0;
+	int l_package_crc = 0;
+	int crc_end = 0;
+#endif
+    int ret = -1;
+    int touchnum = 0;
+    int p_count = 0;
+    int touc_formate_id = 0;
+    int locate = 0;
+    bool read_first = true;
+    
+/*
+		New i2c format 
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
+	* buf[touch num * 6 + 3] = Touch numbers
+	* 
+	* One touch point information include 6 bytes, the order is 
+	* 
+	* 1. status = touch down or touch up
+	* 2. id = finger id 
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	*
+*/
+	do
+	{
+		if (locate >= PACKET_BUFFER_SIZE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
+			return -1;
+		}
+		
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+
+#ifdef _DEBUG_PACKAGE
+		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
+		PrintBuffer(0, 64, tmpbuf);	
+#endif			
+
+		if(ret < 0 )
+		{
+			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		/* error package length of receiving data */
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
+			return -1;	
+		}
+		
+		if (read_first)
+		{
+#ifdef _SUPPORT_BUTTON_TOUCH
+			/* access BUTTON TOUCH event and BUTTON NO TOUCH event */
+			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
+			{
+				memcpy(&buf[0], &tmpbuf[0], 7);
+				return 0; 	/* touchnum is 0 */
+			}
+#endif 
+			/* access NO TOUCH event unless BUTTON NO TOUCH event */
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+			{
+				return 0;	/* touchnum is 0 */
+			}
+		}
+
+		/* skip parsing data when two devices are registered at the same slave address
+		 * parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
+		 */  
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
+		{
+			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
+			return -1;		
+		}
+		
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/* start from 0 */
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
+		{
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_I2C;	/* delete 2 byte crc */
+			}
+			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_CRC_HIDI2C;
+			}
+			else	/* should not be happen */
+			{
+				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
+				return -1;
+			}
+
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+			{
+				p_count -= BYTE_SCANTIME;
+			}
+		}
+		/* else {}    						 For ALL_IN_ONE_PACKAGE */
+		
+		if (read_first)
+		{
+			touchnum = tmpbuf[p_count]; 	
+		}
+		else
+		{
+			if (tmpbuf[p_count] != 0)
+			{
+				printk(KERN_ERR "sis_ReadPacket: get error package\n");
+				return -1;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		buf_crc = cal_crc(tmpbuf, 2, crc_end); /* sub bytecount (2 byte) */
+		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
+		package_crc = get_unaligned_le16(&tmpbuf[l_package_crc]);
+			
+		if (buf_crc != package_crc)
+		{
+			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
+			return -1;
+		}
+#endif	
+		memcpy(&buf[locate], &tmpbuf[0], 64);	/* Buf_Data [0~63] [64~128] */
+		locate += 64;
+		read_first = false;
+		
+	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] 
+> 5);
+
+	return touchnum;
+}	
+
+
+int check_gpio_interrupt(void)
+{
+    int ret = 0;
+
+    /* CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING. */
+    ret = gpio_get_value(GPIO_IRQ);
+	
+    return ret;
+}
+
+void ts_report_key(struct i2c_client *client, uint8_t keybit_state) {
+	int i = 0;
+	uint8_t diff_keybit_state= 0x0; /* check keybit_state is difference with pre_keybit_state */
+	uint8_t key_value = 0x0; 		/* button location for binary */
+	uint8_t  key_pressed = 0x0; 	/* button is up or down */
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts)
+	{
+		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state)
+	{
+		for (i = 0; i < BUTTON_KEY_COUNT; i++)
+		{
+		    if ((diff_keybit_state >> i) & 0x01)
+			{
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value)
+				{
+					case MSK_COMP:
+						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
+						break;
+					case MSK_BACK:
+						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
+						break;
+					case MSK_MENU:
+						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
+						break;
+					case MSK_HOME:
+						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
+						break;
+					case MSK_NOBTN:
+						/* Release the button if it touched. */
+					default:
+						break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+
+
+static void sis_ts_work_func(struct work_struct *work) {
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+    int ret = -1;
+    int point_unit;  
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+    uint8_t p_preasure = 0;
+#ifdef _SUPPORT_BUTTON_TOUCH	
+	int button_key;
+	uint8_t button_buf[10] = {0};
+#endif
+
+#ifdef _ANDROID_4
+	bool all_touch_up = true;
+#endif
+	
+	mutex_lock(&ts->mutex_wq);
+
+    /* I2C or SMBUS block data read */
+    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+ 
+#ifdef _SUPPORT_BUTTON_TOUCH
+	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf); #endif
+
+	/* Error Number */
+	if (ret < 0) 
+	{
+		goto err_free_allocate;
+	}
+#ifdef _SUPPORT_BUTTON_TOUCH
+	/* access BUTTON TOUCH event and BUTTON NO TOUCH even */
+	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
+	{
+		button_key = get_unaligned_le16(&button_buf[BUTTON_STATE]);		
+		ts_report_key(ts->client, button_key);
+	}
+#endif
+	/* access NO TOUCH event unless BUTTON NO TOUCH event */
+	else if (ret == 0)
+	{
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;  /* need to report input_mt_sync() */
+	}
+	
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+	
+	/* Parser and Get the sis9200 data */
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+	
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+	
+	/* fingers 10 =  0 ~ 9 */
+	for (i = 0; i < fingers; i++) 
+	{
+        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
+        { /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	
+			pstatus += 64;
+		}
+		else 
+		{ /* Calc point status */
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	
+		}
+
+	    px = pstatus + 2;	/* Calc point x_coord */
+	    py = px + 2;		/* Calc point y_coord */
+
+		if ((buf[pstatus]) == TOUCHUP)
+		{
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		}
+		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
+		{
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;			
+		}
+		else if ((buf[pstatus]) == TOUCHDOWN)
+		{	
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+
+			/* area */
+			if (IS_AREA(buf[P_REPORT_ID]))
+			{
+				TPInfo->pt[i].Width = buf[p_area] & 0xff;
+				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
+			}
+			else 
+			{
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			/* preasure */
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else 
+				TPInfo->pt[i].Pressure = 1;				
+		}
+		else
+		{
+			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
+        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
+	}
+		
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+	{
+		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
+	}
+#endif
+
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+#ifdef _ANDROID_4	
+	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
+	{
+		if(TPInfo->pt[i].Pressure)
+		{
+			TPInfo->pt[i].Width *= AREA_UNIT;	
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		
+		if (i == (TPInfo->fingers -1) && all_touch_up == true)
+		{
+			input_mt_sync(ts->input_dev);
+		}
+	}
+
+	if(TPInfo->fingers == 0)
+	{
+		input_mt_sync(ts->input_dev);
+	}
+#else
+	i = 0;
+	do
+	{
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
+		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id); /* Android 2.3 */
+		input_mt_sync(ts->input_dev);
+		i++;
+	}
+	while ((i < TPInfo->fingers) && (i < MAX_FINGERS)); #endif
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+    if (ts->use_irq)
+    {
+/* case 1 mode */
+#ifdef _INT_MODE_1 
+	    /*TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high */
+	    ret = check_gpio_interrupt();	/* interrupt pin is still LOW, read data until interrupt pin is released. */
+	    if (!ret)
+	    {
+	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	    }
+	    else
+	    {
+			if (TPInfo->pre_keybit_state)
+			{
+				ts_report_key(ts->client, 0x0);	/* clear for interrupt */
+			}
+			
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED) 
+#else
+        	if ((ts->desc->irq_data.state_use_accessors & 
+IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED) #endif
+        	{
+				enable_irq(ts->client->irq);
+			}
+	    }
+/* case 2 mode */
+#else
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED) #else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_DISABLED) #endif
+		{
+			enable_irq(ts->client->irq);
+		}
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+    return;
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max) 
+{
+	int i = 0;
+	for(i = 0; i < max; i++)
+	{
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer) {
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)
+	{	/* For Polling mode */
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	}
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id) {
+	struct sis_ts_data *ts = dev_id;
+	
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED) #else
+	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_ENABLED) #endif
+	{
+		disable_irq_nosync(ts->client->irq);
+	}
+	queue_work(sis_wq, &ts->work);
+		
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");	/* ex. GPIO_133 for interrupt mode */
+	if (ret < 0)
+	{
+		/* Set Active Low. Please reference the file include/linux/interrupt.h */
+	}
+	/* setting gpio direction here OR boardinfo file*/
+
+#else
+	ret = -1;
+#endif
+	return ret;
+}
+
+uint16_t cal_crc (char* cmd, int start, int end) {
+	int i = 0;
+	uint16_t crc = 0;
+	
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd) 
+{
+	int i = 0;
+	uint16_t crc = 0;
+	
+	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
+	for (i = start; i <= end ; i++)
+	{
+		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
+	}
+	
+	return crc;
+}
+
+void write_crc (unsigned char *buf, int start, int end) {
+	uint16_t crc = 0;
+	
+	crc = cal_crc (buf, start , end);
+	buf[end+1] = (crc >> 8)& 0xff;
+	buf[end+2] = crc & 0xff;
+}
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write( struct file *file, const char __user 
+*buf, size_t count, loff_t *f_pos ) {
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 
+	 printk(KERN_INFO "sis_cdev_write.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }
+#if 0
+	PrintBuffer(0, count, kdata);
+#endif
+		
+	cmd = kdata[6];
+
+/* Write & Read */
+    ret = sis_command_for_write(ts_bak->client, count, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+/* for get system time */
+static ssize_t sis_cdev_read( struct file *file, char __user *buf, 
+size_t count, loff_t *f_pos ) {
+	 int ret = 0;
+	 char *kdata;
+	 char cmd;
+	 int i;
+	 
+	 printk(KERN_INFO "sis_cdev_read.\n");
+	 
+	 if (ts_bak == 0)
+    	return -13;
+    	
+    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+    if (!ret) {
+        printk(KERN_ERR "cannot access user space memory\n");
+        return -11;
+    }
+
+	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+     if (kdata == 0)
+    	return -12;
+    	
+     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+     if (ret) {
+        printk(KERN_ERR "copy_from_user fail\n");
+        kfree(kdata);
+        return -14;
+     }    
+#if 0
+    PrintBuffer(0, count, kdata);
+#endif
+	 cmd = kdata[6];
+	 /* for making sure AP communicates with SiS driver */
+    if(cmd == 0xa2)
+    {
+		kdata[0] = 5;
+		kdata[1] = 0;
+		kdata[3] = 'S';
+		kdata[4] = 'i';
+		kdata[5] = 'S';
+		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+		{
+			printk(KERN_ERR "copy_to_user fail\n" );
+			kfree( kdata );
+			return -19;
+		}
+
+		kfree( kdata );
+		return 3;	
+	}
+/* Write & Read */
+    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+    if (ret < 0) {
+        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return -21;
+	}
+
+	ret = kdata[0] | (kdata[1] << 8);
+
+    printk(KERN_INFO "%d\n", ret);
+
+    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
+    {
+        printk("%02x ", kdata[i]);
+    }
+
+    printk( "\n" );
+
+    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
+    {
+        printk(KERN_ERR "copy_to_user fail\n" );
+        ret = -19;
+    }
+
+    kfree( kdata );
+
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp) {
+	printk(KERN_INFO "sis_cdev_open.\n");
+	if ( ts_bak == 0 )
+    	return -13;
+
+	msleep(200);
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == 
+IRQ_STATUS_ENABLED) #else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
+#endif	
+		{
+			disable_irq(ts_bak->client->irq);
+		}
+		else
+		{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: 
+%x\n",(ts_bak->desc->status & IRQ_DISABLED)); #else
+			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
+#endif	
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   
+    
+    msleep(200);
+
+	return 0; /* success */
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp) {
+	printk(KERN_INFO "sis_cdev_release.\n");
+	
+	msleep(200);
+	
+    if (ts_bak == 0)
+    	return -13;
+
+	if (ts_bak->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+        if ((ts_bak->desc->status & IRQ_DISABLED) == 
+IRQ_STATUS_DISABLED) #else
+		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
+#endif	
+		{
+			enable_irq(ts_bak->client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+    return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts) {
+	
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int alloc_ret = 0;
+	int cdev_err = 0;
+	int input_err = 0;
+	struct device *class_dev = NULL;
+	void *ptr_err;
+	
+	printk("sis_setup_chardev.\n");
+	
+	if (ts == NULL) 
+	{
+	  input_err = -ENOMEM;
+	  goto error;
+	} 
+	/* dynamic allocate driver handle */
+	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
+	if (alloc_ret)
+		goto error;
+		
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), 
+sis_char_devs_count);
+	
+	if (cdev_err) 
+		goto error;
+	
+	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, 
+sis_char_major);
+	
+	/* register class */
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+	
+	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 
+0), NULL, DEVICE_NAME);
+	
+	if(IS_ERR(ptr_err = class_dev)) 
+	{
+		goto err;
+	}
+	
+	return 0;
+error:
+	if (cdev_err == 0)
+		cdev_del(&sis_char_cdev);
+	if (alloc_ret == 0)
+		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
+	if(input_err != 0)
+	{
+		printk("sis_ts_bak error!\n");
+	}
+err:
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+err2:
+	class_destroy(sis_char_class);
+	return -1;
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id) {
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+    printk(KERN_INFO "sis_ts_probe\n");
+
+    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+    if (TPInfo == NULL) 
+    {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) 
+	{
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	ts_bak = ts;
+
+	mutex_init(&ts->mutex_wq);
+	
+	/* 1. Init Work queue and necessary buffers */
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+    pdata = client->dev.platform_data;
+
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) 
+	{
+		ret = ts->power(1);
+		if (ret < 0) 
+		{
+			printk(KERN_ERR "sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+
+	/* 2. Allocate input device */
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) 
+	{
+		ret = -ENOMEM;
+		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+
+	/* This input device name should be the same to IDC file name. */
+	ts->input_dev->name = "sis_touch";
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+
+#ifdef _ANDROID_4
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
+#else
+    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
+    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, 
+AREA_LENGTH_SHORT, 0, 0); #endif
+
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 
+ 0);
+	
+    /* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+
+	/* 3. Register input device to core */
+	ret = input_register_device(ts->input_dev);
+
+	if (ret) 
+	{
+		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	
+	/* 4. irq or timer setup */
+	ret = initial_irq();
+	if (ret < 0) 
+	{
+
+	}
+	else
+	{
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0) 
+		{
+		   ts->use_irq = 1;
+		}
+		else 
+		{
+			dev_err(&client->dev, "request_irq failed\n");
+		}
+	}
+
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+
+	if (!ts->use_irq) 
+	{
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", 
+ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+	
+	if (ts->use_irq)
+	{
+#ifdef _INT_MODE_1
+		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n"); #else
+		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n"); #endif
+	}
+	
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if(ret)
+	{
+		printk( KERN_INFO"sis_setup_chardev fail\n");
+	}
+#endif
+
+	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+
+	return 0;
+
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client) {
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+	
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg) 
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED) #else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_ENABLED) #endif
+		{
+			disable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_cancel(&ts->timer);
+	/* only flush sis_wq */
+	flush_workqueue(sis_wq); 	   		
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_suspend power off failed\n");
+	}
+	
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client) {
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power)
+	{
+		ret = ts->power(1);
+		if (ret < 0)
+			printk(KERN_ERR "sis_ts_resume power on failed\n");
+	}
+
+	if (ts->use_irq)
+	{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED) #else
+		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == 
+IRQ_STATUS_DISABLED) #endif
+		{
+			enable_irq(client->irq);
+		}
+	}
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h) {
+	struct sis_ts_data *ts;
+	
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND); }
+
+static void sis_ts_late_resume(struct early_suspend *h) {
+	struct sis_ts_data *ts;
+	
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+    .class      = I2C_CLASS_HWMON,
+    .detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __init sis_ts_init(void)
+{
+	printk( KERN_INFO "sis_ts_init\n" );
+	
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+		
+	return i2c_add_driver(&sis_ts_driver); }
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */ static int 
+sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+	
+    printk(KERN_INFO "sis_ts_detect\n");
+	
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	
+	return 0;
+}
+#endif
+
+static void __exit sis_ts_exit(void)
+{
+#ifdef _STD_RW_IO
+	dev_t dev;
+#endif
+
+	printk(KERN_INFO "sis_ts_exit\n");
+	
+	i2c_del_driver(&sis_ts_driver);
+	
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+
+#ifdef _STD_RW_IO
+	dev = MKDEV(sis_char_major, 0);
+	cdev_del(&sis_char_cdev);
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
+	class_destroy(sis_char_class);
+#endif
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver"); 
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..c1d65c4
--- /dev/null
+++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,215 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 
+family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2015/01/15
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+#define TIMER_NS    					10000000 //10ms
+#define MAX_FINGERS						10
+
+
+/* For Android 4.0 							*/
+/* Only for Linux kernel 2.6.34 and later 	*/
+#define _ANDROID_4					//  ON/OFF
+
+/* For standard R/W IO*/
+#define _STD_RW_IO						//  ON/OFF
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					//  ON/OFF
+#define GPIO_IRQ 						133
+
+/*  Enable if use interrupt case 1 mode.  */
+/* 	Disable if use interrupt case 2 mode. */
+//#define _INT_MODE_1					//	ON/OFF
+
+/* IRQ STATUS */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
+#define IRQ_STATUS_DISABLED				0x200  
+#else
+#define IRQ_STATUS_DISABLED				(1<<16)
+#endif
+#define IRQ_STATUS_ENABLED				0x0
+
+/* Resolution mode */
+// Constant value 
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE  					8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE       		0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID	                		0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+#ifdef _ANDROID_4
+#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
+#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
+#define AREA_UNIT						(5792/32)
+#else
+#define AREA_LENGTH_LONGER				31
+#define AREA_LENGTH_SHORT				31
+#endif
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0 
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					(x & 0x6)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+//#define _DEBUG_PACKAGE				//  ON/OFF
+//#define _DEBUG_REPORT					//  ON/OFF
+#define NORMAL_LEN_PER_POINT			6
+#define AREA_LEN_PER_POINT				2
+#define PRESSURE_LEN_PER_POINT			1
+
+//#define _CHECK_CRC					//  ON/OFF
+//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+static const unsigned short crc16tab[256]= {
+		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;   	// uint16_t ?
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;	
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t 
+mesg); static int sis_ts_resume(struct i2c_client *client);
+
+#endif /* _LINUX_SIS_I2C_H */

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
  2015-01-16 10:59         ` 曾婷葳 (tammy_tseng)
@ 2015-01-16 13:11           ` Oliver Neukum
  -1 siblings, 0 replies; 21+ messages in thread
From: Oliver Neukum @ 2015-01-16 13:11 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: linux-kernel, linux-input, tammy0524

On Fri, 2015-01-16 at 18:59 +0800, 曾婷葳 (tammy_tseng) wrote:
> Hey, Oliver
> 
> On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
> On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > > (Skip the code diff...)
> > 
> > Again macros for endianness
> > 
> > And the driver has a great number of conditional compilations are they 
> > really needed? The driver as is has a number of issues and is hard to 
> > review due to the use of "//" for comments and a lot of conditional 
> > compilation and unnecessary variables used for constants. Could you 
> > fix this up and resubmit?
> 
> Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
> Please help check them if anything needs to fix.

Hi,

I started from the lower end. I hope you find my comments
useful. A few general points need to be made before the
code is ready for review (it is obviously not ready for
inclusion)

1. We don't do conditional compilation unless we absolutely have
to in the kernel. The support for earlier kernel versions has
to be ripped out of the code.

2. You must use the symbolic names of error codes. They are not
guaranteed to be uniform among architectures.

3. If you need to sleep at places without obvious need, you need
to include comments explaining the reason.

4. No comments with "//"

Please redo these things and resubmit.

	Regards
		Oliver

> +/* for get system time */
> +static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
> +{
> +	 int ret = 0;
> +	 char *kdata;
> +	 char cmd;
> +	 int i;
> +	 
> +	 printk(KERN_INFO "sis_cdev_read.\n");
> +	 
> +	 if (ts_bak == 0)
> +    	return -13;
symbolic name necessary

> +    	
> +    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +    if (!ret) {
> +        printk(KERN_ERR "cannot access user space memory\n");
> +        return -11;
symbolic name necessary
> +    }
> +
> +	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +     if (kdata == 0)
> +    	return -12;
symbolic name necessary
> +    	
> +     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +     if (ret) {
> +        printk(KERN_ERR "copy_from_user fail\n");
> +        kfree(kdata);
> +        return -14;
symbolic name necessary
> +     }    
> +#if 0
> +    PrintBuffer(0, count, kdata);
> +#endif
> +	 cmd = kdata[6];
> +	 /* for making sure AP communicates with SiS driver */
> +    if(cmd == 0xa2)
> +    {
> +		kdata[0] = 5;
> +		kdata[1] = 0;
> +		kdata[3] = 'S';
> +		kdata[4] = 'i';
> +		kdata[5] = 'S';
> +		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
What is happening here?
> +		{
> +			printk(KERN_ERR "copy_to_user fail\n" );
> +			kfree( kdata );
> +			return -19;
symbolic name needed
> +		}
> +
> +		kfree( kdata );
> +		return 3;
Why?
> 	
> +	}
> +/* Write & Read */
> +    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +    if (ret < 0) {
> +        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return -21;
symbolic name needed
> +	}
> +
> +	ret = kdata[0] | (kdata[1] << 8);
Use the macros endianness conversion.

In this case
ret = le16_to_cpu(kdata + 0);

> +    printk(KERN_INFO "%d\n", ret);
> +
> +    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
> +    {
> +        printk("%02x ", kdata[i]);
> +    }
> +
> +    printk( "\n" );
> +
> +    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +    {
> +        printk(KERN_ERR "copy_to_user fail\n" );
> +        ret = -19;
What is this to mean? I suppose it is an error code. The symbolic
values must be used.
> +    }
> +
> +    kfree( kdata );
> +
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_open.\n");
> +	if ( ts_bak == 0 )
> +    	return -13;

What is this to mean?
> +
> +	msleep(200);

Why?
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif	
> +		{
> +			disable_irq(ts_bak->client->irq);
> +		}
> +		else
> +		{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
> +#else
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
> +#endif	
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   
> +    
> +    msleep(200);
Why?

> +
> +	return 0; /* success */
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_release.\n");
> +	
> +	msleep(200);
Why?
> +	
> +    if (ts_bak == 0)
> +    	return -13;

What is this to mean?
> +
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif	
> +		{
> +			enable_irq(ts_bak->client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +    return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int alloc_ret = 0;
> +	int cdev_err = 0;
> +	int input_err = 0;
> +	struct device *class_dev = NULL;
> +	void *ptr_err;
> +	
> +	printk("sis_setup_chardev.\n");
> +	
> +	if (ts == NULL) 
> +	{
> +	  input_err = -ENOMEM;
> +	  goto error;
> +	} 
> +	/* dynamic allocate driver handle */
> +	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
> +	if (alloc_ret)
> +		goto error;
> +		
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	
> +	if (cdev_err) 
> +		goto error;
> +	
> +	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
> +	
> +	/* register class */
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if(IS_ERR(ptr_err = sis_char_class)) 
> +	{
> +		goto err2;
> +	}
> +	
> +	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
> +	
> +	if(IS_ERR(ptr_err = class_dev)) 
> +	{
> +		goto err;
> +	}
> +	
> +	return 0;
> +error:
> +	if (cdev_err == 0)
> +		cdev_del(&sis_char_cdev);
> +	if (alloc_ret == 0)
> +		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	if(input_err != 0)
> +	{
> +		printk("sis_ts_bak error!\n");
> +	}
> +err:
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +err2:
> +	class_destroy(sis_char_class);
> +	return -1;
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +    printk(KERN_INFO "sis_ts_probe\n");
> +
> +    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +    if (TPInfo == NULL) 
> +    {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts_bak = ts;
> +
> +	mutex_init(&ts->mutex_wq);
> +	
> +	/* 1. Init Work queue and necessary buffers */
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +    pdata = client->dev.platform_data;
> +
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) 
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0) 
> +		{
> +			printk(KERN_ERR "sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +
> +	/* 2. Allocate input device */
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +
> +	/* This input device name should be the same to IDC file name. */
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +
> +#ifdef _ANDROID_4
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
> +#else
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
> +#endif
> +
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
> +	
> +    /* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +
> +	/* 3. Register input device to core */
> +	ret = input_register_device(ts->input_dev);
> +
> +	if (ret) 
> +	{
> +		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	
> +	/* 4. irq or timer setup */
> +	ret = initial_irq();
> +	if (ret < 0) 
> +	{
> +
> +	}
> +	else
> +	{
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0) 
> +		{
> +		   ts->use_irq = 1;
> +		}
> +		else 
> +		{
> +			dev_err(&client->dev, "request_irq failed\n");
> +		}
> +	}
> +
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +
> +	if (!ts->use_irq) 
> +	{
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
> +	
> +	if (ts->use_irq)
> +	{
> +#ifdef _INT_MODE_1
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +	
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if(ret)
> +	{
> +		printk( KERN_INFO"sis_setup_chardev fail\n");
> +	}
> +#endif
> +
> +	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +
> +	return 0;
> +
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);
> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +	
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif
> +		{
> +			disable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   		
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_suspend power off failed\n");
> +	}
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power)
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +		{
> +			enable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +	return 0;
> +}
> +

> +
> +static void __exit sis_ts_exit(void)
> +{
> +#ifdef _STD_RW_IO
> +	dev_t dev;
> +#endif
> +
> +	printk(KERN_INFO "sis_ts_exit\n");
> +	
> +	i2c_del_driver(&sis_ts_driver);
> +	
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +
> +#ifdef _STD_RW_IO

Make up your mind what you want to support

> +	dev = MKDEV(sis_char_major, 0);
> +	cdev_del(&sis_char_cdev);
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +	class_destroy(sis_char_class);
> +#endif
> +}

> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +#define TIMER_NS    					10000000 //10ms
> +#define MAX_FINGERS						10
> +
> +
> +/* For Android 4.0 							*/
> +/* Only for Linux kernel 2.6.34 and later 	*/
> +#define _ANDROID_4					//  ON/OFF

You are submitting for a defined kernel version. This needs to
go away.

> +
> +/* For standard R/W IO*/
> +#define _STD_RW_IO						//  ON/OFF
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					//  ON/OFF
> +#define GPIO_IRQ 						133
> +
> +/*  Enable if use interrupt case 1 mode.  */
> +/* 	Disable if use interrupt case 2 mode. */
> +//#define _INT_MODE_1					//	ON/OFF
> +
> +/* IRQ STATUS */
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )

You are submitting for a defined kernel version. This needs to
go away.

> +#define IRQ_STATUS_DISABLED				0x200  
> +#else
> +#define IRQ_STATUS_DISABLED				(1<<16)
> +#endif
> +#define IRQ_STATUS_ENABLED				0x0
> +

[..]
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +static const unsigned short crc16tab[256]= {

What polynom is used for this? I am asking because the usual
polynom has a common table in the kernel. It may be good to share
this table more widely.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-16 13:11           ` Oliver Neukum
  0 siblings, 0 replies; 21+ messages in thread
From: Oliver Neukum @ 2015-01-16 13:11 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: linux-kernel, linux-input, tammy0524

On Fri, 2015-01-16 at 18:59 +0800, 曾婷葳 (tammy_tseng) wrote:
> Hey, Oliver
> 
> On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
> On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > > (Skip the code diff...)
> > 
> > Again macros for endianness
> > 
> > And the driver has a great number of conditional compilations are they 
> > really needed? The driver as is has a number of issues and is hard to 
> > review due to the use of "//" for comments and a lot of conditional 
> > compilation and unnecessary variables used for constants. Could you 
> > fix this up and resubmit?
> 
> Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
> Please help check them if anything needs to fix.

Hi,

I started from the lower end. I hope you find my comments
useful. A few general points need to be made before the
code is ready for review (it is obviously not ready for
inclusion)

1. We don't do conditional compilation unless we absolutely have
to in the kernel. The support for earlier kernel versions has
to be ripped out of the code.

2. You must use the symbolic names of error codes. They are not
guaranteed to be uniform among architectures.

3. If you need to sleep at places without obvious need, you need
to include comments explaining the reason.

4. No comments with "//"

Please redo these things and resubmit.

	Regards
		Oliver

> +/* for get system time */
> +static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
> +{
> +	 int ret = 0;
> +	 char *kdata;
> +	 char cmd;
> +	 int i;
> +	 
> +	 printk(KERN_INFO "sis_cdev_read.\n");
> +	 
> +	 if (ts_bak == 0)
> +    	return -13;
symbolic name necessary

> +    	
> +    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +    if (!ret) {
> +        printk(KERN_ERR "cannot access user space memory\n");
> +        return -11;
symbolic name necessary
> +    }
> +
> +	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +     if (kdata == 0)
> +    	return -12;
symbolic name necessary
> +    	
> +     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +     if (ret) {
> +        printk(KERN_ERR "copy_from_user fail\n");
> +        kfree(kdata);
> +        return -14;
symbolic name necessary
> +     }    
> +#if 0
> +    PrintBuffer(0, count, kdata);
> +#endif
> +	 cmd = kdata[6];
> +	 /* for making sure AP communicates with SiS driver */
> +    if(cmd == 0xa2)
> +    {
> +		kdata[0] = 5;
> +		kdata[1] = 0;
> +		kdata[3] = 'S';
> +		kdata[4] = 'i';
> +		kdata[5] = 'S';
> +		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
What is happening here?
> +		{
> +			printk(KERN_ERR "copy_to_user fail\n" );
> +			kfree( kdata );
> +			return -19;
symbolic name needed
> +		}
> +
> +		kfree( kdata );
> +		return 3;
Why?
> 	
> +	}
> +/* Write & Read */
> +    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +    if (ret < 0) {
> +        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return -21;
symbolic name needed
> +	}
> +
> +	ret = kdata[0] | (kdata[1] << 8);
Use the macros endianness conversion.

In this case
ret = le16_to_cpu(kdata + 0);

> +    printk(KERN_INFO "%d\n", ret);
> +
> +    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
> +    {
> +        printk("%02x ", kdata[i]);
> +    }
> +
> +    printk( "\n" );
> +
> +    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +    {
> +        printk(KERN_ERR "copy_to_user fail\n" );
> +        ret = -19;
What is this to mean? I suppose it is an error code. The symbolic
values must be used.
> +    }
> +
> +    kfree( kdata );
> +
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_open.\n");
> +	if ( ts_bak == 0 )
> +    	return -13;

What is this to mean?
> +
> +	msleep(200);

Why?
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif	
> +		{
> +			disable_irq(ts_bak->client->irq);
> +		}
> +		else
> +		{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
> +#else
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
> +#endif	
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   
> +    
> +    msleep(200);
Why?

> +
> +	return 0; /* success */
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_release.\n");
> +	
> +	msleep(200);
Why?
> +	
> +    if (ts_bak == 0)
> +    	return -13;

What is this to mean?
> +
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif	
> +		{
> +			enable_irq(ts_bak->client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +    return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int alloc_ret = 0;
> +	int cdev_err = 0;
> +	int input_err = 0;
> +	struct device *class_dev = NULL;
> +	void *ptr_err;
> +	
> +	printk("sis_setup_chardev.\n");
> +	
> +	if (ts == NULL) 
> +	{
> +	  input_err = -ENOMEM;
> +	  goto error;
> +	} 
> +	/* dynamic allocate driver handle */
> +	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
> +	if (alloc_ret)
> +		goto error;
> +		
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	
> +	if (cdev_err) 
> +		goto error;
> +	
> +	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
> +	
> +	/* register class */
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if(IS_ERR(ptr_err = sis_char_class)) 
> +	{
> +		goto err2;
> +	}
> +	
> +	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
> +	
> +	if(IS_ERR(ptr_err = class_dev)) 
> +	{
> +		goto err;
> +	}
> +	
> +	return 0;
> +error:
> +	if (cdev_err == 0)
> +		cdev_del(&sis_char_cdev);
> +	if (alloc_ret == 0)
> +		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	if(input_err != 0)
> +	{
> +		printk("sis_ts_bak error!\n");
> +	}
> +err:
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +err2:
> +	class_destroy(sis_char_class);
> +	return -1;
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +    printk(KERN_INFO "sis_ts_probe\n");
> +
> +    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +    if (TPInfo == NULL) 
> +    {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts_bak = ts;
> +
> +	mutex_init(&ts->mutex_wq);
> +	
> +	/* 1. Init Work queue and necessary buffers */
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +    pdata = client->dev.platform_data;
> +
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) 
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0) 
> +		{
> +			printk(KERN_ERR "sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +
> +	/* 2. Allocate input device */
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +
> +	/* This input device name should be the same to IDC file name. */
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +
> +#ifdef _ANDROID_4
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
> +#else
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
> +#endif
> +
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
> +	
> +    /* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +
> +	/* 3. Register input device to core */
> +	ret = input_register_device(ts->input_dev);
> +
> +	if (ret) 
> +	{
> +		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	
> +	/* 4. irq or timer setup */
> +	ret = initial_irq();
> +	if (ret < 0) 
> +	{
> +
> +	}
> +	else
> +	{
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0) 
> +		{
> +		   ts->use_irq = 1;
> +		}
> +		else 
> +		{
> +			dev_err(&client->dev, "request_irq failed\n");
> +		}
> +	}
> +
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +
> +	if (!ts->use_irq) 
> +	{
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
> +	
> +	if (ts->use_irq)
> +	{
> +#ifdef _INT_MODE_1
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +	
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if(ret)
> +	{
> +		printk( KERN_INFO"sis_setup_chardev fail\n");
> +	}
> +#endif
> +
> +	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +
> +	return 0;
> +
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);
> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +	
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif
> +		{
> +			disable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   		
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_suspend power off failed\n");
> +	}
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power)
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
You are submitting for a defined kernel version. This needs to
go away.
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +		{
> +			enable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +	return 0;
> +}
> +

> +
> +static void __exit sis_ts_exit(void)
> +{
> +#ifdef _STD_RW_IO
> +	dev_t dev;
> +#endif
> +
> +	printk(KERN_INFO "sis_ts_exit\n");
> +	
> +	i2c_del_driver(&sis_ts_driver);
> +	
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +
> +#ifdef _STD_RW_IO

Make up your mind what you want to support

> +	dev = MKDEV(sis_char_major, 0);
> +	cdev_del(&sis_char_cdev);
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +	class_destroy(sis_char_class);
> +#endif
> +}

> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +#define TIMER_NS    					10000000 //10ms
> +#define MAX_FINGERS						10
> +
> +
> +/* For Android 4.0 							*/
> +/* Only for Linux kernel 2.6.34 and later 	*/
> +#define _ANDROID_4					//  ON/OFF

You are submitting for a defined kernel version. This needs to
go away.

> +
> +/* For standard R/W IO*/
> +#define _STD_RW_IO						//  ON/OFF
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					//  ON/OFF
> +#define GPIO_IRQ 						133
> +
> +/*  Enable if use interrupt case 1 mode.  */
> +/* 	Disable if use interrupt case 2 mode. */
> +//#define _INT_MODE_1					//	ON/OFF
> +
> +/* IRQ STATUS */
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )

You are submitting for a defined kernel version. This needs to
go away.

> +#define IRQ_STATUS_DISABLED				0x200  
> +#else
> +#define IRQ_STATUS_DISABLED				(1<<16)
> +#endif
> +#define IRQ_STATUS_ENABLED				0x0
> +

[..]
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +static const unsigned short crc16tab[256]= {

What polynom is used for this? I am asking because the usual
polynom has a common table in the kernel. It may be good to share
this table more widely.



--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
  2015-01-16 13:11           ` Oliver Neukum
@ 2015-01-17  0:04             ` Dmitry Torokhov
  -1 siblings, 0 replies; 21+ messages in thread
From: Dmitry Torokhov @ 2015-01-17  0:04 UTC (permalink / raw)
  To: Oliver Neukum
  Cc: 曾婷葳 (tammy_tseng), lkml, linux-input, tammy0524

On Fri, Jan 16, 2015 at 5:11 AM, Oliver Neukum <oneukum@suse.de> wrote:
> On Fri, 2015-01-16 at 18:59 +0800, 曾婷葳 (tammy_tseng) wrote:
>> Hey, Oliver
>>
>> On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
>> On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
>> > > (Skip the code diff...)
>> >
>> > Again macros for endianness
>> >
>> > And the driver has a great number of conditional compilations are they
>> > really needed? The driver as is has a number of issues and is hard to
>> > review due to the use of "//" for comments and a lot of conditional
>> > compilation and unnecessary variables used for constants. Could you
>> > fix this up and resubmit?
>>
>> Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
>> Please help check them if anything needs to fix.
>
> Hi,
>
> I started from the lower end. I hope you find my comments
> useful. A few general points need to be made before the
> code is ready for review (it is obviously not ready for
> inclusion)

Also:

- it was sent as base64 so it can't be applied using normal tools
- it has DOS line endings
- even after decoding it does not apply
- dtor@dtor-ws:~/kernel/work$ ./scripts/checkpatch.pl --no-signoff
sis-decoded.patch
...
total: 677 errors, 355 warnings, 1479 lines checked

Please make sure your code at least conforms to the kernel coding
style before resubmitting.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-17  0:04             ` Dmitry Torokhov
  0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Torokhov @ 2015-01-17  0:04 UTC (permalink / raw)
  To: Oliver Neukum
  Cc: 曾婷葳 (tammy_tseng), lkml, linux-input, tammy0524

On Fri, Jan 16, 2015 at 5:11 AM, Oliver Neukum <oneukum@suse.de> wrote:
> On Fri, 2015-01-16 at 18:59 +0800, 曾婷葳 (tammy_tseng) wrote:
>> Hey, Oliver
>>
>> On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
>> On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
>> > > (Skip the code diff...)
>> >
>> > Again macros for endianness
>> >
>> > And the driver has a great number of conditional compilations are they
>> > really needed? The driver as is has a number of issues and is hard to
>> > review due to the use of "//" for comments and a lot of conditional
>> > compilation and unnecessary variables used for constants. Could you
>> > fix this up and resubmit?
>>
>> Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
>> Please help check them if anything needs to fix.
>
> Hi,
>
> I started from the lower end. I hope you find my comments
> useful. A few general points need to be made before the
> code is ready for review (it is obviously not ready for
> inclusion)

Also:

- it was sent as base64 so it can't be applied using normal tools
- it has DOS line endings
- even after decoding it does not apply
- dtor@dtor-ws:~/kernel/work$ ./scripts/checkpatch.pl --no-signoff
sis-decoded.patch
...
total: 677 errors, 355 warnings, 1479 lines checked

Please make sure your code at least conforms to the kernel coding
style before resubmitting.

Thanks.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
  2015-01-17  0:04             ` Dmitry Torokhov
@ 2015-02-12  6:07               ` 曾婷葳 (tammy_tseng)
  -1 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-02-12  6:07 UTC (permalink / raw)
  To: Dmitry Torokhov, Oliver Neukum; +Cc: lkml, linux-input, tammy0524

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="UTF-8", Size: 36257 bytes --]

Hi, 

I've checked the coding style and modified the i2c and hid touch driver for sis touch controller.
Please help review them. 
Thanks a lot.

Tammy
-----
Here is the sis i2c driver in input:

linux-3.18.5/drivers/input/touchscreen/Kconfig   |    7 +
 linux-3.18.5/drivers/input/touchscreen/Makefile  |    1 +
 linux-3.18.5/drivers/input/touchscreen/sis_i2c.c | 1032 ++++++++++++++++++++++
 linux-3.18.5/drivers/input/touchscreen/sis_i2c.h |  173 ++++
 4 files changed, 1213 insertions(+)


-----
diff --git a/linux-3.18.5/drivers/input/touchscreen/Kconfig b/linux-3.18.5/drivers/input/touchscreen/Kconfig
index e1d8003..5093ccc 100644
--- a/linux-3.18.5/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.5/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,11 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default n
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
 endif
diff --git a/linux-3.18.5/drivers/input/touchscreen/Makefile b/linux-3.18.5/drivers/input/touchscreen/Makefile
index 090e61c..25cfd9f 100644
--- a/linux-3.18.5/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.5/drivers/input/touchscreen/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..260a7b6
--- /dev/null
+++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1032 @@
+/* drivers/input/touchscreen/sis_i2c.c
+ *  - I2C Touch panel driver for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static const int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class;
+#endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
+static struct workqueue_struct *sis_wq;
+struct sis_ts_data *ts_bak;
+struct sisTP_driver_data *TPInfo;
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h);
+static void sis_ts_late_resume(struct early_suspend *h);
+#endif
+
+#ifdef _CHECK_CRC
+static const unsigned short crc16tab[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+static uint16_t cal_crc(char *cmd, int start, int end)
+{
+	int i = 0;
+	uint16_t crc = 0;
+
+	for (i = start; i <= end ; i++)
+		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd[i]) & 0x00FF];
+	return crc;
+}
+#endif
+
+#ifdef _DEBUG_PACKAGE
+static void PrintBuffer(int start, int length, char *buf)
+{
+	int i;
+
+	for (i = start; i < length; i++) {
+		pr_info("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			pr_info("\n");
+	}
+	pr_info("\n");
+}
+#endif
+
+static int sis_command_for_write(struct i2c_client *client, int wlength,
+							unsigned char *wdata)
+{
+	int ret = SIS_ERR;
+	struct i2c_msg msg;
+
+	msg.addr = client->addr;
+	msg.flags = 0; /*Write*/
+	msg.len = wlength;
+	msg.buf = (unsigned char *)wdata;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	return ret;
+}
+
+static int sis_command_for_read(struct i2c_client *client, int rlength,
+							unsigned char *rdata)
+{
+	int ret = SIS_ERR;
+	struct i2c_msg msg;
+
+	msg.addr = client->addr;
+	msg.flags = I2C_M_RD; /*Read*/
+	msg.len = rlength;
+	msg.buf = rdata;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	return ret;
+}
+
+static int sis_cul_unit(uint8_t report_id)
+{
+	int ret = NORMAL_LEN_PER_POINT;
+
+	if (report_id != ALL_IN_ONE_PACKAGE) {
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+			ret += AREA_LEN_PER_POINT;
+		if (IS_PRESSURE(report_id))
+			ret += PRESSURE_LEN_PER_POINT;
+	}
+
+	return ret;
+}
+
+static int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t *buf)
+{
+	uint8_t tmpbuf[MAX_BYTE] = {0};	/*MAX_BYTE = 64;*/
+	int ret = SIS_ERR;
+	int touchnum = 0;
+	int p_count = 0;
+	int touc_formate_id = 0;
+	int locate = 0;
+	bool read_first = true;
+	/*
+	* New i2c format
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations;
+	* 1 touch point has 6 bytes, it could be none if no touch
+	* buf[touch num * 6 + 3] = Touch numbers
+	*
+	* One touch point information include 6 bytes, the order is
+	*
+	* 1. status = touch down or touch up
+	* 2. id = finger id
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	* */
+	do {
+		if (locate >= PACKET_BUFFER_SIZE) {
+			pr_err("sis_ReadPacket: Buf Overflow\n");
+			return SIS_ERR;
+		}
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+#ifdef _DEBUG_PACKAGE
+		pr_info("chaoban test: Buf_Data [0~63]\n");
+		PrintBuffer(0, 64, tmpbuf);
+#endif
+		if (ret < 0) {
+			pr_err("sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		/*error package length of receiving data*/
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE) {
+			pr_err("sis_ReadPacket: Error Bytecount\n");
+			return SIS_ERR;
+		}
+		if (read_first) {
+			/*access NO TOUCH event unless BUTTON NO TOUCH event*/
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+				return 0;	/*touchnum is 0*/
+		}
+		/*skip parsing data when two devices are registered
+		 * at the same slave address*/
+		/*parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT
+		 * or P_REPORT_ID is ALL_IN_ONE_PACKAGE*/
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT)
+		&& (touc_formate_id != HIDI2C_FORMAT)
+		&& (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)) {
+			pr_err("sis_ReadPacket: Error Report_ID\n");
+			return SIS_ERR;
+		}
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/*start from 0*/
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) {
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID])) {
+				p_count -= BYTE_CRC_I2C;/*delete 2 byte crc*/
+			} else if (IS_HIDI2C(tmpbuf[P_REPORT_ID])) {
+				p_count -= BYTE_CRC_HIDI2C;
+			} else {	/*should not be happen*/
+				pr_err("sis_ReadPacket: delete crc error\n");
+				return SIS_ERR;
+			}
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+				p_count -= BYTE_SCANTIME;
+		}
+		/*else {}*/ /*For ALL_IN_ONE_PACKAGE*/
+		if (read_first) {
+			touchnum = tmpbuf[p_count];
+		} else {
+			if (tmpbuf[p_count] != 0) {
+				pr_err("sis_ReadPacket: get error package\n");
+				return SIS_ERR;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		/* HID over I2C data foramt and no touch packet without CRC */
+		if ((touc_formate_id != HIDI2C_FORMAT) &&
+			(tmpbuf[P_BYTECOUNT] > 3)) {
+			int crc_end = p_count + (IS_SCANTIME(
+				tmpbuf[P_REPORT_ID]) * 2);
+			uint16_t buf_crc = cal_crc(
+				tmpbuf, 2, crc_end);/*sub bytecount(2 byte)*/
+			int l_package_crc = (IS_SCANTIME(
+				tmpbuf[P_REPORT_ID]) * 2) + p_count + 1;
+			uint16_t package_crc = le16_to_cpu(get_unaligned_le16(
+				&tmpbuf[l_package_crc]));
+
+			if (buf_crc != package_crc) {
+				pr_err("sis_ReadPacket: CRC Error\n");
+				return SIS_ERR;
+			}
+		}
+#endif
+		memcpy(&buf[locate], &tmpbuf[0], 64);
+		/*Buf_Data [0~63] [64~128]*/
+		locate += 64;
+		read_first = false;
+	} while (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE &&
+			tmpbuf[p_count] > 5);
+	return touchnum;
+}
+
+#ifdef _INT_MODE_1
+static void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
+{
+	int i = 0;
+	uint8_t diff_keybit_state = 0x0;
+	/*check keybit_state is difference with pre_keybit_state*/
+	uint8_t key_value = 0x0; /*button location for binary*/
+	uint8_t  key_pressed = 0x0; /*button is up or down*/
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts) {
+		pr_err("%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state) {
+		for (i = 0; i < BUTTON_KEY_COUNT; i++) {
+			if ((diff_keybit_state >> i) & 0x01) {
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value) {
+				case MSK_COMP:
+					input_report_key(ts->input_dev,
+						KEY_COMPOSE, key_pressed);
+					break;
+				case MSK_BACK:
+					input_report_key(ts->input_dev,
+						KEY_BACK, key_pressed);
+					break;
+				case MSK_MENU:
+					input_report_key(ts->input_dev,
+						KEY_MENU, key_pressed);
+					break;
+				case MSK_HOME:
+					input_report_key(ts->input_dev,
+						KEY_HOME, key_pressed);
+					break;
+				case MSK_NOBTN:
+					/*Release the button if it touched.*/
+				default:
+					break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+#endif
+
+static void sis_ts_work_func(struct work_struct *work)
+{
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+	int ret = SIS_ERR;
+	int point_unit;
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+	uint8_t p_preasure = 0;
+	bool all_touch_up = true;
+
+	mutex_lock(&ts->mutex_wq);
+    /* I2C or SMBUS block data read */
+	ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+	/*Error Number*/
+	if (ret < 0)
+		goto err_free_allocate;
+	/*access NO TOUCH event unless BUTTON NO TOUCH event*/
+	else if (ret == 0) {
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;
+		/*need to report input_mt_sync()*/
+	}
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+
+	/*Parser and Get the sis9200 data*/
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+
+	/*fingers 10 =  0 ~ 9*/
+	for (i = 0; i < fingers; i++) {
+		if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5)) {
+			/*Calc point status*/
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
+					+ ((i - 5) * point_unit);
+			pstatus += 64;
+		} else {
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
+					+ (i * point_unit);
+					/*Calc point status*/
+		}
+	    px = pstatus + 2;	/*Calc point x_coord*/
+	    py = px + 2;	/*Calc point y_coord*/
+		if ((buf[pstatus]) == TOUCHUP) {
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		} else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE
+					&& (buf[pstatus]) == TOUCHDOWN) {
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;
+		} else if ((buf[pstatus]) == TOUCHDOWN) {
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+			/*area*/
+			if (IS_AREA(buf[P_REPORT_ID])) {
+				TPInfo->pt[i].Width = buf[p_area];
+				TPInfo->pt[i].Height = buf[p_area + 1];
+			} else {
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			/*preasure*/
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else
+				TPInfo->pt[i].Pressure = 1;
+		} else {
+			pr_err("sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = le16_to_cpu(get_unaligned_le16(&buf[px]));
+		TPInfo->pt[i].y = le16_to_cpu(get_unaligned_le16(&buf[py]));
+	}
+
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+		pr_info("chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d\n",
+		i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y,
+		buf[pstatus], TPInfo->pt[i].Width, TPInfo->pt[i].Height,
+		TPInfo->pt[i].Pressure);
+#endif
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+	for (i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++) {
+		if (TPInfo->pt[i].Pressure) {
+			TPInfo->pt[i].Width *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR,
+							TPInfo->pt[i].Height);
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
+							TPInfo->pt[i].id);
+			/*Android 2.3*/
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		if (i == (TPInfo->fingers - 1) && all_touch_up == true)
+			input_mt_sync(ts->input_dev);
+	}
+	if (TPInfo->fingers == 0)
+		input_mt_sync(ts->input_dev);
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+	if (ts->use_irq) {
+#ifdef _INT_MODE_1	/*case 1 mode*/
+		/*TODO: After interrupt status low,
+		 * read i2c bus data by polling,
+		 * until interrupt status is high*/
+		ret =  gpio_get_value(GPIO_IRQ);
+		/*interrupt pin is still LOW,
+		 * read data until interrupt pin is released.*/
+		if (!ret)
+			hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS),
+						HRTIMER_MODE_REL);
+		else {
+			if (TPInfo->pre_keybit_state)
+				/*clear for interrupt*/
+				ts_report_key(ts->client, 0x0);
+
+			if (irqd_irq_disabled(&ts->desc->irq_data))
+				enable_irq(ts->client->irq);
+		}
+#else /*case 2 mode*/
+		if (irqd_irq_disabled(&ts->desc->irq_data))
+			enable_irq(ts->client->irq);
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
+{
+	int i = 0;
+
+	for (i = 0; i < max; i++) {
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
+{
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)	/*For Polling mode*/
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+	struct sis_ts_data *ts = dev_id;
+
+	if (!irqd_irq_disabled(&ts->desc->irq_data))
+		disable_irq_nosync(ts->client->irq);
+	queue_work(sis_wq, &ts->work);
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	/*ex. GPIO_133 for interrupt mode*/
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");
+	if (ret < 0) {
+		/*Set Active Low.
+		 * Please reference the file include/linux/interrupt.h*/
+		pr_err("sis_ts_probe: Failed to gpio_request\n");
+		pr_err("sis_ts_probe: Fail : gpio_request was called before this driver call\n");
+	}
+	/* setting gpio direction here OR boardinfo file*/
+
+#else
+	ret = SIS_ERR;
+#endif
+	return ret;
+}
+
+/*static uint16_t cal_crc_with_cmd(char *data, int start, int end, uint8_t cmd)
+{
+	int i = 0;
+	uint16_t crc = 0;
+
+	crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd) & 0x00FF];
+	for (i = start; i <= end ; i++)
+		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ data[i]) & 0x00FF];
+	return crc;
+}*/
+
+/*static void write_crc(unsigned char *buf, int start, int end)
+{
+	uint16_t crc = 0;
+
+	crc = cal_crc(buf, start , end);
+	buf[end+1] = (crc >> 8) & 0xff;
+	buf[end+2] = crc & 0xff;
+}*/
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
+								size_t count,
+								loff_t *f_pos)
+{
+	int ret = 0;
+	char *kdata;
+	char cmd;
+
+	pr_info("sis_cdev_write.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+
+	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+	if (!ret) {
+		pr_err("cannot access user space memory\n");
+		return SIS_ERR_ACCESS_USER_MEM;
+	}
+
+	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+	if (kdata == 0)
+		return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+	if (ret) {
+		pr_err("copy_from_user fail\n");
+		kfree(kdata);
+		return SIS_ERR_COPY_FROM_USER;
+	}
+#ifdef _DEBUG_PACKAGE
+	PrintBuffer(0, count, kdata);
+#endif
+
+	cmd = kdata[6];
+
+/*Write & Read*/
+	ret = sis_command_for_write(ts_bak->client, count, kdata);
+	if (ret < 0) {
+		pr_err("i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return SIS_ERR_TRANSMIT_I2C;
+	}
+	if (copy_to_user((char *) buf, kdata, BUFFER_SIZE)) {
+		pr_err("copy_to_user fail\n");
+		ret = SIS_ERR_COPY_FROM_KERNEL;
+	}
+	kfree(kdata);
+	return ret;
+}
+
+/*for get system time*/
+static ssize_t sis_cdev_read(struct file *file, char __user *buf,
+								size_t count,
+								loff_t *f_pos)
+{
+	int ret = 0;
+	char *kdata;
+
+	pr_info("sis_cdev_read.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+	if (!ret) {
+		pr_err("cannot access user space memory\n");
+		return SIS_ERR_ACCESS_USER_MEM;
+	}
+	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+	if (kdata == 0)
+		return SIS_ERR_ALLOCATE_KERNEL_MEM;
+	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+	if (ret) {
+		pr_err("copy_from_user fail\n");
+		kfree(kdata);
+		return SIS_ERR_COPY_FROM_USER;
+	}
+#ifdef _DEBUG_PACKAGE
+	PrintBuffer(0, count, kdata);
+#endif
+	/*Write & Read*/
+	ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+	if (ret < 0) {
+		pr_err("i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return SIS_ERR_TRANSMIT_I2C;
+	}
+
+	ret = le16_to_cpu(get_unaligned_le16(kdata));
+
+	/*{
+		int i;
+
+		pr_info("ret=%d\n", ret);
+		for (i = 0; i < ret && i < BUFFER_SIZE; i++)
+			pr_info("%02x ", kdata[i]);
+		pr_info("\n");
+	}*/
+
+	if (copy_to_user((char *)buf, kdata, BUFFER_SIZE)) {
+		pr_err("copy_to_user fail\n");
+		ret = SIS_ERR_COPY_FROM_KERNEL;
+	}
+
+	kfree(kdata);
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+	pr_info("sis_cdev_open.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+
+	if (ts_bak->use_irq) {
+		if (!irqd_irq_disabled(&ts_bak->desc->irq_data))
+			disable_irq(ts_bak->client->irq);
+		else {
+			pr_info("sis_cdev_open: IRQ_STATUS: %x\n",
+			irqd_irq_disabled(&ts_bak->desc->irq_data));
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+	flush_workqueue(sis_wq);		/*only flush sis_wq*/
+	return 0;	/*success*/
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	pr_info("sis_cdev_release.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+	if (ts_bak->use_irq) {
+		if (irqd_irq_disabled(&ts_bak->desc->irq_data))
+			enable_irq(ts_bak->client->irq);
+	} else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0),
+					HRTIMER_MODE_REL);
+	return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release	= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts)
+{
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int ret = 0;
+	struct device *class_dev = NULL;
+
+	pr_info("sis_setup_chardev.\n");
+	if (ts == NULL)
+		return -ENOMEM;
+
+	/*dynamic allocate driver handle*/
+	ret = alloc_chrdev_region(&dev, 0,
+				sis_char_devs_count, DEVICE_NAME);
+	if (ret)
+		return ret;
+
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	ret = cdev_add(&sis_char_cdev, dev, sis_char_devs_count);
+	if (ret)
+		goto err1;
+
+	pr_info("%s driver(major %d) installed.\n",
+			DEVICE_NAME, sis_char_major);
+	/*register class*/
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(sis_char_class)) {
+		ret = PTR_ERR(sis_char_class);
+		goto err2;
+	}
+
+	class_dev = device_create(sis_char_class, NULL, dev, NULL, DEVICE_NAME);
+	if (IS_ERR(class_dev)) {
+		ret = PTR_ERR(class_dev);
+		goto err3;
+	}
+
+	return 0;
+err3:
+	class_destroy(sis_char_class);
+	sis_char_class = NULL;
+err2:
+	cdev_del(&sis_char_cdev);
+	memset(&sis_char_cdev, 0, sizeof(struct cdev));
+err1:
+	sis_char_major = 0;
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	return ret;
+}
+
+static void sis_deinit_chardev(void)
+{
+	dev_t dev = MKDEV(sis_char_major, 0);
+
+	if (sis_char_class) {
+		pr_info("sis_deinit_chardev\n");
+		device_destroy(sis_char_class, dev);
+		class_destroy(sis_char_class);
+		sis_char_class = NULL;
+		cdev_del(&sis_char_cdev);
+		memset(&sis_char_cdev, 0, sizeof(struct cdev));
+		sis_char_major = 0;
+		unregister_chrdev_region(dev, sis_char_devs_count);
+	}
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+	pr_info("sis_ts_probe\n");
+	TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+	if (TPInfo == NULL) {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+	ts_bak = ts;
+	mutex_init(&ts->mutex_wq);
+	/*1. Init Work queue and necessary buffers*/
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	pdata = client->dev.platform_data;
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) {
+		ret = ts->power(1);
+		if (ret < 0) {
+			pr_err("sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+	/*2. Allocate input device*/
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		ret = -ENOMEM;
+		pr_err("sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+	/*This input device name should be the same to IDC file name.*/
+	ts->input_dev->name = "sis_touch";
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+	set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+	set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+	set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+	set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+	set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+	set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,
+						0, PRESSURE_MAX, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+						0, AREA_LENGTH_LONGER, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR,
+						0, AREA_LENGTH_SHORT, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+						0, SIS_MAX_X, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+						0, SIS_MAX_Y, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
+						0, 15, 0, 0);
+	/* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+	/*3. Register input device to core*/
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		pr_err("sis_ts_probe: Unable to register %s input device\n",
+				ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	/*4. irq or timer setup*/
+	ret = initial_irq();
+	if (ret >= 0) {
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler,
+					IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0)
+			ts->use_irq = 1;
+		else
+			dev_err(&client->dev, "request_irq failed\n");
+	}
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+	if (!ts->use_irq)
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	pr_info("sis_ts_probe: Start touchscreen %s in %s mode\n",
+			ts->input_dev->name,
+			ts->use_irq ? "interrupt" : "polling");
+	if (ts->use_irq) {
+#ifdef _INT_MODE_1
+		pr_info("sis_ts_probe: interrupt case 1 mode\n");
+#else
+		pr_info("sis_ts_probe: interrupt case 2 mode\n");
+#endif
+	}
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if (ret)
+		pr_err("sis_setup_chardev fail\n");
+#endif
+	pr_info("sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+	return 0;
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client)
+{
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+#ifdef _STD_RW_IO
+	sis_deinit_chardev();
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq) {
+		if (!irqd_irq_disabled(&ts->desc->irq_data))
+			disable_irq(client->irq);
+	} else
+		hrtimer_cancel(&ts->timer);
+	flush_workqueue(sis_wq);		/*only flush sis_wq*/
+
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			pr_err("sis_ts_suspend power off failed\n");
+	}
+
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power) {
+		ret = ts->power(1);
+		if (ret < 0)
+			pr_err("sis_ts_resume power on failed\n");
+	}
+
+	if (ts->use_irq) {
+		if (irqd_irq_disabled(&ts->desc->irq_data))
+			enable_irq(client->irq);
+	} else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void sis_ts_late_resume(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+
+	pr_info("sis_ts_detect\n");
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	return 0;
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+	.class		= I2C_CLASS_HWMON,
+	.detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __init sis_ts_init(void)
+{
+	pr_info("sis_ts_init\n");
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+	return i2c_add_driver(&sis_ts_driver);
+}
+
+static void __exit sis_ts_exit(void)
+{
+	pr_info("sis_ts_exit\n");
+	i2c_del_driver(&sis_ts_driver);
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..7639a52
--- /dev/null
+++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,173 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2015/01/15
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+/*10ms*/
+#define TIMER_NS						10000000
+#define MAX_FINGERS						10
+
+/* For standard R/W IO ( SiS firmware application )*/
+#define _STD_RW_IO						/*ON/OFF*/
+
+/* Check data CRC */
+/*#define _CHECK_CRC*/						/*ON/OFF*/
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					/*ON/OFF*/
+#define GPIO_IRQ						133
+
+/*	Enable if use interrupt case 1 mode.	*/
+/*	Disable if use interrupt case 2 mode.	*/
+/*#define _INT_MODE_1*/					/*ON/OFF*/
+
+/* Resolution mode */
+/*Constant value*/
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE						8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE				0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID							0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+/*Resolution diagonal */
+#define AREA_LENGTH_LONGER				5792
+/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
+#define AREA_LENGTH_SHORT				5792
+#define AREA_UNIT						(5792/32)
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					((x & 0xF) == 0x06)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+/*#define _DEBUG_PACKAGE*/				/*ON/OFF*/
+/*#define _DEBUG_REPORT*/				/*ON/OFF*/
+#define NORMAL_LEN_PER_POINT			6
+#define AREA_LEN_PER_POINT				2
+#define PRESSURE_LEN_PER_POINT			1
+
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+/* SiS i2c error code */
+#define SIS_ERR						-1
+#define SIS_ERR_ACCESS_USER_MEM		-11 /* Access user memory fail */
+#define SIS_ERR_ALLOCATE_KERNEL_MEM	-12 /* Allocate memory fail */
+#define SIS_ERR_CLIENT				-13 /* Client not created */
+#define SIS_ERR_COPY_FROM_USER		-14 /* Copy data from user fail */
+#define SIS_ERR_COPY_FROM_KERNEL	-19 /* Copy data from kernel fail */
+#define SIS_ERR_TRANSMIT_I2C		-21 /* Transmit error in I2C */
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;		/*uint16_t ?*/
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
+static int sis_ts_resume(struct i2c_client *client);
+
+#endif /* _LINUX_SIS_I2C_H */
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* RE: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-02-12  6:07               ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-02-12  6:07 UTC (permalink / raw)
  To: Dmitry Torokhov, Oliver Neukum; +Cc: lkml, linux-input, tammy0524

Hi, 

I've checked the coding style and modified the i2c and hid touch driver for sis touch controller.
Please help review them. 
Thanks a lot.

Tammy
-----
Here is the sis i2c driver in input:

linux-3.18.5/drivers/input/touchscreen/Kconfig   |    7 +
 linux-3.18.5/drivers/input/touchscreen/Makefile  |    1 +
 linux-3.18.5/drivers/input/touchscreen/sis_i2c.c | 1032 ++++++++++++++++++++++
 linux-3.18.5/drivers/input/touchscreen/sis_i2c.h |  173 ++++
 4 files changed, 1213 insertions(+)


-----
diff --git a/linux-3.18.5/drivers/input/touchscreen/Kconfig b/linux-3.18.5/drivers/input/touchscreen/Kconfig
index e1d8003..5093ccc 100644
--- a/linux-3.18.5/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.5/drivers/input/touchscreen/Kconfig
@@ -962,4 +962,11 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen driver"
+	depends on I2C
+	default n
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
 endif
diff --git a/linux-3.18.5/drivers/input/touchscreen/Makefile b/linux-3.18.5/drivers/input/touchscreen/Makefile
index 090e61c..25cfd9f 100644
--- a/linux-3.18.5/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.5/drivers/input/touchscreen/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..260a7b6
--- /dev/null
+++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,1032 @@
+/* drivers/input/touchscreen/sis_i2c.c
+ *  - I2C Touch panel driver for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "sis_i2c.h"
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+
+#ifdef _STD_RW_IO
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#define DEVICE_NAME "sis_aegis_touch_device"
+static const int sis_char_devs_count = 1;        /* device count */
+static int sis_char_major;
+static struct cdev sis_char_cdev;
+static struct class *sis_char_class;
+#endif
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
+static struct workqueue_struct *sis_wq;
+struct sis_ts_data *ts_bak;
+struct sisTP_driver_data *TPInfo;
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h);
+static void sis_ts_late_resume(struct early_suspend *h);
+#endif
+
+#ifdef _CHECK_CRC
+static const unsigned short crc16tab[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+static uint16_t cal_crc(char *cmd, int start, int end)
+{
+	int i = 0;
+	uint16_t crc = 0;
+
+	for (i = start; i <= end ; i++)
+		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd[i]) & 0x00FF];
+	return crc;
+}
+#endif
+
+#ifdef _DEBUG_PACKAGE
+static void PrintBuffer(int start, int length, char *buf)
+{
+	int i;
+
+	for (i = start; i < length; i++) {
+		pr_info("%02x ", buf[i]);
+		if (i != 0 && i % 30 == 0)
+			pr_info("\n");
+	}
+	pr_info("\n");
+}
+#endif
+
+static int sis_command_for_write(struct i2c_client *client, int wlength,
+							unsigned char *wdata)
+{
+	int ret = SIS_ERR;
+	struct i2c_msg msg;
+
+	msg.addr = client->addr;
+	msg.flags = 0; /*Write*/
+	msg.len = wlength;
+	msg.buf = (unsigned char *)wdata;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	return ret;
+}
+
+static int sis_command_for_read(struct i2c_client *client, int rlength,
+							unsigned char *rdata)
+{
+	int ret = SIS_ERR;
+	struct i2c_msg msg;
+
+	msg.addr = client->addr;
+	msg.flags = I2C_M_RD; /*Read*/
+	msg.len = rlength;
+	msg.buf = rdata;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	return ret;
+}
+
+static int sis_cul_unit(uint8_t report_id)
+{
+	int ret = NORMAL_LEN_PER_POINT;
+
+	if (report_id != ALL_IN_ONE_PACKAGE) {
+		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
+			ret += AREA_LEN_PER_POINT;
+		if (IS_PRESSURE(report_id))
+			ret += PRESSURE_LEN_PER_POINT;
+	}
+
+	return ret;
+}
+
+static int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t *buf)
+{
+	uint8_t tmpbuf[MAX_BYTE] = {0};	/*MAX_BYTE = 64;*/
+	int ret = SIS_ERR;
+	int touchnum = 0;
+	int p_count = 0;
+	int touc_formate_id = 0;
+	int locate = 0;
+	bool read_first = true;
+	/*
+	* New i2c format
+	* buf[0] = Low 8 bits of byte count value
+	* buf[1] = High 8 bits of byte counte value
+	* buf[2] = Report ID
+	* buf[touch num * 6 + 2 ] = Touch informations;
+	* 1 touch point has 6 bytes, it could be none if no touch
+	* buf[touch num * 6 + 3] = Touch numbers
+	*
+	* One touch point information include 6 bytes, the order is
+	*
+	* 1. status = touch down or touch up
+	* 2. id = finger id
+	* 3. x axis low 8 bits
+	* 4. x axis high 8 bits
+	* 5. y axis low 8 bits
+	* 6. y axis high 8 bits
+	* */
+	do {
+		if (locate >= PACKET_BUFFER_SIZE) {
+			pr_err("sis_ReadPacket: Buf Overflow\n");
+			return SIS_ERR;
+		}
+		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
+#ifdef _DEBUG_PACKAGE
+		pr_info("chaoban test: Buf_Data [0~63]\n");
+		PrintBuffer(0, 64, tmpbuf);
+#endif
+		if (ret < 0) {
+			pr_err("sis_ReadPacket: i2c transfer error\n");
+			return ret;
+		}
+		/*error package length of receiving data*/
+		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE) {
+			pr_err("sis_ReadPacket: Error Bytecount\n");
+			return SIS_ERR;
+		}
+		if (read_first) {
+			/*access NO TOUCH event unless BUTTON NO TOUCH event*/
+			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
+				return 0;	/*touchnum is 0*/
+		}
+		/*skip parsing data when two devices are registered
+		 * at the same slave address*/
+		/*parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT
+		 * or P_REPORT_ID is ALL_IN_ONE_PACKAGE*/
+		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
+		if ((touc_formate_id != TOUCH_FORMAT)
+		&& (touc_formate_id != HIDI2C_FORMAT)
+		&& (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)) {
+			pr_err("sis_ReadPacket: Error Report_ID\n");
+			return SIS_ERR;
+		}
+		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/*start from 0*/
+		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) {
+			if (IS_TOUCH(tmpbuf[P_REPORT_ID])) {
+				p_count -= BYTE_CRC_I2C;/*delete 2 byte crc*/
+			} else if (IS_HIDI2C(tmpbuf[P_REPORT_ID])) {
+				p_count -= BYTE_CRC_HIDI2C;
+			} else {	/*should not be happen*/
+				pr_err("sis_ReadPacket: delete crc error\n");
+				return SIS_ERR;
+			}
+			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
+				p_count -= BYTE_SCANTIME;
+		}
+		/*else {}*/ /*For ALL_IN_ONE_PACKAGE*/
+		if (read_first) {
+			touchnum = tmpbuf[p_count];
+		} else {
+			if (tmpbuf[p_count] != 0) {
+				pr_err("sis_ReadPacket: get error package\n");
+				return SIS_ERR;
+			}
+		}
+
+#ifdef _CHECK_CRC
+		/* HID over I2C data foramt and no touch packet without CRC */
+		if ((touc_formate_id != HIDI2C_FORMAT) &&
+			(tmpbuf[P_BYTECOUNT] > 3)) {
+			int crc_end = p_count + (IS_SCANTIME(
+				tmpbuf[P_REPORT_ID]) * 2);
+			uint16_t buf_crc = cal_crc(
+				tmpbuf, 2, crc_end);/*sub bytecount(2 byte)*/
+			int l_package_crc = (IS_SCANTIME(
+				tmpbuf[P_REPORT_ID]) * 2) + p_count + 1;
+			uint16_t package_crc = le16_to_cpu(get_unaligned_le16(
+				&tmpbuf[l_package_crc]));
+
+			if (buf_crc != package_crc) {
+				pr_err("sis_ReadPacket: CRC Error\n");
+				return SIS_ERR;
+			}
+		}
+#endif
+		memcpy(&buf[locate], &tmpbuf[0], 64);
+		/*Buf_Data [0~63] [64~128]*/
+		locate += 64;
+		read_first = false;
+	} while (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE &&
+			tmpbuf[p_count] > 5);
+	return touchnum;
+}
+
+#ifdef _INT_MODE_1
+static void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
+{
+	int i = 0;
+	uint8_t diff_keybit_state = 0x0;
+	/*check keybit_state is difference with pre_keybit_state*/
+	uint8_t key_value = 0x0; /*button location for binary*/
+	uint8_t  key_pressed = 0x0; /*button is up or down*/
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (!ts) {
+		pr_err("%s error: Missing Platform Data!\n", __func__);
+		return;
+	}
+
+	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
+
+	if (diff_keybit_state) {
+		for (i = 0; i < BUTTON_KEY_COUNT; i++) {
+			if ((diff_keybit_state >> i) & 0x01) {
+				key_value = diff_keybit_state & (0x01 << i);
+				key_pressed = (keybit_state >> i) & 0x01;
+				switch (key_value) {
+				case MSK_COMP:
+					input_report_key(ts->input_dev,
+						KEY_COMPOSE, key_pressed);
+					break;
+				case MSK_BACK:
+					input_report_key(ts->input_dev,
+						KEY_BACK, key_pressed);
+					break;
+				case MSK_MENU:
+					input_report_key(ts->input_dev,
+						KEY_MENU, key_pressed);
+					break;
+				case MSK_HOME:
+					input_report_key(ts->input_dev,
+						KEY_HOME, key_pressed);
+					break;
+				case MSK_NOBTN:
+					/*Release the button if it touched.*/
+				default:
+					break;
+				}
+			}
+		}
+		TPInfo->pre_keybit_state = keybit_state;
+	}
+}
+#endif
+
+static void sis_ts_work_func(struct work_struct *work)
+{
+	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
+	int ret = SIS_ERR;
+	int point_unit;
+	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
+	uint8_t i = 0, fingers = 0;
+	uint8_t px = 0, py = 0, pstatus = 0;
+	uint8_t p_area = 0;
+	uint8_t p_preasure = 0;
+	bool all_touch_up = true;
+
+	mutex_lock(&ts->mutex_wq);
+    /* I2C or SMBUS block data read */
+	ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
+	/*Error Number*/
+	if (ret < 0)
+		goto err_free_allocate;
+	/*access NO TOUCH event unless BUTTON NO TOUCH event*/
+	else if (ret == 0) {
+		fingers = 0;
+		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+		goto label_send_report;
+		/*need to report input_mt_sync()*/
+	}
+	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
+
+	/*Parser and Get the sis9200 data*/
+	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
+	fingers = ret;
+
+	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
+
+	/*fingers 10 =  0 ~ 9*/
+	for (i = 0; i < fingers; i++) {
+		if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5)) {
+			/*Calc point status*/
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
+					+ ((i - 5) * point_unit);
+			pstatus += 64;
+		} else {
+			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
+					+ (i * point_unit);
+					/*Calc point status*/
+		}
+	    px = pstatus + 2;	/*Calc point x_coord*/
+	    py = px + 2;	/*Calc point y_coord*/
+		if ((buf[pstatus]) == TOUCHUP) {
+			TPInfo->pt[i].Width = 0;
+			TPInfo->pt[i].Height = 0;
+			TPInfo->pt[i].Pressure = 0;
+		} else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE
+					&& (buf[pstatus]) == TOUCHDOWN) {
+			TPInfo->pt[i].Width = 1;
+			TPInfo->pt[i].Height = 1;
+			TPInfo->pt[i].Pressure = 1;
+		} else if ((buf[pstatus]) == TOUCHDOWN) {
+			p_area = py + 2;
+			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
+			/*area*/
+			if (IS_AREA(buf[P_REPORT_ID])) {
+				TPInfo->pt[i].Width = buf[p_area];
+				TPInfo->pt[i].Height = buf[p_area + 1];
+			} else {
+				TPInfo->pt[i].Width = 1;
+				TPInfo->pt[i].Height = 1;
+			}
+			/*preasure*/
+			if (IS_PRESSURE(buf[P_REPORT_ID]))
+				TPInfo->pt[i].Pressure = (buf[p_preasure]);
+			else
+				TPInfo->pt[i].Pressure = 1;
+		} else {
+			pr_err("sis_ts_work_func: Error Touch Status\n");
+			goto err_free_allocate;
+		}
+		TPInfo->pt[i].id = (buf[pstatus + 1]);
+		TPInfo->pt[i].x = le16_to_cpu(get_unaligned_le16(&buf[px]));
+		TPInfo->pt[i].y = le16_to_cpu(get_unaligned_le16(&buf[py]));
+	}
+
+#ifdef _DEBUG_REPORT
+	for (i = 0; i < TPInfo->fingers; i++)
+		pr_info("chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d\n",
+		i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y,
+		buf[pstatus], TPInfo->pt[i].Width, TPInfo->pt[i].Height,
+		TPInfo->pt[i].Pressure);
+#endif
+label_send_report:
+/* Report co-ordinates to the multi-touch stack */
+	for (i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++) {
+		if (TPInfo->pt[i].Pressure) {
+			TPInfo->pt[i].Width *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							TPInfo->pt[i].Width);
+			TPInfo->pt[i].Height *= AREA_UNIT;
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR,
+							TPInfo->pt[i].Height);
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							TPInfo->pt[i].Pressure);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							TPInfo->pt[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							TPInfo->pt[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
+							TPInfo->pt[i].id);
+			/*Android 2.3*/
+			input_mt_sync(ts->input_dev);
+			all_touch_up = false;
+		}
+		if (i == (TPInfo->fingers - 1) && all_touch_up == true)
+			input_mt_sync(ts->input_dev);
+	}
+	if (TPInfo->fingers == 0)
+		input_mt_sync(ts->input_dev);
+	input_sync(ts->input_dev);
+
+err_free_allocate:
+
+	if (ts->use_irq) {
+#ifdef _INT_MODE_1	/*case 1 mode*/
+		/*TODO: After interrupt status low,
+		 * read i2c bus data by polling,
+		 * until interrupt status is high*/
+		ret =  gpio_get_value(GPIO_IRQ);
+		/*interrupt pin is still LOW,
+		 * read data until interrupt pin is released.*/
+		if (!ret)
+			hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS),
+						HRTIMER_MODE_REL);
+		else {
+			if (TPInfo->pre_keybit_state)
+				/*clear for interrupt*/
+				ts_report_key(ts->client, 0x0);
+
+			if (irqd_irq_disabled(&ts->desc->irq_data))
+				enable_irq(ts->client->irq);
+		}
+#else /*case 2 mode*/
+		if (irqd_irq_disabled(&ts->desc->irq_data))
+			enable_irq(ts->client->irq);
+#endif
+	}
+
+	mutex_unlock(&ts->mutex_wq);
+}
+
+static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
+{
+	int i = 0;
+
+	for (i = 0; i < max; i++) {
+		TPInfo->pt[i].id = -1;
+		TPInfo->pt[i].x = 0;
+		TPInfo->pt[i].y = 0;
+		TPInfo->pt[i].Pressure = 0;
+		TPInfo->pt[i].Width = 0;
+	}
+	TPInfo->id = 0x0;
+	TPInfo->fingers = 0;
+}
+
+static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
+{
+	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
+
+	queue_work(sis_wq, &ts->work);
+	if (!ts->use_irq)	/*For Polling mode*/
+	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+	struct sis_ts_data *ts = dev_id;
+
+	if (!irqd_irq_disabled(&ts->desc->irq_data))
+		disable_irq_nosync(ts->client->irq);
+	queue_work(sis_wq, &ts->work);
+	return IRQ_HANDLED;
+}
+
+static int initial_irq(void)
+{
+	int ret = 0;
+#ifdef _I2C_INT_ENABLE
+	/* initialize gpio and interrupt pins */
+	/*ex. GPIO_133 for interrupt mode*/
+	ret = gpio_request(GPIO_IRQ, "GPIO_133");
+	if (ret < 0) {
+		/*Set Active Low.
+		 * Please reference the file include/linux/interrupt.h*/
+		pr_err("sis_ts_probe: Failed to gpio_request\n");
+		pr_err("sis_ts_probe: Fail : gpio_request was called before this driver call\n");
+	}
+	/* setting gpio direction here OR boardinfo file*/
+
+#else
+	ret = SIS_ERR;
+#endif
+	return ret;
+}
+
+/*static uint16_t cal_crc_with_cmd(char *data, int start, int end, uint8_t cmd)
+{
+	int i = 0;
+	uint16_t crc = 0;
+
+	crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd) & 0x00FF];
+	for (i = start; i <= end ; i++)
+		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ data[i]) & 0x00FF];
+	return crc;
+}*/
+
+/*static void write_crc(unsigned char *buf, int start, int end)
+{
+	uint16_t crc = 0;
+
+	crc = cal_crc(buf, start , end);
+	buf[end+1] = (crc >> 8) & 0xff;
+	buf[end+2] = crc & 0xff;
+}*/
+
+#ifdef _STD_RW_IO
+#define BUFFER_SIZE MAX_BYTE
+static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
+								size_t count,
+								loff_t *f_pos)
+{
+	int ret = 0;
+	char *kdata;
+	char cmd;
+
+	pr_info("sis_cdev_write.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+
+	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+	if (!ret) {
+		pr_err("cannot access user space memory\n");
+		return SIS_ERR_ACCESS_USER_MEM;
+	}
+
+	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+	if (kdata == 0)
+		return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+	if (ret) {
+		pr_err("copy_from_user fail\n");
+		kfree(kdata);
+		return SIS_ERR_COPY_FROM_USER;
+	}
+#ifdef _DEBUG_PACKAGE
+	PrintBuffer(0, count, kdata);
+#endif
+
+	cmd = kdata[6];
+
+/*Write & Read*/
+	ret = sis_command_for_write(ts_bak->client, count, kdata);
+	if (ret < 0) {
+		pr_err("i2c_transfer write error %d\n", ret);
+		kfree(kdata);
+		return SIS_ERR_TRANSMIT_I2C;
+	}
+	if (copy_to_user((char *) buf, kdata, BUFFER_SIZE)) {
+		pr_err("copy_to_user fail\n");
+		ret = SIS_ERR_COPY_FROM_KERNEL;
+	}
+	kfree(kdata);
+	return ret;
+}
+
+/*for get system time*/
+static ssize_t sis_cdev_read(struct file *file, char __user *buf,
+								size_t count,
+								loff_t *f_pos)
+{
+	int ret = 0;
+	char *kdata;
+
+	pr_info("sis_cdev_read.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
+	if (!ret) {
+		pr_err("cannot access user space memory\n");
+		return SIS_ERR_ACCESS_USER_MEM;
+	}
+	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+	if (kdata == 0)
+		return SIS_ERR_ALLOCATE_KERNEL_MEM;
+	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
+	if (ret) {
+		pr_err("copy_from_user fail\n");
+		kfree(kdata);
+		return SIS_ERR_COPY_FROM_USER;
+	}
+#ifdef _DEBUG_PACKAGE
+	PrintBuffer(0, count, kdata);
+#endif
+	/*Write & Read*/
+	ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
+	if (ret < 0) {
+		pr_err("i2c_transfer read error %d\n", ret);
+		kfree(kdata);
+		return SIS_ERR_TRANSMIT_I2C;
+	}
+
+	ret = le16_to_cpu(get_unaligned_le16(kdata));
+
+	/*{
+		int i;
+
+		pr_info("ret=%d\n", ret);
+		for (i = 0; i < ret && i < BUFFER_SIZE; i++)
+			pr_info("%02x ", kdata[i]);
+		pr_info("\n");
+	}*/
+
+	if (copy_to_user((char *)buf, kdata, BUFFER_SIZE)) {
+		pr_err("copy_to_user fail\n");
+		ret = SIS_ERR_COPY_FROM_KERNEL;
+	}
+
+	kfree(kdata);
+	return ret;
+}
+
+#undef BUFFER_SIZE
+
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+	pr_info("sis_cdev_open.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+
+	if (ts_bak->use_irq) {
+		if (!irqd_irq_disabled(&ts_bak->desc->irq_data))
+			disable_irq(ts_bak->client->irq);
+		else {
+			pr_info("sis_cdev_open: IRQ_STATUS: %x\n",
+			irqd_irq_disabled(&ts_bak->desc->irq_data));
+		}
+	}
+	hrtimer_cancel(&ts_bak->timer);
+	flush_workqueue(sis_wq);		/*only flush sis_wq*/
+	return 0;	/*success*/
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	pr_info("sis_cdev_release.\n");
+	if (ts_bak == 0)
+		return SIS_ERR_CLIENT;
+	if (ts_bak->use_irq) {
+		if (irqd_irq_disabled(&ts_bak->desc->irq_data))
+			enable_irq(ts_bak->client->irq);
+	} else
+		hrtimer_start(&ts_bak->timer, ktime_set(1, 0),
+					HRTIMER_MODE_REL);
+	return 0;
+}
+
+static const struct file_operations sis_cdev_fops = {
+	.owner	= THIS_MODULE,
+	.read	= sis_cdev_read,
+	.write	= sis_cdev_write,
+	.open	= sis_cdev_open,
+	.release	= sis_cdev_release,
+};
+
+static int sis_setup_chardev(struct sis_ts_data *ts)
+{
+	dev_t dev = MKDEV(sis_char_major, 0);
+	int ret = 0;
+	struct device *class_dev = NULL;
+
+	pr_info("sis_setup_chardev.\n");
+	if (ts == NULL)
+		return -ENOMEM;
+
+	/*dynamic allocate driver handle*/
+	ret = alloc_chrdev_region(&dev, 0,
+				sis_char_devs_count, DEVICE_NAME);
+	if (ret)
+		return ret;
+
+	sis_char_major = MAJOR(dev);
+	cdev_init(&sis_char_cdev, &sis_cdev_fops);
+	sis_char_cdev.owner = THIS_MODULE;
+	ret = cdev_add(&sis_char_cdev, dev, sis_char_devs_count);
+	if (ret)
+		goto err1;
+
+	pr_info("%s driver(major %d) installed.\n",
+			DEVICE_NAME, sis_char_major);
+	/*register class*/
+	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(sis_char_class)) {
+		ret = PTR_ERR(sis_char_class);
+		goto err2;
+	}
+
+	class_dev = device_create(sis_char_class, NULL, dev, NULL, DEVICE_NAME);
+	if (IS_ERR(class_dev)) {
+		ret = PTR_ERR(class_dev);
+		goto err3;
+	}
+
+	return 0;
+err3:
+	class_destroy(sis_char_class);
+	sis_char_class = NULL;
+err2:
+	cdev_del(&sis_char_cdev);
+	memset(&sis_char_cdev, 0, sizeof(struct cdev));
+err1:
+	sis_char_major = 0;
+	unregister_chrdev_region(dev, sis_char_devs_count);
+	return ret;
+}
+
+static void sis_deinit_chardev(void)
+{
+	dev_t dev = MKDEV(sis_char_major, 0);
+
+	if (sis_char_class) {
+		pr_info("sis_deinit_chardev\n");
+		device_destroy(sis_char_class, dev);
+		class_destroy(sis_char_class);
+		sis_char_class = NULL;
+		cdev_del(&sis_char_cdev);
+		memset(&sis_char_cdev, 0, sizeof(struct cdev));
+		sis_char_major = 0;
+		unregister_chrdev_region(dev, sis_char_devs_count);
+	}
+}
+#endif
+
+static int sis_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = NULL;
+	struct sis_i2c_rmi_platform_data *pdata = NULL;
+
+	pr_info("sis_ts_probe\n");
+	TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
+	if (TPInfo == NULL) {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
+	if (ts == NULL) {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+	ts_bak = ts;
+	mutex_init(&ts->mutex_wq);
+	/*1. Init Work queue and necessary buffers*/
+	INIT_WORK(&ts->work, sis_ts_work_func);
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	pdata = client->dev.platform_data;
+	if (pdata)
+		ts->power = pdata->power;
+	if (ts->power) {
+		ret = ts->power(1);
+		if (ret < 0) {
+			pr_err("sis_ts_probe power on failed\n");
+			goto err_power_failed;
+		}
+	}
+	/*2. Allocate input device*/
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		ret = -ENOMEM;
+		pr_err("sis_ts_probe: Failed to allocate input device\n");
+		goto err_input_dev_alloc_failed;
+	}
+	/*This input device name should be the same to IDC file name.*/
+	ts->input_dev->name = "sis_touch";
+
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+	set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+	set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+	set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+	set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
+	set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+	set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
+	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,
+						0, PRESSURE_MAX, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+						0, AREA_LENGTH_LONGER, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR,
+						0, AREA_LENGTH_SHORT, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+						0, SIS_MAX_X, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+						0, SIS_MAX_Y, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
+						0, 15, 0, 0);
+	/* add for touch keys */
+	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+	/*3. Register input device to core*/
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		pr_err("sis_ts_probe: Unable to register %s input device\n",
+				ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+	/*4. irq or timer setup*/
+	ret = initial_irq();
+	if (ret >= 0) {
+		client->irq = gpio_to_irq(GPIO_IRQ);
+		ret = request_irq(client->irq, sis_ts_irq_handler,
+					IRQF_TRIGGER_FALLING, client->name, ts);
+		if (ret == 0)
+			ts->use_irq = 1;
+		else
+			dev_err(&client->dev, "request_irq failed\n");
+	}
+	ts->desc = irq_to_desc(ts_bak->client->irq);
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ts->timer.function = sis_ts_timer_func;
+	if (!ts->use_irq)
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = sis_ts_early_suspend;
+	ts->early_suspend.resume = sis_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+	pr_info("sis_ts_probe: Start touchscreen %s in %s mode\n",
+			ts->input_dev->name,
+			ts->use_irq ? "interrupt" : "polling");
+	if (ts->use_irq) {
+#ifdef _INT_MODE_1
+		pr_info("sis_ts_probe: interrupt case 1 mode\n");
+#else
+		pr_info("sis_ts_probe: interrupt case 2 mode\n");
+#endif
+	}
+#ifdef _STD_RW_IO
+	ret = sis_setup_chardev(ts);
+	if (ret)
+		pr_err("sis_setup_chardev fail\n");
+#endif
+	pr_info("sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
+	return 0;
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+err_input_dev_alloc_failed:
+err_power_failed:
+	kfree(ts);
+err_alloc_data_failed:
+	return ret;
+}
+
+static int sis_ts_remove(struct i2c_client *client)
+{
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+#ifdef _STD_RW_IO
+	sis_deinit_chardev();
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+	return 0;
+}
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	TPInfo->pre_keybit_state = 0x0;
+
+	if (ts->use_irq) {
+		if (!irqd_irq_disabled(&ts->desc->irq_data))
+			disable_irq(client->irq);
+	} else
+		hrtimer_cancel(&ts->timer);
+	flush_workqueue(sis_wq);		/*only flush sis_wq*/
+
+
+	if (ts->power) {
+		ret = ts->power(0);
+		if (ret < 0)
+			pr_err("sis_ts_suspend power off failed\n");
+	}
+
+	return 0;
+}
+
+static int sis_ts_resume(struct i2c_client *client)
+{
+	int ret = 0;
+	struct sis_ts_data *ts = i2c_get_clientdata(client);
+
+	if (ts->power) {
+		ret = ts->power(1);
+		if (ret < 0)
+			pr_err("sis_ts_resume power on failed\n");
+	}
+
+	if (ts->use_irq) {
+		if (irqd_irq_disabled(&ts->desc->irq_data))
+			enable_irq(client->irq);
+	} else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sis_ts_early_suspend(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+
+	TPInfo->pre_keybit_state = 0x0;
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void sis_ts_late_resume(struct early_suspend *h)
+{
+	struct sis_ts_data *ts;
+
+	ts = container_of(h, struct sis_ts_data, early_suspend);
+	sis_ts_resume(ts->client);
+}
+#endif
+
+#ifdef CONFIG_X86
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int sis_ts_detect(struct i2c_client *client,
+		       struct i2c_board_info *info)
+{
+	const char *type_name;
+
+	pr_info("sis_ts_detect\n");
+	type_name = "sis_i2c_ts";
+	strlcpy(info->type, type_name, I2C_NAME_SIZE);
+	return 0;
+}
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.probe		= sis_ts_probe,
+	.remove		= sis_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= sis_ts_suspend,
+	.resume		= sis_ts_resume,
+#endif
+#ifdef CONFIG_X86
+	.class		= I2C_CLASS_HWMON,
+	.detect		= sis_ts_detect,
+	.address_list	= normal_i2c,
+#endif
+	.id_table	= sis_ts_id,
+	.driver = {
+		.name	= SIS_I2C_NAME,
+	},
+};
+
+static int __init sis_ts_init(void)
+{
+	pr_info("sis_ts_init\n");
+	sis_wq = create_singlethread_workqueue("sis_wq");
+
+	if (!sis_wq)
+		return -ENOMEM;
+	return i2c_add_driver(&sis_ts_driver);
+}
+
+static void __exit sis_ts_exit(void)
+{
+	pr_info("sis_ts_exit\n");
+	i2c_del_driver(&sis_ts_driver);
+	if (sis_wq)
+		destroy_workqueue(sis_wq);
+}
+
+module_init(sis_ts_init);
+module_exit(sis_ts_exit);
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
new file mode 100644
index 0000000..7639a52
--- /dev/null
+++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
@@ -0,0 +1,173 @@
+/*
+ * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
+ *
+ * Copyright (C) 2011 SiS, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Date: 2015/01/15
+ * Version:	Android_v2.05.00-A639-1113
+ */
+#include <linux/version.h>
+
+#ifndef _LINUX_SIS_I2C_H
+#define _LINUX_SIS_I2C_H
+
+
+#define SIS_I2C_NAME "sis_i2c_ts"
+#define SIS_SLAVE_ADDR					0x5c
+/*10ms*/
+#define TIMER_NS						10000000
+#define MAX_FINGERS						10
+
+/* For standard R/W IO ( SiS firmware application )*/
+#define _STD_RW_IO						/*ON/OFF*/
+
+/* Check data CRC */
+/*#define _CHECK_CRC*/						/*ON/OFF*/
+
+/* Interrupt setting and modes */
+#define _I2C_INT_ENABLE					/*ON/OFF*/
+#define GPIO_IRQ						133
+
+/*	Enable if use interrupt case 1 mode.	*/
+/*	Disable if use interrupt case 2 mode.	*/
+/*#define _INT_MODE_1*/					/*ON/OFF*/
+
+/* Resolution mode */
+/*Constant value*/
+#define SIS_MAX_X						4095
+#define SIS_MAX_Y						4095
+
+#define ONE_BYTE						1
+#define FIVE_BYTE						5
+#define EIGHT_BYTE						8
+#define SIXTEEN_BYTE					16
+#define PACKET_BUFFER_SIZE				128
+
+#define SIS_CMD_NORMAL					0x0
+#define SIS_CMD_SOFTRESET				0x82
+#define SIS_CMD_RECALIBRATE				0x87
+#define SIS_CMD_POWERMODE				0x90
+#define MSK_TOUCHNUM					0x0f
+#define MSK_HAS_CRC						0x10
+#define MSK_DATAFMT						0xe0
+#define MSK_PSTATE						0x0f
+#define MSK_PID							0xf0
+#define RES_FMT							0x00
+#define FIX_FMT							0x40
+
+/* for new i2c format */
+#define TOUCHDOWN						0x3
+#define TOUCHUP							0x0
+#define MAX_BYTE						64
+#define	PRESSURE_MAX					255
+
+/*Resolution diagonal */
+#define AREA_LENGTH_LONGER				5792
+/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
+#define AREA_LENGTH_SHORT				5792
+#define AREA_UNIT						(5792/32)
+
+
+#define FORMAT_MODE						1
+
+#define MSK_NOBTN						0
+#define MSK_COMP						1
+#define MSK_BACK						2
+#define MSK_MENU						4
+#define MSK_HOME						8
+
+#define P_BYTECOUNT						0
+#define ALL_IN_ONE_PACKAGE				0x10
+#define IS_TOUCH(x)						(x & 0x1)
+#define IS_HIDI2C(x)					((x & 0xF) == 0x06)
+#define IS_AREA(x)						((x >> 4) & 0x1)
+#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
+#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
+/*#define _DEBUG_PACKAGE*/				/*ON/OFF*/
+/*#define _DEBUG_REPORT*/				/*ON/OFF*/
+#define NORMAL_LEN_PER_POINT			6
+#define AREA_LEN_PER_POINT				2
+#define PRESSURE_LEN_PER_POINT			1
+
+#define TOUCH_FORMAT					0x1
+#define BUTTON_FORMAT					0x4
+#define HIDI2C_FORMAT					0x6
+#define P_REPORT_ID						2
+#define BUTTON_STATE					3
+#define BUTTON_KEY_COUNT				16
+#define BYTE_BYTECOUNT					2
+#define BYTE_COUNT						1
+#define BYTE_ReportID					1
+#define BYTE_CRC_HIDI2C					0
+#define BYTE_CRC_I2C					2
+#define BYTE_SCANTIME					2
+#define NO_TOUCH_BYTECOUNT				0x3
+
+/* TODO */
+#define TOUCH_POWER_PIN					0
+#define TOUCH_RESET_PIN					1
+
+/* CMD Define */
+#define BUF_ACK_PLACE_L					4
+#define BUF_ACK_PLACE_H					5
+#define BUF_ACK_L						0xEF
+#define BUF_ACK_H						0xBE
+#define BUF_NACK_L						0xAD
+#define BUF_NACK_H						0xDE
+#define BUF_CRC_PLACE					7
+
+/* SiS i2c error code */
+#define SIS_ERR						-1
+#define SIS_ERR_ACCESS_USER_MEM		-11 /* Access user memory fail */
+#define SIS_ERR_ALLOCATE_KERNEL_MEM	-12 /* Allocate memory fail */
+#define SIS_ERR_CLIENT				-13 /* Client not created */
+#define SIS_ERR_COPY_FROM_USER		-14 /* Copy data from user fail */
+#define SIS_ERR_COPY_FROM_KERNEL	-19 /* Copy data from kernel fail */
+#define SIS_ERR_TRANSMIT_I2C		-21 /* Transmit error in I2C */
+
+struct sis_i2c_rmi_platform_data {
+	int (*power)(int on);	/* Only valid in first array entry */
+};
+
+struct Point {
+	int id;
+	unsigned short x, y;		/*uint16_t ?*/
+	uint16_t Pressure;
+	uint16_t Width;
+	uint16_t Height;
+};
+
+struct sisTP_driver_data {
+	int id;
+	int fingers;
+	uint8_t pre_keybit_state;
+	struct Point pt[MAX_FINGERS];
+};
+
+struct sis_ts_data {
+	int (*power)(int on);
+	int use_irq;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct irq_desc *desc;
+	struct work_struct work;
+	struct mutex mutex_wq;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
+static int sis_ts_resume(struct i2c_client *client);
+
+#endif /* _LINUX_SIS_I2C_H */

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
  2015-02-12  6:07               ` 曾婷葳 (tammy_tseng)
@ 2015-02-12  7:02                 ` Dmitry Torokhov
  -1 siblings, 0 replies; 21+ messages in thread
From: Dmitry Torokhov @ 2015-02-12  7:02 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: Oliver Neukum, lkml, linux-input, tammy0524

Hi Tammy,

On Thu, Feb 12, 2015 at 02:07:21PM +0800, 曾婷葳 (tammy_tseng) wrote:
> Hi, 
> 
> I've checked the coding style and modified the i2c and hid touch driver for sis touch controller.
> Please help review them. 
> Thanks a lot.

This was again sent in base64, with DOS file endings...

> 
> Tammy
> -----
> Here is the sis i2c driver in input:
> 
> linux-3.18.5/drivers/input/touchscreen/Kconfig   |    7 +
>  linux-3.18.5/drivers/input/touchscreen/Makefile  |    1 +
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.c | 1032 ++++++++++++++++++++++
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.h |  173 ++++
>  4 files changed, 1213 insertions(+)
> 
> 
> -----
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Kconfig b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> index e1d8003..5093ccc 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Kconfig
> +++ b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> @@ -962,4 +962,11 @@ config TOUCHSCREEN_ZFORCE
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called zforce_ts.
>  
> +config TOUCHSCREEN_SIS_I2C
> +	tristate "SiS 9200 family I2C touchscreen driver"
> +	depends on I2C
> +	default n

No need to say "default n".

> +	help
> +	  This enables support for SiS 9200 family over I2C based touchscreens.

Please add

	To compile this driver as a module...

as all the rest of input dirvers.

> +
>  endif
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Makefile b/linux-3.18.5/drivers/input/touchscreen/Makefile
> index 090e61c..25cfd9f 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Makefile
> +++ b/linux-3.18.5/drivers/input/touchscreen/Makefile
> @@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> new file mode 100644
> index 0000000..260a7b6
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> @@ -0,0 +1,1032 @@
> +/* drivers/input/touchscreen/sis_i2c.c
> + *  - I2C Touch panel driver for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.

Not 2015?

> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif

There is no CONFIG_HAS_EARLYSUSPEND in mainline, please drop.

> +#include <linux/hrtimer.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include "sis_i2c.h"
> +#include <linux/linkage.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/uaccess.h>
> +#include <linux/irq.h>
> +#include <asm/unaligned.h>
> +
> +#ifdef _STD_RW_IO
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#define DEVICE_NAME "sis_aegis_touch_device"
> +static const int sis_char_devs_count = 1;        /* device count */
> +static int sis_char_major;
> +static struct cdev sis_char_cdev;
> +static struct class *sis_char_class;

This all should go away, we do not need custom char device for a
touchscreen.

> +#endif
> +
> +/* Addresses to scan */
> +static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
> +static struct workqueue_struct *sis_wq;

I see you are trying to support polling mode... Please don't, it is not
useful for production code. Also please switch to using threaded irq
instead of having hard irq + work queue - it is really hard to manage it
in race-free way.

> +struct sis_ts_data *ts_bak;
> +struct sisTP_driver_data *TPInfo;

Global? Why?

> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h);
> +static void sis_ts_late_resume(struct early_suspend *h);

Nope, don't have it.

> +#endif
> +
> +#ifdef _CHECK_CRC
> +static const unsigned short crc16tab[256] = {
> +	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
> +	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,

Isn't this CRC ITU-T V.41? We already have it in kernel.

> +	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
> +	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
> +	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
> +	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
> +	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
> +	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
> +	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
> +	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
> +	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
> +	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
> +	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
> +	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
> +	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
> +	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
> +	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
> +	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
> +	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
> +	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
> +	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
> +	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
> +	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
> +	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
> +	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
> +	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
> +	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
> +	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
> +	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
> +	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
> +	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
> +	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
> +};
> +
> +static uint16_t cal_crc(char *cmd, int start, int end)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd[i]) & 0x00FF];
> +	return crc;
> +}
> +#endif
> +
> +#ifdef _DEBUG_PACKAGE
> +static void PrintBuffer(int start, int length, char *buf)
> +{
> +	int i;
> +
> +	for (i = start; i < length; i++) {
> +		pr_info("%02x ", buf[i]);
> +		if (i != 0 && i % 30 == 0)
> +			pr_info("\n");
> +	}
> +	pr_info("\n");
> +}

To print hex buffer please use dev_dbg(dev, "%*ph", length, buf) instead
of rolling your custom implementation.

Also please avoid camel casing.

> +#endif
> +
> +static int sis_command_for_write(struct i2c_client *client, int wlength,
> +							unsigned char *wdata)
> +{
> +	int ret = SIS_ERR;

We definitely do not need custom error codes.

> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = 0; /*Write*/
> +	msg.len = wlength;
> +	msg.buf = (unsigned char *)wdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;

i2c_master_send()?

> +}
> +
> +static int sis_command_for_read(struct i2c_client *client, int rlength,
> +							unsigned char *rdata)
> +{
> +	int ret = SIS_ERR;
> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = I2C_M_RD; /*Read*/
> +	msg.len = rlength;
> +	msg.buf = rdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;

i2c_master_recv()?

> +}
> +
> +static int sis_cul_unit(uint8_t report_id)
> +{
> +	int ret = NORMAL_LEN_PER_POINT;
> +
> +	if (report_id != ALL_IN_ONE_PACKAGE) {
> +		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
> +			ret += AREA_LEN_PER_POINT;
> +		if (IS_PRESSURE(report_id))
> +			ret += PRESSURE_LEN_PER_POINT;
> +	}
> +
> +	return ret;
> +}
> +
> +static int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t *buf)
> +{
> +	uint8_t tmpbuf[MAX_BYTE] = {0};	/*MAX_BYTE = 64;*/
> +	int ret = SIS_ERR;
> +	int touchnum = 0;
> +	int p_count = 0;
> +	int touc_formate_id = 0;
> +	int locate = 0;
> +	bool read_first = true;
> +	/*
> +	* New i2c format
> +	* buf[0] = Low 8 bits of byte count value
> +	* buf[1] = High 8 bits of byte counte value
> +	* buf[2] = Report ID
> +	* buf[touch num * 6 + 2 ] = Touch informations;
> +	* 1 touch point has 6 bytes, it could be none if no touch
> +	* buf[touch num * 6 + 3] = Touch numbers
> +	*
> +	* One touch point information include 6 bytes, the order is
> +	*
> +	* 1. status = touch down or touch up
> +	* 2. id = finger id
> +	* 3. x axis low 8 bits
> +	* 4. x axis high 8 bits
> +	* 5. y axis low 8 bits
> +	* 6. y axis high 8 bits
> +	* */
> +	do {
> +		if (locate >= PACKET_BUFFER_SIZE) {
> +			pr_err("sis_ReadPacket: Buf Overflow\n");
> +			return SIS_ERR;
> +		}
> +		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
> +#ifdef _DEBUG_PACKAGE

Please drop this define and use dev_dbg().

> +		pr_info("chaoban test: Buf_Data [0~63]\n");
> +		PrintBuffer(0, 64, tmpbuf);
> +#endif
> +		if (ret < 0) {
> +			pr_err("sis_ReadPacket: i2c transfer error\n");
> +			return ret;
> +		}
> +		/*error package length of receiving data*/
> +		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE) {
> +			pr_err("sis_ReadPacket: Error Bytecount\n");
> +			return SIS_ERR;
> +		}
> +		if (read_first) {
> +			/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
> +				return 0;	/*touchnum is 0*/
> +		}
> +		/*skip parsing data when two devices are registered
> +		 * at the same slave address*/
> +		/*parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT
> +		 * or P_REPORT_ID is ALL_IN_ONE_PACKAGE*/
> +		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
> +		if ((touc_formate_id != TOUCH_FORMAT)
> +		&& (touc_formate_id != HIDI2C_FORMAT)
> +		&& (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)) {
> +			pr_err("sis_ReadPacket: Error Report_ID\n");
> +			return SIS_ERR;
> +		}
> +		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/*start from 0*/
> +		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) {
> +			if (IS_TOUCH(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_I2C;/*delete 2 byte crc*/
> +			} else if (IS_HIDI2C(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_HIDI2C;
> +			} else {	/*should not be happen*/
> +				pr_err("sis_ReadPacket: delete crc error\n");
> +				return SIS_ERR;
> +			}
> +			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
> +				p_count -= BYTE_SCANTIME;
> +		}
> +		/*else {}*/ /*For ALL_IN_ONE_PACKAGE*/
> +		if (read_first) {
> +			touchnum = tmpbuf[p_count];
> +		} else {
> +			if (tmpbuf[p_count] != 0) {
> +				pr_err("sis_ReadPacket: get error package\n");
> +				return SIS_ERR;
> +			}
> +		}
> +
> +#ifdef _CHECK_CRC
> +		/* HID over I2C data foramt and no touch packet without CRC */

If this device indeed uses HID protocol over I2C why do we need special
driver?

> +		if ((touc_formate_id != HIDI2C_FORMAT) &&
> +			(tmpbuf[P_BYTECOUNT] > 3)) {
> +			int crc_end = p_count + (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2);
> +			uint16_t buf_crc = cal_crc(
> +				tmpbuf, 2, crc_end);/*sub bytecount(2 byte)*/
> +			int l_package_crc = (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2) + p_count + 1;
> +			uint16_t package_crc = le16_to_cpu(get_unaligned_le16(
> +				&tmpbuf[l_package_crc]));
> +
> +			if (buf_crc != package_crc) {
> +				pr_err("sis_ReadPacket: CRC Error\n");
> +				return SIS_ERR;
> +			}
> +		}
> +#endif
> +		memcpy(&buf[locate], &tmpbuf[0], 64);
> +		/*Buf_Data [0~63] [64~128]*/
> +		locate += 64;
> +		read_first = false;
> +	} while (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE &&
> +			tmpbuf[p_count] > 5);
> +	return touchnum;
> +}
> +
> +#ifdef _INT_MODE_1
> +static void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
> +{
> +	int i = 0;
> +	uint8_t diff_keybit_state = 0x0;
> +	/*check keybit_state is difference with pre_keybit_state*/
> +	uint8_t key_value = 0x0; /*button location for binary*/
> +	uint8_t  key_pressed = 0x0; /*button is up or down*/
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (!ts) {
> +		pr_err("%s error: Missing Platform Data!\n", __func__);
> +		return;
> +	}
> +
> +	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
> +
> +	if (diff_keybit_state) {
> +		for (i = 0; i < BUTTON_KEY_COUNT; i++) {
> +			if ((diff_keybit_state >> i) & 0x01) {
> +				key_value = diff_keybit_state & (0x01 << i);
> +				key_pressed = (keybit_state >> i) & 0x01;
> +				switch (key_value) {
> +				case MSK_COMP:
> +					input_report_key(ts->input_dev,
> +						KEY_COMPOSE, key_pressed);
> +					break;
> +				case MSK_BACK:
> +					input_report_key(ts->input_dev,
> +						KEY_BACK, key_pressed);
> +					break;
> +				case MSK_MENU:
> +					input_report_key(ts->input_dev,
> +						KEY_MENU, key_pressed);
> +					break;
> +				case MSK_HOME:
> +					input_report_key(ts->input_dev,
> +						KEY_HOME, key_pressed);

I do not think you mean for the cursor to go to beginning of the
screen. All in all the set of events is unusual for a touchscreen.

> +					break;
> +				case MSK_NOBTN:
> +					/*Release the button if it touched.*/
> +				default:
> +					break;
> +				}
> +			}
> +		}
> +		TPInfo->pre_keybit_state = keybit_state;
> +	}
> +}
> +#endif
> +
> +static void sis_ts_work_func(struct work_struct *work)
> +{
> +	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
> +	int ret = SIS_ERR;
> +	int point_unit;
> +	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
> +	uint8_t i = 0, fingers = 0;
> +	uint8_t px = 0, py = 0, pstatus = 0;
> +	uint8_t p_area = 0;
> +	uint8_t p_preasure = 0;
> +	bool all_touch_up = true;
> +
> +	mutex_lock(&ts->mutex_wq);
> +    /* I2C or SMBUS block data read */
> +	ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
> +	/*Error Number*/
> +	if (ret < 0)
> +		goto err_free_allocate;
> +	/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +	else if (ret == 0) {
> +		fingers = 0;
> +		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +		goto label_send_report;
> +		/*need to report input_mt_sync()*/
> +	}
> +	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +
> +	/*Parser and Get the sis9200 data*/
> +	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
> +	fingers = ret;
> +
> +	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
> +
> +	/*fingers 10 =  0 ~ 9*/
> +	for (i = 0; i < fingers; i++) {
> +		if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5)) {
> +			/*Calc point status*/
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ ((i - 5) * point_unit);
> +			pstatus += 64;
> +		} else {
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ (i * point_unit);
> +					/*Calc point status*/
> +		}
> +	    px = pstatus + 2;	/*Calc point x_coord*/
> +	    py = px + 2;	/*Calc point y_coord*/
> +		if ((buf[pstatus]) == TOUCHUP) {
> +			TPInfo->pt[i].Width = 0;
> +			TPInfo->pt[i].Height = 0;
> +			TPInfo->pt[i].Pressure = 0;
> +		} else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE
> +					&& (buf[pstatus]) == TOUCHDOWN) {
> +			TPInfo->pt[i].Width = 1;
> +			TPInfo->pt[i].Height = 1;
> +			TPInfo->pt[i].Pressure = 1;
> +		} else if ((buf[pstatus]) == TOUCHDOWN) {
> +			p_area = py + 2;
> +			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
> +			/*area*/
> +			if (IS_AREA(buf[P_REPORT_ID])) {
> +				TPInfo->pt[i].Width = buf[p_area];
> +				TPInfo->pt[i].Height = buf[p_area + 1];
> +			} else {
> +				TPInfo->pt[i].Width = 1;
> +				TPInfo->pt[i].Height = 1;
> +			}
> +			/*preasure*/
> +			if (IS_PRESSURE(buf[P_REPORT_ID]))
> +				TPInfo->pt[i].Pressure = (buf[p_preasure]);
> +			else
> +				TPInfo->pt[i].Pressure = 1;
> +		} else {
> +			pr_err("sis_ts_work_func: Error Touch Status\n");
> +			goto err_free_allocate;
> +		}
> +		TPInfo->pt[i].id = (buf[pstatus + 1]);
> +		TPInfo->pt[i].x = le16_to_cpu(get_unaligned_le16(&buf[px]));
> +		TPInfo->pt[i].y = le16_to_cpu(get_unaligned_le16(&buf[py]));
> +	}
> +
> +#ifdef _DEBUG_REPORT
> +	for (i = 0; i < TPInfo->fingers; i++)
> +		pr_info("chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d\n",
> +		i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y,
> +		buf[pstatus], TPInfo->pt[i].Width, TPInfo->pt[i].Height,
> +		TPInfo->pt[i].Pressure);
> +#endif
> +label_send_report:
> +/* Report co-ordinates to the multi-touch stack */
> +	for (i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++) {
> +		if (TPInfo->pt[i].Pressure) {
> +			TPInfo->pt[i].Width *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +							TPInfo->pt[i].Width);
> +			TPInfo->pt[i].Height *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +							TPInfo->pt[i].Height);
> +			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
> +							TPInfo->pt[i].Pressure);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
> +							TPInfo->pt[i].x);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
> +							TPInfo->pt[i].y);
> +			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
> +							TPInfo->pt[i].id);
> +			/*Android 2.3*/

Huh?

> +			input_mt_sync(ts->input_dev);
> +			all_touch_up = false;

We need slotted MT-B protocol for new drivers, not MT-A.

> +		}
> +		if (i == (TPInfo->fingers - 1) && all_touch_up == true)
> +			input_mt_sync(ts->input_dev);
> +	}
> +	if (TPInfo->fingers == 0)
> +		input_mt_sync(ts->input_dev);
> +	input_sync(ts->input_dev);
> +
> +err_free_allocate:
> +
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1	/*case 1 mode*/
> +		/*TODO: After interrupt status low,
> +		 * read i2c bus data by polling,
> +		 * until interrupt status is high*/
> +		ret =  gpio_get_value(GPIO_IRQ);
> +		/*interrupt pin is still LOW,
> +		 * read data until interrupt pin is released.*/
> +		if (!ret)
> +			hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS),
> +						HRTIMER_MODE_REL);
> +		else {
> +			if (TPInfo->pre_keybit_state)
> +				/*clear for interrupt*/
> +				ts_report_key(ts->client, 0x0);
> +
> +			if (irqd_irq_disabled(&ts->desc->irq_data))
> +				enable_irq(ts->client->irq);
> +		}
> +#else /*case 2 mode*/
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(ts->client->irq);
> +#endif
> +	}
> +
> +	mutex_unlock(&ts->mutex_wq);
> +}
> +
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
> +{
> +	int i = 0;
> +
> +	for (i = 0; i < max; i++) {
> +		TPInfo->pt[i].id = -1;
> +		TPInfo->pt[i].x = 0;
> +		TPInfo->pt[i].y = 0;
> +		TPInfo->pt[i].Pressure = 0;
> +		TPInfo->pt[i].Width = 0;
> +	}
> +	TPInfo->id = 0x0;
> +	TPInfo->fingers = 0;
> +}
> +
> +static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
> +{
> +	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
> +
> +	queue_work(sis_wq, &ts->work);
> +	if (!ts->use_irq)	/*For Polling mode*/
> +	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	return HRTIMER_NORESTART;
> +}
> +
> +static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
> +{
> +	struct sis_ts_data *ts = dev_id;
> +
> +	if (!irqd_irq_disabled(&ts->desc->irq_data))
> +		disable_irq_nosync(ts->client->irq);
> +	queue_work(sis_wq, &ts->work);
> +	return IRQ_HANDLED;
> +}
> +
> +static int initial_irq(void)
> +{
> +	int ret = 0;
> +#ifdef _I2C_INT_ENABLE
> +	/* initialize gpio and interrupt pins */
> +	/*ex. GPIO_133 for interrupt mode*/
> +	ret = gpio_request(GPIO_IRQ, "GPIO_133");
> +	if (ret < 0) {
> +		/*Set Active Low.
> +		 * Please reference the file include/linux/interrupt.h*/
> +		pr_err("sis_ts_probe: Failed to gpio_request\n");
> +		pr_err("sis_ts_probe: Fail : gpio_request was called before this driver call\n");
> +	}
> +	/* setting gpio direction here OR boardinfo file*/
> +
> +#else
> +	ret = SIS_ERR;
> +#endif
> +	return ret;
> +}
> +
> +/*static uint16_t cal_crc_with_cmd(char *data, int start, int end, uint8_t cmd)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd) & 0x00FF];
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ data[i]) & 0x00FF];
> +	return crc;
> +}*/
> +
> +/*static void write_crc(unsigned char *buf, int start, int end)
> +{
> +	uint16_t crc = 0;
> +
> +	crc = cal_crc(buf, start , end);
> +	buf[end+1] = (crc >> 8) & 0xff;
> +	buf[end+2] = crc & 0xff;
> +}*/

Why do we need this commented out code? Please do clean up the code from
old cruft, debugging bits, etc, etc.

> +
> +#ifdef _STD_RW_IO
> +#define BUFFER_SIZE MAX_BYTE
> +static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +	char cmd;
> +
> +	pr_info("sis_cdev_write.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +
> +	cmd = kdata[6];
> +
> +/*Write & Read*/
> +	ret = sis_command_for_write(ts_bak->client, count, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer write error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +	if (copy_to_user((char *) buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +/*for get system time*/
> +static ssize_t sis_cdev_read(struct file *file, char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +
> +	pr_info("sis_cdev_read.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +	/*Write & Read*/
> +	ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +
> +	ret = le16_to_cpu(get_unaligned_le16(kdata));
> +
> +	/*{
> +		int i;
> +
> +		pr_info("ret=%d\n", ret);
> +		for (i = 0; i < ret && i < BUFFER_SIZE; i++)
> +			pr_info("%02x ", kdata[i]);
> +		pr_info("\n");
> +	}*/
> +
> +	if (copy_to_user((char *)buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_open.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	if (ts_bak->use_irq) {
> +		if (!irqd_irq_disabled(&ts_bak->desc->irq_data))
> +			disable_irq(ts_bak->client->irq);
> +		else {
> +			pr_info("sis_cdev_open: IRQ_STATUS: %x\n",
> +			irqd_irq_disabled(&ts_bak->desc->irq_data));
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +	return 0;	/*success*/
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_release.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	if (ts_bak->use_irq) {
> +		if (irqd_irq_disabled(&ts_bak->desc->irq_data))
> +			enable_irq(ts_bak->client->irq);
> +	} else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0),
> +					HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release	= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int ret = 0;
> +	struct device *class_dev = NULL;
> +
> +	pr_info("sis_setup_chardev.\n");
> +	if (ts == NULL)
> +		return -ENOMEM;
> +
> +	/*dynamic allocate driver handle*/
> +	ret = alloc_chrdev_region(&dev, 0,
> +				sis_char_devs_count, DEVICE_NAME);
> +	if (ret)
> +		return ret;
> +
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	ret = cdev_add(&sis_char_cdev, dev, sis_char_devs_count);
> +	if (ret)
> +		goto err1;
> +
> +	pr_info("%s driver(major %d) installed.\n",
> +			DEVICE_NAME, sis_char_major);
> +	/*register class*/
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if (IS_ERR(sis_char_class)) {
> +		ret = PTR_ERR(sis_char_class);
> +		goto err2;
> +	}
> +
> +	class_dev = device_create(sis_char_class, NULL, dev, NULL, DEVICE_NAME);
> +	if (IS_ERR(class_dev)) {
> +		ret = PTR_ERR(class_dev);
> +		goto err3;
> +	}
> +
> +	return 0;
> +err3:
> +	class_destroy(sis_char_class);
> +	sis_char_class = NULL;
> +err2:
> +	cdev_del(&sis_char_cdev);
> +	memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +err1:
> +	sis_char_major = 0;
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	return ret;
> +}
> +
> +static void sis_deinit_chardev(void)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +
> +	if (sis_char_class) {
> +		pr_info("sis_deinit_chardev\n");
> +		device_destroy(sis_char_class, dev);
> +		class_destroy(sis_char_class);
> +		sis_char_class = NULL;
> +		cdev_del(&sis_char_cdev);
> +		memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +		sis_char_major = 0;
> +		unregister_chrdev_region(dev, sis_char_devs_count);
> +	}
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +	pr_info("sis_ts_probe\n");
> +	TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +	if (TPInfo == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts_bak = ts;
> +	mutex_init(&ts->mutex_wq);
> +	/*1. Init Work queue and necessary buffers*/
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +	pdata = client->dev.platform_data;
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0) {
> +			pr_err("sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +	/*2. Allocate input device*/
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) {
> +		ret = -ENOMEM;
> +		pr_err("sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +	/*This input device name should be the same to IDC file name.*/
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +	set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +	set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +	set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,
> +						0, PRESSURE_MAX, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +						0, AREA_LENGTH_LONGER, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +						0, AREA_LENGTH_SHORT, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
> +						0, SIS_MAX_X, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
> +						0, SIS_MAX_Y, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
> +						0, 15, 0, 0);
> +	/* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +	/*3. Register input device to core*/
> +	ret = input_register_device(ts->input_dev);
> +	if (ret) {
> +		pr_err("sis_ts_probe: Unable to register %s input device\n",
> +				ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	/*4. irq or timer setup*/
> +	ret = initial_irq();
> +	if (ret >= 0) {
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler,
> +					IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0)
> +			ts->use_irq = 1;
> +		else
> +			dev_err(&client->dev, "request_irq failed\n");
> +	}
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +	if (!ts->use_irq)
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	pr_info("sis_ts_probe: Start touchscreen %s in %s mode\n",
> +			ts->input_dev->name,
> +			ts->use_irq ? "interrupt" : "polling");
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1
> +		pr_info("sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		pr_info("sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if (ret)
> +		pr_err("sis_setup_chardev fail\n");
> +#endif
> +	pr_info("sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +	return 0;
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);
> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +#ifdef _STD_RW_IO
> +	sis_deinit_chardev();
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq) {
> +		if (!irqd_irq_disabled(&ts->desc->irq_data))
> +			disable_irq(client->irq);
> +	} else
> +		hrtimer_cancel(&ts->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			pr_err("sis_ts_suspend power off failed\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			pr_err("sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq) {
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(client->irq);
> +	} else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_suspend(ts->client, PMSG_SUSPEND);
> +}
> +
> +static void sis_ts_late_resume(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_resume(ts->client);
> +}
> +#endif
> +
> +#ifdef CONFIG_X86
> +/* Return 0 if detection is successful, -ENODEV otherwise */
> +static int sis_ts_detect(struct i2c_client *client,
> +		       struct i2c_board_info *info)
> +{
> +	const char *type_name;
> +
> +	pr_info("sis_ts_detect\n");
> +	type_name = "sis_i2c_ts";
> +	strlcpy(info->type, type_name, I2C_NAME_SIZE);
> +	return 0;
> +}
> +#endif
> +
> +static const struct i2c_device_id sis_ts_id[] = {
> +	{ SIS_I2C_NAME, 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, sis_ts_id);
> +
> +static struct i2c_driver sis_ts_driver = {
> +	.probe		= sis_ts_probe,
> +	.remove		= sis_ts_remove,
> +#ifndef CONFIG_HAS_EARLYSUSPEND
> +	.suspend	= sis_ts_suspend,
> +	.resume		= sis_ts_resume,
> +#endif
> +#ifdef CONFIG_X86
> +	.class		= I2C_CLASS_HWMON,
> +	.detect		= sis_ts_detect,
> +	.address_list	= normal_i2c,
> +#endif
> +	.id_table	= sis_ts_id,
> +	.driver = {
> +		.name	= SIS_I2C_NAME,
> +	},
> +};
> +
> +static int __init sis_ts_init(void)
> +{
> +	pr_info("sis_ts_init\n");
> +	sis_wq = create_singlethread_workqueue("sis_wq");
> +
> +	if (!sis_wq)
> +		return -ENOMEM;
> +	return i2c_add_driver(&sis_ts_driver);
> +}
> +
> +static void __exit sis_ts_exit(void)
> +{
> +	pr_info("sis_ts_exit\n");
> +	i2c_del_driver(&sis_ts_driver);
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +}
> +
> +module_init(sis_ts_init);
> +module_exit(sis_ts_exit);
> +MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> new file mode 100644
> index 0000000..7639a52
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> @@ -0,0 +1,173 @@
> +/*
> + * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * Date: 2015/01/15
> + * Version:	Android_v2.05.00-A639-1113
> + */
> +#include <linux/version.h>
> +
> +#ifndef _LINUX_SIS_I2C_H
> +#define _LINUX_SIS_I2C_H
> +
> +
> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +/*10ms*/
> +#define TIMER_NS						10000000
> +#define MAX_FINGERS						10
> +
> +/* For standard R/W IO ( SiS firmware application )*/
> +#define _STD_RW_IO						/*ON/OFF*/
> +
> +/* Check data CRC */
> +/*#define _CHECK_CRC*/						/*ON/OFF*/
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					/*ON/OFF*/
> +#define GPIO_IRQ						133
> +
> +/*	Enable if use interrupt case 1 mode.	*/
> +/*	Disable if use interrupt case 2 mode.	*/
> +/*#define _INT_MODE_1*/					/*ON/OFF*/
> +
> +/* Resolution mode */
> +/*Constant value*/
> +#define SIS_MAX_X						4095
> +#define SIS_MAX_Y						4095
> +
> +#define ONE_BYTE						1
> +#define FIVE_BYTE						5
> +#define EIGHT_BYTE						8
> +#define SIXTEEN_BYTE					16
> +#define PACKET_BUFFER_SIZE				128
> +
> +#define SIS_CMD_NORMAL					0x0
> +#define SIS_CMD_SOFTRESET				0x82
> +#define SIS_CMD_RECALIBRATE				0x87
> +#define SIS_CMD_POWERMODE				0x90
> +#define MSK_TOUCHNUM					0x0f
> +#define MSK_HAS_CRC						0x10
> +#define MSK_DATAFMT						0xe0
> +#define MSK_PSTATE						0x0f
> +#define MSK_PID							0xf0
> +#define RES_FMT							0x00
> +#define FIX_FMT							0x40
> +
> +/* for new i2c format */
> +#define TOUCHDOWN						0x3
> +#define TOUCHUP							0x0
> +#define MAX_BYTE						64
> +#define	PRESSURE_MAX					255
> +
> +/*Resolution diagonal */
> +#define AREA_LENGTH_LONGER				5792
> +/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
> +#define AREA_LENGTH_SHORT				5792
> +#define AREA_UNIT						(5792/32)
> +
> +
> +#define FORMAT_MODE						1
> +
> +#define MSK_NOBTN						0
> +#define MSK_COMP						1
> +#define MSK_BACK						2
> +#define MSK_MENU						4
> +#define MSK_HOME						8
> +
> +#define P_BYTECOUNT						0
> +#define ALL_IN_ONE_PACKAGE				0x10
> +#define IS_TOUCH(x)						(x & 0x1)
> +#define IS_HIDI2C(x)					((x & 0xF) == 0x06)
> +#define IS_AREA(x)						((x >> 4) & 0x1)
> +#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
> +#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
> +/*#define _DEBUG_PACKAGE*/				/*ON/OFF*/
> +/*#define _DEBUG_REPORT*/				/*ON/OFF*/
> +#define NORMAL_LEN_PER_POINT			6
> +#define AREA_LEN_PER_POINT				2
> +#define PRESSURE_LEN_PER_POINT			1
> +
> +#define TOUCH_FORMAT					0x1
> +#define BUTTON_FORMAT					0x4
> +#define HIDI2C_FORMAT					0x6
> +#define P_REPORT_ID						2
> +#define BUTTON_STATE					3
> +#define BUTTON_KEY_COUNT				16
> +#define BYTE_BYTECOUNT					2
> +#define BYTE_COUNT						1
> +#define BYTE_ReportID					1
> +#define BYTE_CRC_HIDI2C					0
> +#define BYTE_CRC_I2C					2
> +#define BYTE_SCANTIME					2
> +#define NO_TOUCH_BYTECOUNT				0x3
> +
> +/* TODO */
> +#define TOUCH_POWER_PIN					0
> +#define TOUCH_RESET_PIN					1
> +
> +/* CMD Define */
> +#define BUF_ACK_PLACE_L					4
> +#define BUF_ACK_PLACE_H					5
> +#define BUF_ACK_L						0xEF
> +#define BUF_ACK_H						0xBE
> +#define BUF_NACK_L						0xAD
> +#define BUF_NACK_H						0xDE
> +#define BUF_CRC_PLACE					7
> +
> +/* SiS i2c error code */
> +#define SIS_ERR						-1
> +#define SIS_ERR_ACCESS_USER_MEM		-11 /* Access user memory fail */
> +#define SIS_ERR_ALLOCATE_KERNEL_MEM	-12 /* Allocate memory fail */
> +#define SIS_ERR_CLIENT				-13 /* Client not created */
> +#define SIS_ERR_COPY_FROM_USER		-14 /* Copy data from user fail */
> +#define SIS_ERR_COPY_FROM_KERNEL	-19 /* Copy data from kernel fail */
> +#define SIS_ERR_TRANSMIT_I2C		-21 /* Transmit error in I2C */
> +
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +struct Point {
> +	int id;
> +	unsigned short x, y;		/*uint16_t ?*/
> +	uint16_t Pressure;
> +	uint16_t Width;
> +	uint16_t Height;
> +};
> +
> +struct sisTP_driver_data {
> +	int id;
> +	int fingers;
> +	uint8_t pre_keybit_state;
> +	struct Point pt[MAX_FINGERS];
> +};
> +
> +struct sis_ts_data {
> +	int (*power)(int on);
> +	int use_irq;
> +	struct i2c_client *client;
> +	struct input_dev *input_dev;
> +	struct hrtimer timer;
> +	struct irq_desc *desc;
> +	struct work_struct work;
> +	struct mutex mutex_wq;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif
> +};
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
> +static int sis_ts_resume(struct i2c_client *client);
> +
> +#endif /* _LINUX_SIS_I2C_H */

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-02-12  7:02                 ` Dmitry Torokhov
  0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Torokhov @ 2015-02-12  7:02 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: Oliver Neukum, lkml, linux-input, tammy0524

Hi Tammy,

On Thu, Feb 12, 2015 at 02:07:21PM +0800, 曾婷葳 (tammy_tseng) wrote:
> Hi, 
> 
> I've checked the coding style and modified the i2c and hid touch driver for sis touch controller.
> Please help review them. 
> Thanks a lot.

This was again sent in base64, with DOS file endings...

> 
> Tammy
> -----
> Here is the sis i2c driver in input:
> 
> linux-3.18.5/drivers/input/touchscreen/Kconfig   |    7 +
>  linux-3.18.5/drivers/input/touchscreen/Makefile  |    1 +
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.c | 1032 ++++++++++++++++++++++
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.h |  173 ++++
>  4 files changed, 1213 insertions(+)
> 
> 
> -----
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Kconfig b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> index e1d8003..5093ccc 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Kconfig
> +++ b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> @@ -962,4 +962,11 @@ config TOUCHSCREEN_ZFORCE
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called zforce_ts.
>  
> +config TOUCHSCREEN_SIS_I2C
> +	tristate "SiS 9200 family I2C touchscreen driver"
> +	depends on I2C
> +	default n

No need to say "default n".

> +	help
> +	  This enables support for SiS 9200 family over I2C based touchscreens.

Please add

	To compile this driver as a module...

as all the rest of input dirvers.

> +
>  endif
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Makefile b/linux-3.18.5/drivers/input/touchscreen/Makefile
> index 090e61c..25cfd9f 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Makefile
> +++ b/linux-3.18.5/drivers/input/touchscreen/Makefile
> @@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> new file mode 100644
> index 0000000..260a7b6
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> @@ -0,0 +1,1032 @@
> +/* drivers/input/touchscreen/sis_i2c.c
> + *  - I2C Touch panel driver for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.

Not 2015?

> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif

There is no CONFIG_HAS_EARLYSUSPEND in mainline, please drop.

> +#include <linux/hrtimer.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include "sis_i2c.h"
> +#include <linux/linkage.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/uaccess.h>
> +#include <linux/irq.h>
> +#include <asm/unaligned.h>
> +
> +#ifdef _STD_RW_IO
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#define DEVICE_NAME "sis_aegis_touch_device"
> +static const int sis_char_devs_count = 1;        /* device count */
> +static int sis_char_major;
> +static struct cdev sis_char_cdev;
> +static struct class *sis_char_class;

This all should go away, we do not need custom char device for a
touchscreen.

> +#endif
> +
> +/* Addresses to scan */
> +static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
> +static struct workqueue_struct *sis_wq;

I see you are trying to support polling mode... Please don't, it is not
useful for production code. Also please switch to using threaded irq
instead of having hard irq + work queue - it is really hard to manage it
in race-free way.

> +struct sis_ts_data *ts_bak;
> +struct sisTP_driver_data *TPInfo;

Global? Why?

> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h);
> +static void sis_ts_late_resume(struct early_suspend *h);

Nope, don't have it.

> +#endif
> +
> +#ifdef _CHECK_CRC
> +static const unsigned short crc16tab[256] = {
> +	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
> +	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,

Isn't this CRC ITU-T V.41? We already have it in kernel.

> +	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
> +	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
> +	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
> +	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
> +	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
> +	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
> +	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
> +	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
> +	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
> +	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
> +	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
> +	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
> +	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
> +	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
> +	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
> +	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
> +	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
> +	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
> +	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
> +	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
> +	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
> +	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
> +	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
> +	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
> +	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
> +	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
> +	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
> +	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
> +	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
> +	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
> +};
> +
> +static uint16_t cal_crc(char *cmd, int start, int end)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd[i]) & 0x00FF];
> +	return crc;
> +}
> +#endif
> +
> +#ifdef _DEBUG_PACKAGE
> +static void PrintBuffer(int start, int length, char *buf)
> +{
> +	int i;
> +
> +	for (i = start; i < length; i++) {
> +		pr_info("%02x ", buf[i]);
> +		if (i != 0 && i % 30 == 0)
> +			pr_info("\n");
> +	}
> +	pr_info("\n");
> +}

To print hex buffer please use dev_dbg(dev, "%*ph", length, buf) instead
of rolling your custom implementation.

Also please avoid camel casing.

> +#endif
> +
> +static int sis_command_for_write(struct i2c_client *client, int wlength,
> +							unsigned char *wdata)
> +{
> +	int ret = SIS_ERR;

We definitely do not need custom error codes.

> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = 0; /*Write*/
> +	msg.len = wlength;
> +	msg.buf = (unsigned char *)wdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;

i2c_master_send()?

> +}
> +
> +static int sis_command_for_read(struct i2c_client *client, int rlength,
> +							unsigned char *rdata)
> +{
> +	int ret = SIS_ERR;
> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = I2C_M_RD; /*Read*/
> +	msg.len = rlength;
> +	msg.buf = rdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;

i2c_master_recv()?

> +}
> +
> +static int sis_cul_unit(uint8_t report_id)
> +{
> +	int ret = NORMAL_LEN_PER_POINT;
> +
> +	if (report_id != ALL_IN_ONE_PACKAGE) {
> +		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
> +			ret += AREA_LEN_PER_POINT;
> +		if (IS_PRESSURE(report_id))
> +			ret += PRESSURE_LEN_PER_POINT;
> +	}
> +
> +	return ret;
> +}
> +
> +static int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t *buf)
> +{
> +	uint8_t tmpbuf[MAX_BYTE] = {0};	/*MAX_BYTE = 64;*/
> +	int ret = SIS_ERR;
> +	int touchnum = 0;
> +	int p_count = 0;
> +	int touc_formate_id = 0;
> +	int locate = 0;
> +	bool read_first = true;
> +	/*
> +	* New i2c format
> +	* buf[0] = Low 8 bits of byte count value
> +	* buf[1] = High 8 bits of byte counte value
> +	* buf[2] = Report ID
> +	* buf[touch num * 6 + 2 ] = Touch informations;
> +	* 1 touch point has 6 bytes, it could be none if no touch
> +	* buf[touch num * 6 + 3] = Touch numbers
> +	*
> +	* One touch point information include 6 bytes, the order is
> +	*
> +	* 1. status = touch down or touch up
> +	* 2. id = finger id
> +	* 3. x axis low 8 bits
> +	* 4. x axis high 8 bits
> +	* 5. y axis low 8 bits
> +	* 6. y axis high 8 bits
> +	* */
> +	do {
> +		if (locate >= PACKET_BUFFER_SIZE) {
> +			pr_err("sis_ReadPacket: Buf Overflow\n");
> +			return SIS_ERR;
> +		}
> +		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
> +#ifdef _DEBUG_PACKAGE

Please drop this define and use dev_dbg().

> +		pr_info("chaoban test: Buf_Data [0~63]\n");
> +		PrintBuffer(0, 64, tmpbuf);
> +#endif
> +		if (ret < 0) {
> +			pr_err("sis_ReadPacket: i2c transfer error\n");
> +			return ret;
> +		}
> +		/*error package length of receiving data*/
> +		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE) {
> +			pr_err("sis_ReadPacket: Error Bytecount\n");
> +			return SIS_ERR;
> +		}
> +		if (read_first) {
> +			/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
> +				return 0;	/*touchnum is 0*/
> +		}
> +		/*skip parsing data when two devices are registered
> +		 * at the same slave address*/
> +		/*parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT
> +		 * or P_REPORT_ID is ALL_IN_ONE_PACKAGE*/
> +		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
> +		if ((touc_formate_id != TOUCH_FORMAT)
> +		&& (touc_formate_id != HIDI2C_FORMAT)
> +		&& (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)) {
> +			pr_err("sis_ReadPacket: Error Report_ID\n");
> +			return SIS_ERR;
> +		}
> +		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/*start from 0*/
> +		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) {
> +			if (IS_TOUCH(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_I2C;/*delete 2 byte crc*/
> +			} else if (IS_HIDI2C(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_HIDI2C;
> +			} else {	/*should not be happen*/
> +				pr_err("sis_ReadPacket: delete crc error\n");
> +				return SIS_ERR;
> +			}
> +			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
> +				p_count -= BYTE_SCANTIME;
> +		}
> +		/*else {}*/ /*For ALL_IN_ONE_PACKAGE*/
> +		if (read_first) {
> +			touchnum = tmpbuf[p_count];
> +		} else {
> +			if (tmpbuf[p_count] != 0) {
> +				pr_err("sis_ReadPacket: get error package\n");
> +				return SIS_ERR;
> +			}
> +		}
> +
> +#ifdef _CHECK_CRC
> +		/* HID over I2C data foramt and no touch packet without CRC */

If this device indeed uses HID protocol over I2C why do we need special
driver?

> +		if ((touc_formate_id != HIDI2C_FORMAT) &&
> +			(tmpbuf[P_BYTECOUNT] > 3)) {
> +			int crc_end = p_count + (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2);
> +			uint16_t buf_crc = cal_crc(
> +				tmpbuf, 2, crc_end);/*sub bytecount(2 byte)*/
> +			int l_package_crc = (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2) + p_count + 1;
> +			uint16_t package_crc = le16_to_cpu(get_unaligned_le16(
> +				&tmpbuf[l_package_crc]));
> +
> +			if (buf_crc != package_crc) {
> +				pr_err("sis_ReadPacket: CRC Error\n");
> +				return SIS_ERR;
> +			}
> +		}
> +#endif
> +		memcpy(&buf[locate], &tmpbuf[0], 64);
> +		/*Buf_Data [0~63] [64~128]*/
> +		locate += 64;
> +		read_first = false;
> +	} while (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE &&
> +			tmpbuf[p_count] > 5);
> +	return touchnum;
> +}
> +
> +#ifdef _INT_MODE_1
> +static void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
> +{
> +	int i = 0;
> +	uint8_t diff_keybit_state = 0x0;
> +	/*check keybit_state is difference with pre_keybit_state*/
> +	uint8_t key_value = 0x0; /*button location for binary*/
> +	uint8_t  key_pressed = 0x0; /*button is up or down*/
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (!ts) {
> +		pr_err("%s error: Missing Platform Data!\n", __func__);
> +		return;
> +	}
> +
> +	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
> +
> +	if (diff_keybit_state) {
> +		for (i = 0; i < BUTTON_KEY_COUNT; i++) {
> +			if ((diff_keybit_state >> i) & 0x01) {
> +				key_value = diff_keybit_state & (0x01 << i);
> +				key_pressed = (keybit_state >> i) & 0x01;
> +				switch (key_value) {
> +				case MSK_COMP:
> +					input_report_key(ts->input_dev,
> +						KEY_COMPOSE, key_pressed);
> +					break;
> +				case MSK_BACK:
> +					input_report_key(ts->input_dev,
> +						KEY_BACK, key_pressed);
> +					break;
> +				case MSK_MENU:
> +					input_report_key(ts->input_dev,
> +						KEY_MENU, key_pressed);
> +					break;
> +				case MSK_HOME:
> +					input_report_key(ts->input_dev,
> +						KEY_HOME, key_pressed);

I do not think you mean for the cursor to go to beginning of the
screen. All in all the set of events is unusual for a touchscreen.

> +					break;
> +				case MSK_NOBTN:
> +					/*Release the button if it touched.*/
> +				default:
> +					break;
> +				}
> +			}
> +		}
> +		TPInfo->pre_keybit_state = keybit_state;
> +	}
> +}
> +#endif
> +
> +static void sis_ts_work_func(struct work_struct *work)
> +{
> +	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
> +	int ret = SIS_ERR;
> +	int point_unit;
> +	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
> +	uint8_t i = 0, fingers = 0;
> +	uint8_t px = 0, py = 0, pstatus = 0;
> +	uint8_t p_area = 0;
> +	uint8_t p_preasure = 0;
> +	bool all_touch_up = true;
> +
> +	mutex_lock(&ts->mutex_wq);
> +    /* I2C or SMBUS block data read */
> +	ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
> +	/*Error Number*/
> +	if (ret < 0)
> +		goto err_free_allocate;
> +	/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +	else if (ret == 0) {
> +		fingers = 0;
> +		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +		goto label_send_report;
> +		/*need to report input_mt_sync()*/
> +	}
> +	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +
> +	/*Parser and Get the sis9200 data*/
> +	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
> +	fingers = ret;
> +
> +	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
> +
> +	/*fingers 10 =  0 ~ 9*/
> +	for (i = 0; i < fingers; i++) {
> +		if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5)) {
> +			/*Calc point status*/
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ ((i - 5) * point_unit);
> +			pstatus += 64;
> +		} else {
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ (i * point_unit);
> +					/*Calc point status*/
> +		}
> +	    px = pstatus + 2;	/*Calc point x_coord*/
> +	    py = px + 2;	/*Calc point y_coord*/
> +		if ((buf[pstatus]) == TOUCHUP) {
> +			TPInfo->pt[i].Width = 0;
> +			TPInfo->pt[i].Height = 0;
> +			TPInfo->pt[i].Pressure = 0;
> +		} else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE
> +					&& (buf[pstatus]) == TOUCHDOWN) {
> +			TPInfo->pt[i].Width = 1;
> +			TPInfo->pt[i].Height = 1;
> +			TPInfo->pt[i].Pressure = 1;
> +		} else if ((buf[pstatus]) == TOUCHDOWN) {
> +			p_area = py + 2;
> +			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
> +			/*area*/
> +			if (IS_AREA(buf[P_REPORT_ID])) {
> +				TPInfo->pt[i].Width = buf[p_area];
> +				TPInfo->pt[i].Height = buf[p_area + 1];
> +			} else {
> +				TPInfo->pt[i].Width = 1;
> +				TPInfo->pt[i].Height = 1;
> +			}
> +			/*preasure*/
> +			if (IS_PRESSURE(buf[P_REPORT_ID]))
> +				TPInfo->pt[i].Pressure = (buf[p_preasure]);
> +			else
> +				TPInfo->pt[i].Pressure = 1;
> +		} else {
> +			pr_err("sis_ts_work_func: Error Touch Status\n");
> +			goto err_free_allocate;
> +		}
> +		TPInfo->pt[i].id = (buf[pstatus + 1]);
> +		TPInfo->pt[i].x = le16_to_cpu(get_unaligned_le16(&buf[px]));
> +		TPInfo->pt[i].y = le16_to_cpu(get_unaligned_le16(&buf[py]));
> +	}
> +
> +#ifdef _DEBUG_REPORT
> +	for (i = 0; i < TPInfo->fingers; i++)
> +		pr_info("chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d\n",
> +		i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y,
> +		buf[pstatus], TPInfo->pt[i].Width, TPInfo->pt[i].Height,
> +		TPInfo->pt[i].Pressure);
> +#endif
> +label_send_report:
> +/* Report co-ordinates to the multi-touch stack */
> +	for (i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++) {
> +		if (TPInfo->pt[i].Pressure) {
> +			TPInfo->pt[i].Width *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +							TPInfo->pt[i].Width);
> +			TPInfo->pt[i].Height *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +							TPInfo->pt[i].Height);
> +			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
> +							TPInfo->pt[i].Pressure);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
> +							TPInfo->pt[i].x);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
> +							TPInfo->pt[i].y);
> +			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
> +							TPInfo->pt[i].id);
> +			/*Android 2.3*/

Huh?

> +			input_mt_sync(ts->input_dev);
> +			all_touch_up = false;

We need slotted MT-B protocol for new drivers, not MT-A.

> +		}
> +		if (i == (TPInfo->fingers - 1) && all_touch_up == true)
> +			input_mt_sync(ts->input_dev);
> +	}
> +	if (TPInfo->fingers == 0)
> +		input_mt_sync(ts->input_dev);
> +	input_sync(ts->input_dev);
> +
> +err_free_allocate:
> +
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1	/*case 1 mode*/
> +		/*TODO: After interrupt status low,
> +		 * read i2c bus data by polling,
> +		 * until interrupt status is high*/
> +		ret =  gpio_get_value(GPIO_IRQ);
> +		/*interrupt pin is still LOW,
> +		 * read data until interrupt pin is released.*/
> +		if (!ret)
> +			hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS),
> +						HRTIMER_MODE_REL);
> +		else {
> +			if (TPInfo->pre_keybit_state)
> +				/*clear for interrupt*/
> +				ts_report_key(ts->client, 0x0);
> +
> +			if (irqd_irq_disabled(&ts->desc->irq_data))
> +				enable_irq(ts->client->irq);
> +		}
> +#else /*case 2 mode*/
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(ts->client->irq);
> +#endif
> +	}
> +
> +	mutex_unlock(&ts->mutex_wq);
> +}
> +
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
> +{
> +	int i = 0;
> +
> +	for (i = 0; i < max; i++) {
> +		TPInfo->pt[i].id = -1;
> +		TPInfo->pt[i].x = 0;
> +		TPInfo->pt[i].y = 0;
> +		TPInfo->pt[i].Pressure = 0;
> +		TPInfo->pt[i].Width = 0;
> +	}
> +	TPInfo->id = 0x0;
> +	TPInfo->fingers = 0;
> +}
> +
> +static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
> +{
> +	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
> +
> +	queue_work(sis_wq, &ts->work);
> +	if (!ts->use_irq)	/*For Polling mode*/
> +	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	return HRTIMER_NORESTART;
> +}
> +
> +static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
> +{
> +	struct sis_ts_data *ts = dev_id;
> +
> +	if (!irqd_irq_disabled(&ts->desc->irq_data))
> +		disable_irq_nosync(ts->client->irq);
> +	queue_work(sis_wq, &ts->work);
> +	return IRQ_HANDLED;
> +}
> +
> +static int initial_irq(void)
> +{
> +	int ret = 0;
> +#ifdef _I2C_INT_ENABLE
> +	/* initialize gpio and interrupt pins */
> +	/*ex. GPIO_133 for interrupt mode*/
> +	ret = gpio_request(GPIO_IRQ, "GPIO_133");
> +	if (ret < 0) {
> +		/*Set Active Low.
> +		 * Please reference the file include/linux/interrupt.h*/
> +		pr_err("sis_ts_probe: Failed to gpio_request\n");
> +		pr_err("sis_ts_probe: Fail : gpio_request was called before this driver call\n");
> +	}
> +	/* setting gpio direction here OR boardinfo file*/
> +
> +#else
> +	ret = SIS_ERR;
> +#endif
> +	return ret;
> +}
> +
> +/*static uint16_t cal_crc_with_cmd(char *data, int start, int end, uint8_t cmd)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd) & 0x00FF];
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ data[i]) & 0x00FF];
> +	return crc;
> +}*/
> +
> +/*static void write_crc(unsigned char *buf, int start, int end)
> +{
> +	uint16_t crc = 0;
> +
> +	crc = cal_crc(buf, start , end);
> +	buf[end+1] = (crc >> 8) & 0xff;
> +	buf[end+2] = crc & 0xff;
> +}*/

Why do we need this commented out code? Please do clean up the code from
old cruft, debugging bits, etc, etc.

> +
> +#ifdef _STD_RW_IO
> +#define BUFFER_SIZE MAX_BYTE
> +static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +	char cmd;
> +
> +	pr_info("sis_cdev_write.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +
> +	cmd = kdata[6];
> +
> +/*Write & Read*/
> +	ret = sis_command_for_write(ts_bak->client, count, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer write error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +	if (copy_to_user((char *) buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +/*for get system time*/
> +static ssize_t sis_cdev_read(struct file *file, char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +
> +	pr_info("sis_cdev_read.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +	/*Write & Read*/
> +	ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +
> +	ret = le16_to_cpu(get_unaligned_le16(kdata));
> +
> +	/*{
> +		int i;
> +
> +		pr_info("ret=%d\n", ret);
> +		for (i = 0; i < ret && i < BUFFER_SIZE; i++)
> +			pr_info("%02x ", kdata[i]);
> +		pr_info("\n");
> +	}*/
> +
> +	if (copy_to_user((char *)buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_open.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	if (ts_bak->use_irq) {
> +		if (!irqd_irq_disabled(&ts_bak->desc->irq_data))
> +			disable_irq(ts_bak->client->irq);
> +		else {
> +			pr_info("sis_cdev_open: IRQ_STATUS: %x\n",
> +			irqd_irq_disabled(&ts_bak->desc->irq_data));
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +	return 0;	/*success*/
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_release.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	if (ts_bak->use_irq) {
> +		if (irqd_irq_disabled(&ts_bak->desc->irq_data))
> +			enable_irq(ts_bak->client->irq);
> +	} else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0),
> +					HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release	= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int ret = 0;
> +	struct device *class_dev = NULL;
> +
> +	pr_info("sis_setup_chardev.\n");
> +	if (ts == NULL)
> +		return -ENOMEM;
> +
> +	/*dynamic allocate driver handle*/
> +	ret = alloc_chrdev_region(&dev, 0,
> +				sis_char_devs_count, DEVICE_NAME);
> +	if (ret)
> +		return ret;
> +
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	ret = cdev_add(&sis_char_cdev, dev, sis_char_devs_count);
> +	if (ret)
> +		goto err1;
> +
> +	pr_info("%s driver(major %d) installed.\n",
> +			DEVICE_NAME, sis_char_major);
> +	/*register class*/
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if (IS_ERR(sis_char_class)) {
> +		ret = PTR_ERR(sis_char_class);
> +		goto err2;
> +	}
> +
> +	class_dev = device_create(sis_char_class, NULL, dev, NULL, DEVICE_NAME);
> +	if (IS_ERR(class_dev)) {
> +		ret = PTR_ERR(class_dev);
> +		goto err3;
> +	}
> +
> +	return 0;
> +err3:
> +	class_destroy(sis_char_class);
> +	sis_char_class = NULL;
> +err2:
> +	cdev_del(&sis_char_cdev);
> +	memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +err1:
> +	sis_char_major = 0;
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	return ret;
> +}
> +
> +static void sis_deinit_chardev(void)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +
> +	if (sis_char_class) {
> +		pr_info("sis_deinit_chardev\n");
> +		device_destroy(sis_char_class, dev);
> +		class_destroy(sis_char_class);
> +		sis_char_class = NULL;
> +		cdev_del(&sis_char_cdev);
> +		memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +		sis_char_major = 0;
> +		unregister_chrdev_region(dev, sis_char_devs_count);
> +	}
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +	pr_info("sis_ts_probe\n");
> +	TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +	if (TPInfo == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts_bak = ts;
> +	mutex_init(&ts->mutex_wq);
> +	/*1. Init Work queue and necessary buffers*/
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +	pdata = client->dev.platform_data;
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0) {
> +			pr_err("sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +	/*2. Allocate input device*/
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) {
> +		ret = -ENOMEM;
> +		pr_err("sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +	/*This input device name should be the same to IDC file name.*/
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +	set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +	set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +	set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,
> +						0, PRESSURE_MAX, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +						0, AREA_LENGTH_LONGER, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +						0, AREA_LENGTH_SHORT, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
> +						0, SIS_MAX_X, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
> +						0, SIS_MAX_Y, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
> +						0, 15, 0, 0);
> +	/* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +	/*3. Register input device to core*/
> +	ret = input_register_device(ts->input_dev);
> +	if (ret) {
> +		pr_err("sis_ts_probe: Unable to register %s input device\n",
> +				ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	/*4. irq or timer setup*/
> +	ret = initial_irq();
> +	if (ret >= 0) {
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler,
> +					IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0)
> +			ts->use_irq = 1;
> +		else
> +			dev_err(&client->dev, "request_irq failed\n");
> +	}
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +	if (!ts->use_irq)
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	pr_info("sis_ts_probe: Start touchscreen %s in %s mode\n",
> +			ts->input_dev->name,
> +			ts->use_irq ? "interrupt" : "polling");
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1
> +		pr_info("sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		pr_info("sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if (ret)
> +		pr_err("sis_setup_chardev fail\n");
> +#endif
> +	pr_info("sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +	return 0;
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);
> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +#ifdef _STD_RW_IO
> +	sis_deinit_chardev();
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq) {
> +		if (!irqd_irq_disabled(&ts->desc->irq_data))
> +			disable_irq(client->irq);
> +	} else
> +		hrtimer_cancel(&ts->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			pr_err("sis_ts_suspend power off failed\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			pr_err("sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq) {
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(client->irq);
> +	} else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_suspend(ts->client, PMSG_SUSPEND);
> +}
> +
> +static void sis_ts_late_resume(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_resume(ts->client);
> +}
> +#endif
> +
> +#ifdef CONFIG_X86
> +/* Return 0 if detection is successful, -ENODEV otherwise */
> +static int sis_ts_detect(struct i2c_client *client,
> +		       struct i2c_board_info *info)
> +{
> +	const char *type_name;
> +
> +	pr_info("sis_ts_detect\n");
> +	type_name = "sis_i2c_ts";
> +	strlcpy(info->type, type_name, I2C_NAME_SIZE);
> +	return 0;
> +}
> +#endif
> +
> +static const struct i2c_device_id sis_ts_id[] = {
> +	{ SIS_I2C_NAME, 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, sis_ts_id);
> +
> +static struct i2c_driver sis_ts_driver = {
> +	.probe		= sis_ts_probe,
> +	.remove		= sis_ts_remove,
> +#ifndef CONFIG_HAS_EARLYSUSPEND
> +	.suspend	= sis_ts_suspend,
> +	.resume		= sis_ts_resume,
> +#endif
> +#ifdef CONFIG_X86
> +	.class		= I2C_CLASS_HWMON,
> +	.detect		= sis_ts_detect,
> +	.address_list	= normal_i2c,
> +#endif
> +	.id_table	= sis_ts_id,
> +	.driver = {
> +		.name	= SIS_I2C_NAME,
> +	},
> +};
> +
> +static int __init sis_ts_init(void)
> +{
> +	pr_info("sis_ts_init\n");
> +	sis_wq = create_singlethread_workqueue("sis_wq");
> +
> +	if (!sis_wq)
> +		return -ENOMEM;
> +	return i2c_add_driver(&sis_ts_driver);
> +}
> +
> +static void __exit sis_ts_exit(void)
> +{
> +	pr_info("sis_ts_exit\n");
> +	i2c_del_driver(&sis_ts_driver);
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +}
> +
> +module_init(sis_ts_init);
> +module_exit(sis_ts_exit);
> +MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> new file mode 100644
> index 0000000..7639a52
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> @@ -0,0 +1,173 @@
> +/*
> + * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * Date: 2015/01/15
> + * Version:	Android_v2.05.00-A639-1113
> + */
> +#include <linux/version.h>
> +
> +#ifndef _LINUX_SIS_I2C_H
> +#define _LINUX_SIS_I2C_H
> +
> +
> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +/*10ms*/
> +#define TIMER_NS						10000000
> +#define MAX_FINGERS						10
> +
> +/* For standard R/W IO ( SiS firmware application )*/
> +#define _STD_RW_IO						/*ON/OFF*/
> +
> +/* Check data CRC */
> +/*#define _CHECK_CRC*/						/*ON/OFF*/
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					/*ON/OFF*/
> +#define GPIO_IRQ						133
> +
> +/*	Enable if use interrupt case 1 mode.	*/
> +/*	Disable if use interrupt case 2 mode.	*/
> +/*#define _INT_MODE_1*/					/*ON/OFF*/
> +
> +/* Resolution mode */
> +/*Constant value*/
> +#define SIS_MAX_X						4095
> +#define SIS_MAX_Y						4095
> +
> +#define ONE_BYTE						1
> +#define FIVE_BYTE						5
> +#define EIGHT_BYTE						8
> +#define SIXTEEN_BYTE					16
> +#define PACKET_BUFFER_SIZE				128
> +
> +#define SIS_CMD_NORMAL					0x0
> +#define SIS_CMD_SOFTRESET				0x82
> +#define SIS_CMD_RECALIBRATE				0x87
> +#define SIS_CMD_POWERMODE				0x90
> +#define MSK_TOUCHNUM					0x0f
> +#define MSK_HAS_CRC						0x10
> +#define MSK_DATAFMT						0xe0
> +#define MSK_PSTATE						0x0f
> +#define MSK_PID							0xf0
> +#define RES_FMT							0x00
> +#define FIX_FMT							0x40
> +
> +/* for new i2c format */
> +#define TOUCHDOWN						0x3
> +#define TOUCHUP							0x0
> +#define MAX_BYTE						64
> +#define	PRESSURE_MAX					255
> +
> +/*Resolution diagonal */
> +#define AREA_LENGTH_LONGER				5792
> +/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
> +#define AREA_LENGTH_SHORT				5792
> +#define AREA_UNIT						(5792/32)
> +
> +
> +#define FORMAT_MODE						1
> +
> +#define MSK_NOBTN						0
> +#define MSK_COMP						1
> +#define MSK_BACK						2
> +#define MSK_MENU						4
> +#define MSK_HOME						8
> +
> +#define P_BYTECOUNT						0
> +#define ALL_IN_ONE_PACKAGE				0x10
> +#define IS_TOUCH(x)						(x & 0x1)
> +#define IS_HIDI2C(x)					((x & 0xF) == 0x06)
> +#define IS_AREA(x)						((x >> 4) & 0x1)
> +#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
> +#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
> +/*#define _DEBUG_PACKAGE*/				/*ON/OFF*/
> +/*#define _DEBUG_REPORT*/				/*ON/OFF*/
> +#define NORMAL_LEN_PER_POINT			6
> +#define AREA_LEN_PER_POINT				2
> +#define PRESSURE_LEN_PER_POINT			1
> +
> +#define TOUCH_FORMAT					0x1
> +#define BUTTON_FORMAT					0x4
> +#define HIDI2C_FORMAT					0x6
> +#define P_REPORT_ID						2
> +#define BUTTON_STATE					3
> +#define BUTTON_KEY_COUNT				16
> +#define BYTE_BYTECOUNT					2
> +#define BYTE_COUNT						1
> +#define BYTE_ReportID					1
> +#define BYTE_CRC_HIDI2C					0
> +#define BYTE_CRC_I2C					2
> +#define BYTE_SCANTIME					2
> +#define NO_TOUCH_BYTECOUNT				0x3
> +
> +/* TODO */
> +#define TOUCH_POWER_PIN					0
> +#define TOUCH_RESET_PIN					1
> +
> +/* CMD Define */
> +#define BUF_ACK_PLACE_L					4
> +#define BUF_ACK_PLACE_H					5
> +#define BUF_ACK_L						0xEF
> +#define BUF_ACK_H						0xBE
> +#define BUF_NACK_L						0xAD
> +#define BUF_NACK_H						0xDE
> +#define BUF_CRC_PLACE					7
> +
> +/* SiS i2c error code */
> +#define SIS_ERR						-1
> +#define SIS_ERR_ACCESS_USER_MEM		-11 /* Access user memory fail */
> +#define SIS_ERR_ALLOCATE_KERNEL_MEM	-12 /* Allocate memory fail */
> +#define SIS_ERR_CLIENT				-13 /* Client not created */
> +#define SIS_ERR_COPY_FROM_USER		-14 /* Copy data from user fail */
> +#define SIS_ERR_COPY_FROM_KERNEL	-19 /* Copy data from kernel fail */
> +#define SIS_ERR_TRANSMIT_I2C		-21 /* Transmit error in I2C */
> +
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +struct Point {
> +	int id;
> +	unsigned short x, y;		/*uint16_t ?*/
> +	uint16_t Pressure;
> +	uint16_t Width;
> +	uint16_t Height;
> +};
> +
> +struct sisTP_driver_data {
> +	int id;
> +	int fingers;
> +	uint8_t pre_keybit_state;
> +	struct Point pt[MAX_FINGERS];
> +};
> +
> +struct sis_ts_data {
> +	int (*power)(int on);
> +	int use_irq;
> +	struct i2c_client *client;
> +	struct input_dev *input_dev;
> +	struct hrtimer timer;
> +	struct irq_desc *desc;
> +	struct work_struct work;
> +	struct mutex mutex_wq;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif
> +};
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
> +static int sis_ts_resume(struct i2c_client *client);
> +
> +#endif /* _LINUX_SIS_I2C_H */

Thanks.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
  2015-01-16 10:59         ` 曾婷葳 (tammy_tseng)
@ 2015-02-16 14:16           ` Oliver Neukum
  -1 siblings, 0 replies; 21+ messages in thread
From: Oliver Neukum @ 2015-02-16 14:16 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: linux-kernel, linux-input, tammy0524

On Fri, 2015-01-16 at 18:59 +0800, 曾婷葳 (tammy_tseng) wrote:
> Hey, Oliver
> 
> On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
> On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > > (Skip the code diff...)
> > 
> > Again macros for endianness
> > 
> > And the driver has a great number of conditional compilations are they 
> > really needed? The driver as is has a number of issues and is hard to 
> > review due to the use of "//" for comments and a lot of conditional 
> > compilation and unnecessary variables used for constants. Could you 
> > fix this up and resubmit?
> 
> Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
> Please help check them if anything needs to fix.
> Thanks.

You still have conditional compilation needlessly. You still haven't
addressed the issues I told you about during the review of the last
version.

	Oliver

> 
> Tammy
> 
> ---
> diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
> index e1d8003..401cd8b 100644
> --- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
> +++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
> @@ -962,4 +962,12 @@ config TOUCHSCREEN_ZFORCE
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called zforce_ts.
>  
> +config TOUCHSCREEN_SIS_I2C
> +	tristate "SiS 9200 family I2C touchscreen driver"
> +	depends on I2C
> +	default n
> +	help
> +	  This enables support for SiS 9200 family over I2C based touchscreens.
> +
> +
>  endif
> diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
> index 090e61c..67137af 100644
> --- a/linux-3.18.1/drivers/input/touchscreen/Makefile
> +++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
> @@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   	+= sis_i2c.o
> diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
> new file mode 100644
> index 0000000..157f991
> --- /dev/null
> +++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
> @@ -0,0 +1,1267 @@
> +/*
> + * SiS 9200 family I2C Touch Screen Controller Driver
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif
> +#include <linux/hrtimer.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include "sis_i2c.h"
> +#include <linux/linkage.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <asm/uaccess.h>
> +#include <linux/irq.h>
> +#include <asm/unaligned.h>
> +
> +#ifdef _STD_RW_IO
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#define DEVICE_NAME "sis_aegis_touch_device"
> +static int sis_char_devs_count = 1;        /* device count */
> +static int sis_char_major = 0;
> +static struct cdev sis_char_cdev;
> +static struct class *sis_char_class = NULL;
> +#endif
> +
> +/* Addresses to scan */
> +static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
> +static struct workqueue_struct *sis_wq;
> +struct sis_ts_data *ts_bak = 0;
> +struct sisTP_driver_data *TPInfo = NULL;
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h);
> +static void sis_ts_late_resume(struct early_suspend *h);
> +#endif
> +
> +#ifdef CONFIG_X86
> +/* static const struct i2c_client_address_data addr_data; */
> +/* Insmod parameters */
> +static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
> +#endif
> +
> +#ifdef _CHECK_CRC
> +uint16_t cal_crc (char* cmd, int start, int end);
> +#endif
> +
> +static void PrintBuffer(int start, int length, char* buf)
> +{
> +	int i;
> +	for ( i = start; i < length; i++ )
> +	{
> +		printk("%02x ", buf[i]);
> +		if (i != 0 && i % 30 == 0)
> +			printk("\n");
> +	}
> +	printk("\n");	
> +}
> +
> +int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
> +{
> +    int ret = -1;
> +    struct i2c_msg msg;
> +
> +    msg.addr = client->addr;
> +    /* Write */
> +    msg.flags = 0;
> +    msg.len = wlength;
> +    msg.buf = (unsigned char *)wdata;
> +
> +    ret = i2c_transfer(client->adapter, &msg, 1);
> +
> +    return ret;
> +}
> +
> +int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
> +{
> +    int ret = -1;
> +    struct i2c_msg msg;
> +
> +    msg.addr = client->addr;
> +    /* Read */
> +    msg.flags = I2C_M_RD;
> +    msg.len = rlength;
> +    msg.buf = rdata;
> +
> +    ret = i2c_transfer(client->adapter, &msg, 1);
> +
> +    return ret;
> +}
> +
> +int sis_cul_unit(uint8_t report_id)
> +{
> +	int ret = NORMAL_LEN_PER_POINT;
> +	
> +	if (report_id != ALL_IN_ONE_PACKAGE)
> +	{
> +		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
> +		{
> +			ret += AREA_LEN_PER_POINT;
> +		}
> +		if (IS_PRESSURE(report_id))
> +		{
> +			ret += PRESSURE_LEN_PER_POINT;
> +		}
> +	}
> +	
> +	return ret;	
> +}
> +
> +int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
> +{
> +	uint8_t tmpbuf[MAX_BYTE] = {0};
> +#ifdef _CHECK_CRC
> +	uint16_t buf_crc = 0;
> +	uint16_t package_crc = 0;
> +	int l_package_crc = 0;
> +	int crc_end = 0;
> +#endif
> +    int ret = -1;
> +    int touchnum = 0;
> +    int p_count = 0;
> +    int touc_formate_id = 0;
> +    int locate = 0;
> +    bool read_first = true;
> +    
> +/*
> +		New i2c format 
> +	* buf[0] = Low 8 bits of byte count value
> +	* buf[1] = High 8 bits of byte counte value
> +	* buf[2] = Report ID
> +	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
> +	* buf[touch num * 6 + 3] = Touch numbers
> +	* 
> +	* One touch point information include 6 bytes, the order is 
> +	* 
> +	* 1. status = touch down or touch up
> +	* 2. id = finger id 
> +	* 3. x axis low 8 bits
> +	* 4. x axis high 8 bits
> +	* 5. y axis low 8 bits
> +	* 6. y axis high 8 bits
> +	* 
> +*/
> +	do
> +	{
> +		if (locate >= PACKET_BUFFER_SIZE)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
> +			return -1;
> +		}
> +		
> +		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
> +
> +#ifdef _DEBUG_PACKAGE
> +		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
> +		PrintBuffer(0, 64, tmpbuf);	
> +#endif			
> +
> +		if(ret < 0 )
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
> +			return ret;
> +		}
> +		/* error package length of receiving data */
> +		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
> +			return -1;	
> +		}
> +		
> +		if (read_first)
> +		{
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +			/* access BUTTON TOUCH event and BUTTON NO TOUCH event */
> +			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
> +			{
> +				memcpy(&buf[0], &tmpbuf[0], 7);
> +				return 0; 	/* touchnum is 0 */
> +			}
> +#endif 
> +			/* access NO TOUCH event unless BUTTON NO TOUCH event */
> +			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
> +			{
> +				return 0;	/* touchnum is 0 */
> +			}
> +		}
> +
> +		/* skip parsing data when two devices are registered at the same slave address
> +		 * parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
> +		 */  
> +		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
> +		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
> +			return -1;		
> +		}
> +		
> +		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/* start from 0 */
> +		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
> +		{
> +			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_CRC_I2C;	/* delete 2 byte crc */
> +			}
> +			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_CRC_HIDI2C;
> +			}
> +			else	/* should not be happen */
> +			{
> +				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
> +				return -1;
> +			}
> +
> +			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_SCANTIME;
> +			}
> +		}
> +		/* else {}    						 For ALL_IN_ONE_PACKAGE */
> +		
> +		if (read_first)
> +		{
> +			touchnum = tmpbuf[p_count]; 	
> +		}
> +		else
> +		{
> +			if (tmpbuf[p_count] != 0)
> +			{
> +				printk(KERN_ERR "sis_ReadPacket: get error package\n");
> +				return -1;
> +			}
> +		}
> +
> +#ifdef _CHECK_CRC
> +		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
> +		buf_crc = cal_crc(tmpbuf, 2, crc_end); /* sub bytecount (2 byte) */
> +		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
> +		package_crc = get_unaligned_le16(&tmpbuf[l_package_crc]);
> +			
> +		if (buf_crc != package_crc)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
> +			return -1;
> +		}
> +#endif	
> +		memcpy(&buf[locate], &tmpbuf[0], 64);	/* Buf_Data [0~63] [64~128] */
> +		locate += 64;
> +		read_first = false;
> +		
> +	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
> +
> +	return touchnum;
> +}	
> +
> +
> +int check_gpio_interrupt(void)
> +{
> +    int ret = 0;
> +
> +    /* CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING. */
> +    ret = gpio_get_value(GPIO_IRQ);
> +	
> +    return ret;
> +}
> +
> +void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
> +{
> +	int i = 0;
> +	uint8_t diff_keybit_state= 0x0; /* check keybit_state is difference with pre_keybit_state */
> +	uint8_t key_value = 0x0; 		/* button location for binary */
> +	uint8_t  key_pressed = 0x0; 	/* button is up or down */
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (!ts)
> +	{
> +		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
> +		return;
> +	}
> +
> +	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
> +
> +	if (diff_keybit_state)
> +	{
> +		for (i = 0; i < BUTTON_KEY_COUNT; i++)
> +		{
> +		    if ((diff_keybit_state >> i) & 0x01)
> +			{
> +				key_value = diff_keybit_state & (0x01 << i);
> +				key_pressed = (keybit_state >> i) & 0x01;
> +				switch (key_value)
> +				{
> +					case MSK_COMP:
> +						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
> +						break;
> +					case MSK_BACK:
> +						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
> +						break;
> +					case MSK_MENU:
> +						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
> +						break;
> +					case MSK_HOME:
> +						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
> +						break;
> +					case MSK_NOBTN:
> +						/* Release the button if it touched. */
> +					default:
> +						break;
> +				}
> +			}
> +		}
> +		TPInfo->pre_keybit_state = keybit_state;
> +	}
> +}
> +
> +
> +static void sis_ts_work_func(struct work_struct *work)
> +{
> +	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
> +    int ret = -1;
> +    int point_unit;  
> +	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
> +	uint8_t i = 0, fingers = 0;
> +	uint8_t px = 0, py = 0, pstatus = 0;
> +	uint8_t p_area = 0;
> +    uint8_t p_preasure = 0;
> +#ifdef _SUPPORT_BUTTON_TOUCH	
> +	int button_key;
> +	uint8_t button_buf[10] = {0};
> +#endif
> +
> +#ifdef _ANDROID_4
> +	bool all_touch_up = true;
> +#endif
> +	
> +	mutex_lock(&ts->mutex_wq); 
> +
> +    /* I2C or SMBUS block data read */
> +    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
> + 
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
> +#endif
> +
> +	/* Error Number */
> +	if (ret < 0) 
> +	{
> +		goto err_free_allocate;
> +	}
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +	/* access BUTTON TOUCH event and BUTTON NO TOUCH even */
> +	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
> +	{
> +		button_key = get_unaligned_le16(&button_buf[BUTTON_STATE]);		
> +		ts_report_key(ts->client, button_key);
> +	}
> +#endif
> +	/* access NO TOUCH event unless BUTTON NO TOUCH event */
> +	else if (ret == 0)
> +	{
> +		fingers = 0;
> +		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +		goto label_send_report;  /* need to report input_mt_sync() */
> +	}
> +	
> +	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +	
> +	/* Parser and Get the sis9200 data */
> +	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
> +	fingers = ret;
> +	
> +	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
> +	
> +	/* fingers 10 =  0 ~ 9 */
> +	for (i = 0; i < fingers; i++) 
> +	{
> +        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
> +        { /* Calc point status */
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	
> +			pstatus += 64;
> +		}
> +		else 
> +		{ /* Calc point status */
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	
> +		}
> +
> +	    px = pstatus + 2;	/* Calc point x_coord */
> +	    py = px + 2;		/* Calc point y_coord */
> +
> +		if ((buf[pstatus]) == TOUCHUP)
> +		{
> +			TPInfo->pt[i].Width = 0;
> +			TPInfo->pt[i].Height = 0;
> +			TPInfo->pt[i].Pressure = 0;
> +		}
> +		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
> +		{
> +			TPInfo->pt[i].Width = 1;
> +			TPInfo->pt[i].Height = 1;
> +			TPInfo->pt[i].Pressure = 1;			
> +		}
> +		else if ((buf[pstatus]) == TOUCHDOWN)
> +		{	
> +			p_area = py + 2;
> +			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
> +
> +			/* area */
> +			if (IS_AREA(buf[P_REPORT_ID]))
> +			{
> +				TPInfo->pt[i].Width = buf[p_area] & 0xff;
> +				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
> +			}
> +			else 
> +			{
> +				TPInfo->pt[i].Width = 1;
> +				TPInfo->pt[i].Height = 1;
> +			}
> +			/* preasure */
> +			if (IS_PRESSURE(buf[P_REPORT_ID]))
> +				TPInfo->pt[i].Pressure = (buf[p_preasure]);
> +			else 
> +				TPInfo->pt[i].Pressure = 1;				
> +		}
> +		else
> +		{
> +			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
> +			goto err_free_allocate;
> +		}
> +		
> +		TPInfo->pt[i].id = (buf[pstatus + 1]);
> +		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
> +        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));   

Please use the macros for endianness conversion.

>    
> +	}
> +		
> +#ifdef _DEBUG_REPORT
> +	for (i = 0; i < TPInfo->fingers; i++)
> +	{
> +		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
> +	}
> +#endif
> +
> +label_send_report:
> +/* Report co-ordinates to the multi-touch stack */
> +#ifdef _ANDROID_4	
> +	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
> +	{
> +		if(TPInfo->pt[i].Pressure)
> +		{
> +			TPInfo->pt[i].Width *= AREA_UNIT;	
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
> +			TPInfo->pt[i].Height *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
> +			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
> +			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);
> +			input_mt_sync(ts->input_dev);
> +			all_touch_up = false;
> +		}
> +		
> +		if (i == (TPInfo->fingers -1) && all_touch_up == true)
> +		{
> +			input_mt_sync(ts->input_dev);
> +		}
> +	}
> +
> +	if(TPInfo->fingers == 0)
> +	{
> +		input_mt_sync(ts->input_dev);
> +	}
> +#else
> +	i = 0;
> +	do
> +	{
> +		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
> +		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
> +		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
> +		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
> +		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
> +		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id); /* Android 2.3 */
> +		input_mt_sync(ts->input_dev);
> +		i++;
> +	}
> +	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
> +#endif
> +	input_sync(ts->input_dev);
> +
> +err_free_allocate:
> +
> +    if (ts->use_irq)
> +    {
> +/* case 1 mode */
> +#ifdef _INT_MODE_1 
> +	    /*TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high */
> +	    ret = check_gpio_interrupt();	/* interrupt pin is still LOW, read data until interrupt pin is released. */
> +	    if (!ret)
> +	    {
> +	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	    }
> +	    else
> +	    {
> +			if (TPInfo->pre_keybit_state)
> +			{
> +				ts_report_key(ts->client, 0x0);	/* clear for interrupt */
> +			}
> +			
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +        	{
> +				enable_irq(ts->client->irq);
> +			}
> +	    }
> +/* case 2 mode */
> +#else
> +
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +		{
> +			enable_irq(ts->client->irq);
> +		}
> +#endif
> +	}
> +
> +	mutex_unlock(&ts->mutex_wq);
> +    return;
> +}
> +
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
> +{
> +	int i = 0;
> +	for(i = 0; i < max; i++)
> +	{
> +		TPInfo->pt[i].id = -1;
> +		TPInfo->pt[i].x = 0;
> +		TPInfo->pt[i].y = 0;
> +		TPInfo->pt[i].Pressure = 0;
> +		TPInfo->pt[i].Width = 0;
> +	}
> +	TPInfo->id = 0x0;
> +	TPInfo->fingers = 0;
> +}
> +
> +static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
> +{
> +	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
> +	queue_work(sis_wq, &ts->work);
> +	if (!ts->use_irq)
> +	{	/* For Polling mode */
> +	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	}
> +	return HRTIMER_NORESTART;
> +}
> +
> +static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
> +{
> +	struct sis_ts_data *ts = dev_id;
> +	
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif
> +	{
> +		disable_irq_nosync(ts->client->irq);
> +	}
> +	queue_work(sis_wq, &ts->work);
> +		
> +	return IRQ_HANDLED;
> +}
> +
> +static int initial_irq(void)
> +{
> +	int ret = 0;
> +#ifdef _I2C_INT_ENABLE
> +	/* initialize gpio and interrupt pins */
> +	ret = gpio_request(GPIO_IRQ, "GPIO_133");	/* ex. GPIO_133 for interrupt mode */
> +	if (ret < 0)
> +	{
> +		/* Set Active Low. Please reference the file include/linux/interrupt.h */
> +	}
> +	/* setting gpio direction here OR boardinfo file*/
> +
> +#else
> +	ret = -1;
> +#endif
> +	return ret;
> +}
> +
> +uint16_t cal_crc (char* cmd, int start, int end)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +	
> +	for (i = start; i <= end ; i++)
> +	{
> +		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
> +	}
> +	
> +	return crc;
> +}

How about making this CRC generally available?
> +
> +uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +	
> +	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
> +	for (i = start; i <= end ; i++)
> +	{
> +		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
> +	}
> +	
> +	return crc;
> +}
> +
> +void write_crc (unsigned char *buf, int start, int end)
> +{
> +	uint16_t crc = 0;
> +	
> +	crc = cal_crc (buf, start , end);
> +	buf[end+1] = (crc >> 8)& 0xff;
> +	buf[end+2] = crc & 0xff;

Please use the macro

> +}
> +
> +#ifdef _STD_RW_IO
> +#define BUFFER_SIZE MAX_BYTE
> +static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
> +{
> +	 int ret = 0;
> +	 char *kdata;
> +	 char cmd;
> +	 
> +	 printk(KERN_INFO "sis_cdev_write.\n");
> +	 
> +	 if (ts_bak == 0)
> +    	return -13;

You _must_ use symbolic values.

> +    	
> +    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +    if (!ret) {
> +        printk(KERN_ERR "cannot access user space memory\n");
> +        return -11;
> +    }
> +
> +	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +     if (kdata == 0)
> +    	return -12;
> +    	
> +     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +     if (ret) {
> +        printk(KERN_ERR "copy_from_user fail\n");
> +        kfree(kdata);
> +        return -14;
> +     } 
> +#if 0
> +	PrintBuffer(0, count, kdata);
> +#endif
> +		
> +	cmd = kdata[6];
> +
> +/* Write & Read */
> +    ret = sis_command_for_write(ts_bak->client, count, kdata);
> +    if (ret < 0) {
> +        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
> +		kfree(kdata);
> +		return -21;
> +	}
> +
> +    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +    {
> +        printk(KERN_ERR "copy_to_user fail\n" );
> +        ret = -19;
> +    }
> +
> +    kfree( kdata );
> +
> +	return ret;
> +}
> +
> +/* for get system time */
> +static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
> +{
> +	 int ret = 0;
> +	 char *kdata;
> +	 char cmd;
> +	 int i;
> +	 
> +	 printk(KERN_INFO "sis_cdev_read.\n");
> +	 
> +	 if (ts_bak == 0)
> +    	return -13;
> +    	
> +    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +    if (!ret) {
> +        printk(KERN_ERR "cannot access user space memory\n");
> +        return -11;
> +    }
> +
> +	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +     if (kdata == 0)
> +    	return -12;
> +    	
> +     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +     if (ret) {
> +        printk(KERN_ERR "copy_from_user fail\n");
> +        kfree(kdata);
> +        return -14;
> +     }    
> +#if 0
> +    PrintBuffer(0, count, kdata);
> +#endif
> +	 cmd = kdata[6];
> +	 /* for making sure AP communicates with SiS driver */
> +    if(cmd == 0xa2)
> +    {
> +		kdata[0] = 5;
> +		kdata[1] = 0;
> +		kdata[3] = 'S';
> +		kdata[4] = 'i';
> +		kdata[5] = 'S';
> +		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +		{
> +			printk(KERN_ERR "copy_to_user fail\n" );
> +			kfree( kdata );
> +			return -19;
> +		}
> +
> +		kfree( kdata );
> +		return 3;	
> +	}
> +/* Write & Read */
> +    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +    if (ret < 0) {
> +        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return -21;
> +	}
> +
> +	ret = kdata[0] | (kdata[1] << 8);
> +
> +    printk(KERN_INFO "%d\n", ret);
> +
> +    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
> +    {
> +        printk("%02x ", kdata[i]);
> +    }
> +
> +    printk( "\n" );
> +
> +    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +    {
> +        printk(KERN_ERR "copy_to_user fail\n" );
> +        ret = -19;
> +    }
> +
> +    kfree( kdata );
> +
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_open.\n");
> +	if ( ts_bak == 0 )
> +    	return -13;
> +
> +	msleep(200);
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif	
> +		{
> +			disable_irq(ts_bak->client->irq);
> +		}
> +		else
> +		{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
> +#else
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
> +#endif	
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   
> +    
> +    msleep(200);
> +
> +	return 0; /* success */
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_release.\n");
> +	
> +	msleep(200);
> +	
> +    if (ts_bak == 0)
> +    	return -13;
> +
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif	
> +		{
> +			enable_irq(ts_bak->client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +    return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int alloc_ret = 0;
> +	int cdev_err = 0;
> +	int input_err = 0;
> +	struct device *class_dev = NULL;
> +	void *ptr_err;
> +	
> +	printk("sis_setup_chardev.\n");
> +	
> +	if (ts == NULL) 
> +	{
> +	  input_err = -ENOMEM;
> +	  goto error;
> +	} 
> +	/* dynamic allocate driver handle */
> +	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
> +	if (alloc_ret)
> +		goto error;
> +		
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	
> +	if (cdev_err) 
> +		goto error;
> +	
> +	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
> +	
> +	/* register class */
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if(IS_ERR(ptr_err = sis_char_class)) 
> +	{
> +		goto err2;
> +	}
> +	
> +	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
> +	
> +	if(IS_ERR(ptr_err = class_dev)) 
> +	{
> +		goto err;
> +	}
> +	
> +	return 0;
> +error:
> +	if (cdev_err == 0)
> +		cdev_del(&sis_char_cdev);
> +	if (alloc_ret == 0)
> +		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	if(input_err != 0)
> +	{
> +		printk("sis_ts_bak error!\n");
> +	}
> +err:
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +err2:
> +	class_destroy(sis_char_class);
> +	return -1;
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +    printk(KERN_INFO "sis_ts_probe\n");
> +
> +    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +    if (TPInfo == NULL) 
> +    {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts_bak = ts;
> +
> +	mutex_init(&ts->mutex_wq);
> +	
> +	/* 1. Init Work queue and necessary buffers */
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +    pdata = client->dev.platform_data;
> +
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) 
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0) 
> +		{
> +			printk(KERN_ERR "sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +
> +	/* 2. Allocate input device */
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +
> +	/* This input device name should be the same to IDC file name. */
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +
> +#ifdef _ANDROID_4
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
> +#else
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
> +#endif
> +
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
> +	
> +    /* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +
> +	/* 3. Register input device to core */
> +	ret = input_register_device(ts->input_dev);
> +
> +	if (ret) 
> +	{
> +		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	
> +	/* 4. irq or timer setup */
> +	ret = initial_irq();
> +	if (ret < 0) 
> +	{
> +
> +	}
> +	else
> +	{
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0) 
> +		{
> +		   ts->use_irq = 1;
> +		}
> +		else 
> +		{
> +			dev_err(&client->dev, "request_irq failed\n");
> +		}
> +	}
> +
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +
> +	if (!ts->use_irq) 
> +	{
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
> +	
> +	if (ts->use_irq)
> +	{
> +#ifdef _INT_MODE_1
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +	
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if(ret)
> +	{
> +		printk( KERN_INFO"sis_setup_chardev fail\n");
> +	}
> +#endif
> +
> +	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +
> +	return 0;
> +
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);
> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +	
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif
> +		{
> +			disable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   		
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_suspend power off failed\n");
> +	}
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power)
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +		{
> +			enable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +	
> +	TPInfo->pre_keybit_state = 0x0;
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_suspend(ts->client, PMSG_SUSPEND);
> +}
> +
> +static void sis_ts_late_resume(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +	
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_resume(ts->client);
> +}
> +#endif
> +
> +static const struct i2c_device_id sis_ts_id[] = {
> +	{ SIS_I2C_NAME, 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, sis_ts_id);
> +
> +static struct i2c_driver sis_ts_driver = {
> +	.probe		= sis_ts_probe,
> +	.remove		= sis_ts_remove,
> +#ifndef CONFIG_HAS_EARLYSUSPEND
> +	.suspend	= sis_ts_suspend,
> +	.resume		= sis_ts_resume,
> +#endif
> +#ifdef CONFIG_X86
> +    .class      = I2C_CLASS_HWMON,
> +    .detect		= sis_ts_detect,
> +	.address_list	= normal_i2c,
> +#endif
> +	.id_table	= sis_ts_id,
> +	.driver = {
> +		.name	= SIS_I2C_NAME,
> +	},
> +};
> +
> +static int __init sis_ts_init(void)
> +{
> +	printk( KERN_INFO "sis_ts_init\n" );
> +	
> +	sis_wq = create_singlethread_workqueue("sis_wq");
> +
> +	if (!sis_wq)
> +		return -ENOMEM;
> +		
> +	return i2c_add_driver(&sis_ts_driver);
> +}
> +
> +#ifdef CONFIG_X86
> +/* Return 0 if detection is successful, -ENODEV otherwise */
> +static int sis_ts_detect(struct i2c_client *client,
> +		       struct i2c_board_info *info)
> +{
> +	const char *type_name;
> +	
> +    printk(KERN_INFO "sis_ts_detect\n");
> +	
> +	type_name = "sis_i2c_ts";
> +	strlcpy(info->type, type_name, I2C_NAME_SIZE);
> +	
> +	return 0;
> +}
> +#endif
> +
> +static void __exit sis_ts_exit(void)
> +{
> +#ifdef _STD_RW_IO
> +	dev_t dev;
> +#endif
> +
> +	printk(KERN_INFO "sis_ts_exit\n");
> +	
> +	i2c_del_driver(&sis_ts_driver);
> +	
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +
> +#ifdef _STD_RW_IO
> +	dev = MKDEV(sis_char_major, 0);
> +	cdev_del(&sis_char_cdev);
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +	class_destroy(sis_char_class);

This is a race condition. You must destroy the character devce
first, then the infrastructure it uses.
> +#endif
> +}
> +
> +module_init(sis_ts_init);
> +module_exit(sis_ts_exit);
> +MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
> new file mode 100644
> index 0000000..c1d65c4
> --- /dev/null
> +++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
> @@ -0,0 +1,215 @@
> +/*
> + * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * Date: 2015/01/15
> + * Version:	Android_v2.05.00-A639-1113
> + */
> +#include <linux/version.h>
> +
> +#ifndef _LINUX_SIS_I2C_H
> +#define _LINUX_SIS_I2C_H
> +
> +
> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +#define TIMER_NS    					10000000 //10ms
> +#define MAX_FINGERS						10
> +
> +
> +/* For Android 4.0 							*/
> +/* Only for Linux kernel 2.6.34 and later 	*/
> +#define _ANDROID_4					//  ON/OFF
> +
> +/* For standard R/W IO*/
> +#define _STD_RW_IO						//  ON/OFF
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					//  ON/OFF
> +#define GPIO_IRQ 						133
> +
> +/*  Enable if use interrupt case 1 mode.  */
> +/* 	Disable if use interrupt case 2 mode. */
> +//#define _INT_MODE_1					//	ON/OFF
> +
> +/* IRQ STATUS */
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +#define IRQ_STATUS_DISABLED				0x200  
> +#else
> +#define IRQ_STATUS_DISABLED				(1<<16)
> +#endif
> +#define IRQ_STATUS_ENABLED				0x0
> +
> +/* Resolution mode */
> +// Constant value 
> +#define SIS_MAX_X						4095
> +#define SIS_MAX_Y						4095
> +
> +#define ONE_BYTE						1
> +#define FIVE_BYTE						5
> +#define EIGHT_BYTE  					8
> +#define SIXTEEN_BYTE					16
> +#define PACKET_BUFFER_SIZE				128
> +
> +#define SIS_CMD_NORMAL					0x0
> +#define SIS_CMD_SOFTRESET				0x82
> +#define SIS_CMD_RECALIBRATE				0x87
> +#define SIS_CMD_POWERMODE       		0x90
> +#define MSK_TOUCHNUM					0x0f
> +#define MSK_HAS_CRC						0x10
> +#define MSK_DATAFMT						0xe0
> +#define MSK_PSTATE						0x0f
> +#define MSK_PID	                		0xf0
> +#define RES_FMT							0x00
> +#define FIX_FMT							0x40
> +
> +/* for new i2c format */
> +#define TOUCHDOWN						0x3
> +#define TOUCHUP							0x0
> +#define MAX_BYTE						64
> +#define	PRESSURE_MAX					255
> +
> +#ifdef _ANDROID_4
> +#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
> +#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
> +#define AREA_UNIT						(5792/32)
> +#else
> +#define AREA_LENGTH_LONGER				31
> +#define AREA_LENGTH_SHORT				31
> +#endif
> +
> +
> +#define FORMAT_MODE						1
> +
> +#define MSK_NOBTN						0
> +#define MSK_COMP						1
> +#define MSK_BACK						2
> +#define MSK_MENU						4
> +#define MSK_HOME						8
> +
> +#define P_BYTECOUNT						0 
> +#define ALL_IN_ONE_PACKAGE				0x10
> +#define IS_TOUCH(x)						(x & 0x1)
> +#define IS_HIDI2C(x)					(x & 0x6)
> +#define IS_AREA(x)						((x >> 4) & 0x1)
> +#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
> +#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
> +//#define _DEBUG_PACKAGE				//  ON/OFF
> +//#define _DEBUG_REPORT					//  ON/OFF
> +#define NORMAL_LEN_PER_POINT			6
> +#define AREA_LEN_PER_POINT				2
> +#define PRESSURE_LEN_PER_POINT			1
> +
> +//#define _CHECK_CRC					//  ON/OFF
> +//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
> +#define TOUCH_FORMAT					0x1
> +#define BUTTON_FORMAT					0x4
> +#define HIDI2C_FORMAT					0x6
> +#define P_REPORT_ID						2
> +#define BUTTON_STATE					3
> +#define BUTTON_KEY_COUNT				16
> +#define BYTE_BYTECOUNT					2
> +#define BYTE_COUNT						1
> +#define BYTE_ReportID					1
> +#define BYTE_CRC_HIDI2C					0
> +#define BYTE_CRC_I2C					2
> +#define BYTE_SCANTIME					2
> +#define NO_TOUCH_BYTECOUNT				0x3
> +
> +/* TODO */
> +#define TOUCH_POWER_PIN					0
> +#define TOUCH_RESET_PIN					1
> +
> +/* CMD Define */
> +#define BUF_ACK_PLACE_L					4
> +#define BUF_ACK_PLACE_H					5
> +#define BUF_ACK_L						0xEF
> +#define BUF_ACK_H						0xBE
> +#define BUF_NACK_L						0xAD
> +#define BUF_NACK_H						0xDE
> +#define BUF_CRC_PLACE					7
> +
> +
> +
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +static const unsigned short crc16tab[256]= {
> +		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
> +        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
> +        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
> +        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
> +        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
> +        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
> +        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
> +        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
> +        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
> +        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
> +        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
> +        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
> +        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
> +        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
> +        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
> +        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
> +        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
> +        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
> +        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
> +        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
> +        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
> +        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
> +        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
> +        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
> +        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
> +        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
> +        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
> +        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
> +        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
> +        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
> +        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
> +        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
> +};
> +
> +struct Point {
> +	int id;
> +	unsigned short x, y;   	// uint16_t ?
> +	uint16_t Pressure;
> +	uint16_t Width;
> +	uint16_t Height;
> +};
> +
> +struct sisTP_driver_data {
> +	int id;
> +	int fingers;
> +	uint8_t pre_keybit_state;	
> +	struct Point pt[MAX_FINGERS];
> +};
> +
> +struct sis_ts_data {
> +	int (*power)(int on);
> +	int use_irq;
> +	struct i2c_client *client;
> +	struct input_dev *input_dev;
> +	struct hrtimer timer;
> +	struct irq_desc *desc;
> +	struct work_struct work;
> +	struct mutex mutex_wq;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif
> +};
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
> +static int sis_ts_resume(struct i2c_client *client);
> +
> +#endif /* _LINUX_SIS_I2C_H */


-- 
Oliver Neukum <oneukum@suse.de>


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-02-16 14:16           ` Oliver Neukum
  0 siblings, 0 replies; 21+ messages in thread
From: Oliver Neukum @ 2015-02-16 14:16 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: linux-kernel, linux-input, tammy0524

On Fri, 2015-01-16 at 18:59 +0800, 曾婷葳 (tammy_tseng) wrote:
> Hey, Oliver
> 
> On Mon, Jan 12, 2015 at 7:50 PM, Oliver Neukum <oneukum@suse.de> wrote:
> On Mon, 2015-01-12 at 18:53 +0800, 曾婷葳 (tammy_tseng) wrote:
> > > (Skip the code diff...)
> > 
> > Again macros for endianness
> > 
> > And the driver has a great number of conditional compilations are they 
> > really needed? The driver as is has a number of issues and is hard to 
> > review due to the use of "//" for comments and a lot of conditional 
> > compilation and unnecessary variables used for constants. Could you 
> > fix this up and resubmit?
> 
> Thanks for the reply. I've modified the code (sis_i2c.c/sis_i2c.h/Kconfig/Makefile) to fix them.
> Please help check them if anything needs to fix.
> Thanks.

You still have conditional compilation needlessly. You still haven't
addressed the issues I told you about during the review of the last
version.

	Oliver

> 
> Tammy
> 
> ---
> diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
> index e1d8003..401cd8b 100644
> --- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
> +++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
> @@ -962,4 +962,12 @@ config TOUCHSCREEN_ZFORCE
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called zforce_ts.
>  
> +config TOUCHSCREEN_SIS_I2C
> +	tristate "SiS 9200 family I2C touchscreen driver"
> +	depends on I2C
> +	default n
> +	help
> +	  This enables support for SiS 9200 family over I2C based touchscreens.
> +
> +
>  endif
> diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
> index 090e61c..67137af 100644
> --- a/linux-3.18.1/drivers/input/touchscreen/Makefile
> +++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
> @@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   	+= sis_i2c.o
> diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
> new file mode 100644
> index 0000000..157f991
> --- /dev/null
> +++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
> @@ -0,0 +1,1267 @@
> +/*
> + * SiS 9200 family I2C Touch Screen Controller Driver
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif
> +#include <linux/hrtimer.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include "sis_i2c.h"
> +#include <linux/linkage.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <asm/uaccess.h>
> +#include <linux/irq.h>
> +#include <asm/unaligned.h>
> +
> +#ifdef _STD_RW_IO
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#define DEVICE_NAME "sis_aegis_touch_device"
> +static int sis_char_devs_count = 1;        /* device count */
> +static int sis_char_major = 0;
> +static struct cdev sis_char_cdev;
> +static struct class *sis_char_class = NULL;
> +#endif
> +
> +/* Addresses to scan */
> +static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
> +static struct workqueue_struct *sis_wq;
> +struct sis_ts_data *ts_bak = 0;
> +struct sisTP_driver_data *TPInfo = NULL;
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h);
> +static void sis_ts_late_resume(struct early_suspend *h);
> +#endif
> +
> +#ifdef CONFIG_X86
> +/* static const struct i2c_client_address_data addr_data; */
> +/* Insmod parameters */
> +static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
> +#endif
> +
> +#ifdef _CHECK_CRC
> +uint16_t cal_crc (char* cmd, int start, int end);
> +#endif
> +
> +static void PrintBuffer(int start, int length, char* buf)
> +{
> +	int i;
> +	for ( i = start; i < length; i++ )
> +	{
> +		printk("%02x ", buf[i]);
> +		if (i != 0 && i % 30 == 0)
> +			printk("\n");
> +	}
> +	printk("\n");	
> +}
> +
> +int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
> +{
> +    int ret = -1;
> +    struct i2c_msg msg;
> +
> +    msg.addr = client->addr;
> +    /* Write */
> +    msg.flags = 0;
> +    msg.len = wlength;
> +    msg.buf = (unsigned char *)wdata;
> +
> +    ret = i2c_transfer(client->adapter, &msg, 1);
> +
> +    return ret;
> +}
> +
> +int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
> +{
> +    int ret = -1;
> +    struct i2c_msg msg;
> +
> +    msg.addr = client->addr;
> +    /* Read */
> +    msg.flags = I2C_M_RD;
> +    msg.len = rlength;
> +    msg.buf = rdata;
> +
> +    ret = i2c_transfer(client->adapter, &msg, 1);
> +
> +    return ret;
> +}
> +
> +int sis_cul_unit(uint8_t report_id)
> +{
> +	int ret = NORMAL_LEN_PER_POINT;
> +	
> +	if (report_id != ALL_IN_ONE_PACKAGE)
> +	{
> +		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
> +		{
> +			ret += AREA_LEN_PER_POINT;
> +		}
> +		if (IS_PRESSURE(report_id))
> +		{
> +			ret += PRESSURE_LEN_PER_POINT;
> +		}
> +	}
> +	
> +	return ret;	
> +}
> +
> +int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
> +{
> +	uint8_t tmpbuf[MAX_BYTE] = {0};
> +#ifdef _CHECK_CRC
> +	uint16_t buf_crc = 0;
> +	uint16_t package_crc = 0;
> +	int l_package_crc = 0;
> +	int crc_end = 0;
> +#endif
> +    int ret = -1;
> +    int touchnum = 0;
> +    int p_count = 0;
> +    int touc_formate_id = 0;
> +    int locate = 0;
> +    bool read_first = true;
> +    
> +/*
> +		New i2c format 
> +	* buf[0] = Low 8 bits of byte count value
> +	* buf[1] = High 8 bits of byte counte value
> +	* buf[2] = Report ID
> +	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
> +	* buf[touch num * 6 + 3] = Touch numbers
> +	* 
> +	* One touch point information include 6 bytes, the order is 
> +	* 
> +	* 1. status = touch down or touch up
> +	* 2. id = finger id 
> +	* 3. x axis low 8 bits
> +	* 4. x axis high 8 bits
> +	* 5. y axis low 8 bits
> +	* 6. y axis high 8 bits
> +	* 
> +*/
> +	do
> +	{
> +		if (locate >= PACKET_BUFFER_SIZE)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
> +			return -1;
> +		}
> +		
> +		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
> +
> +#ifdef _DEBUG_PACKAGE
> +		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
> +		PrintBuffer(0, 64, tmpbuf);	
> +#endif			
> +
> +		if(ret < 0 )
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
> +			return ret;
> +		}
> +		/* error package length of receiving data */
> +		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
> +			return -1;	
> +		}
> +		
> +		if (read_first)
> +		{
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +			/* access BUTTON TOUCH event and BUTTON NO TOUCH event */
> +			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
> +			{
> +				memcpy(&buf[0], &tmpbuf[0], 7);
> +				return 0; 	/* touchnum is 0 */
> +			}
> +#endif 
> +			/* access NO TOUCH event unless BUTTON NO TOUCH event */
> +			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
> +			{
> +				return 0;	/* touchnum is 0 */
> +			}
> +		}
> +
> +		/* skip parsing data when two devices are registered at the same slave address
> +		 * parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
> +		 */  
> +		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
> +		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
> +			return -1;		
> +		}
> +		
> +		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/* start from 0 */
> +		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
> +		{
> +			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_CRC_I2C;	/* delete 2 byte crc */
> +			}
> +			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_CRC_HIDI2C;
> +			}
> +			else	/* should not be happen */
> +			{
> +				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
> +				return -1;
> +			}
> +
> +			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
> +			{
> +				p_count -= BYTE_SCANTIME;
> +			}
> +		}
> +		/* else {}    						 For ALL_IN_ONE_PACKAGE */
> +		
> +		if (read_first)
> +		{
> +			touchnum = tmpbuf[p_count]; 	
> +		}
> +		else
> +		{
> +			if (tmpbuf[p_count] != 0)
> +			{
> +				printk(KERN_ERR "sis_ReadPacket: get error package\n");
> +				return -1;
> +			}
> +		}
> +
> +#ifdef _CHECK_CRC
> +		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
> +		buf_crc = cal_crc(tmpbuf, 2, crc_end); /* sub bytecount (2 byte) */
> +		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
> +		package_crc = get_unaligned_le16(&tmpbuf[l_package_crc]);
> +			
> +		if (buf_crc != package_crc)
> +		{
> +			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
> +			return -1;
> +		}
> +#endif	
> +		memcpy(&buf[locate], &tmpbuf[0], 64);	/* Buf_Data [0~63] [64~128] */
> +		locate += 64;
> +		read_first = false;
> +		
> +	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
> +
> +	return touchnum;
> +}	
> +
> +
> +int check_gpio_interrupt(void)
> +{
> +    int ret = 0;
> +
> +    /* CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING. */
> +    ret = gpio_get_value(GPIO_IRQ);
> +	
> +    return ret;
> +}
> +
> +void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
> +{
> +	int i = 0;
> +	uint8_t diff_keybit_state= 0x0; /* check keybit_state is difference with pre_keybit_state */
> +	uint8_t key_value = 0x0; 		/* button location for binary */
> +	uint8_t  key_pressed = 0x0; 	/* button is up or down */
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (!ts)
> +	{
> +		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
> +		return;
> +	}
> +
> +	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
> +
> +	if (diff_keybit_state)
> +	{
> +		for (i = 0; i < BUTTON_KEY_COUNT; i++)
> +		{
> +		    if ((diff_keybit_state >> i) & 0x01)
> +			{
> +				key_value = diff_keybit_state & (0x01 << i);
> +				key_pressed = (keybit_state >> i) & 0x01;
> +				switch (key_value)
> +				{
> +					case MSK_COMP:
> +						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
> +						break;
> +					case MSK_BACK:
> +						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
> +						break;
> +					case MSK_MENU:
> +						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
> +						break;
> +					case MSK_HOME:
> +						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
> +						break;
> +					case MSK_NOBTN:
> +						/* Release the button if it touched. */
> +					default:
> +						break;
> +				}
> +			}
> +		}
> +		TPInfo->pre_keybit_state = keybit_state;
> +	}
> +}
> +
> +
> +static void sis_ts_work_func(struct work_struct *work)
> +{
> +	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
> +    int ret = -1;
> +    int point_unit;  
> +	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
> +	uint8_t i = 0, fingers = 0;
> +	uint8_t px = 0, py = 0, pstatus = 0;
> +	uint8_t p_area = 0;
> +    uint8_t p_preasure = 0;
> +#ifdef _SUPPORT_BUTTON_TOUCH	
> +	int button_key;
> +	uint8_t button_buf[10] = {0};
> +#endif
> +
> +#ifdef _ANDROID_4
> +	bool all_touch_up = true;
> +#endif
> +	
> +	mutex_lock(&ts->mutex_wq); 
> +
> +    /* I2C or SMBUS block data read */
> +    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
> + 
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
> +#endif
> +
> +	/* Error Number */
> +	if (ret < 0) 
> +	{
> +		goto err_free_allocate;
> +	}
> +#ifdef _SUPPORT_BUTTON_TOUCH
> +	/* access BUTTON TOUCH event and BUTTON NO TOUCH even */
> +	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
> +	{
> +		button_key = get_unaligned_le16(&button_buf[BUTTON_STATE]);		
> +		ts_report_key(ts->client, button_key);
> +	}
> +#endif
> +	/* access NO TOUCH event unless BUTTON NO TOUCH event */
> +	else if (ret == 0)
> +	{
> +		fingers = 0;
> +		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +		goto label_send_report;  /* need to report input_mt_sync() */
> +	}
> +	
> +	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +	
> +	/* Parser and Get the sis9200 data */
> +	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
> +	fingers = ret;
> +	
> +	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
> +	
> +	/* fingers 10 =  0 ~ 9 */
> +	for (i = 0; i < fingers; i++) 
> +	{
> +        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
> +        { /* Calc point status */
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	
> +			pstatus += 64;
> +		}
> +		else 
> +		{ /* Calc point status */
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	
> +		}
> +
> +	    px = pstatus + 2;	/* Calc point x_coord */
> +	    py = px + 2;		/* Calc point y_coord */
> +
> +		if ((buf[pstatus]) == TOUCHUP)
> +		{
> +			TPInfo->pt[i].Width = 0;
> +			TPInfo->pt[i].Height = 0;
> +			TPInfo->pt[i].Pressure = 0;
> +		}
> +		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
> +		{
> +			TPInfo->pt[i].Width = 1;
> +			TPInfo->pt[i].Height = 1;
> +			TPInfo->pt[i].Pressure = 1;			
> +		}
> +		else if ((buf[pstatus]) == TOUCHDOWN)
> +		{	
> +			p_area = py + 2;
> +			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
> +
> +			/* area */
> +			if (IS_AREA(buf[P_REPORT_ID]))
> +			{
> +				TPInfo->pt[i].Width = buf[p_area] & 0xff;
> +				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
> +			}
> +			else 
> +			{
> +				TPInfo->pt[i].Width = 1;
> +				TPInfo->pt[i].Height = 1;
> +			}
> +			/* preasure */
> +			if (IS_PRESSURE(buf[P_REPORT_ID]))
> +				TPInfo->pt[i].Pressure = (buf[p_preasure]);
> +			else 
> +				TPInfo->pt[i].Pressure = 1;				
> +		}
> +		else
> +		{
> +			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
> +			goto err_free_allocate;
> +		}
> +		
> +		TPInfo->pt[i].id = (buf[pstatus + 1]);
> +		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
> +        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));   

Please use the macros for endianness conversion.

>    
> +	}
> +		
> +#ifdef _DEBUG_REPORT
> +	for (i = 0; i < TPInfo->fingers; i++)
> +	{
> +		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
> +	}
> +#endif
> +
> +label_send_report:
> +/* Report co-ordinates to the multi-touch stack */
> +#ifdef _ANDROID_4	
> +	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
> +	{
> +		if(TPInfo->pt[i].Pressure)
> +		{
> +			TPInfo->pt[i].Width *= AREA_UNIT;	
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
> +			TPInfo->pt[i].Height *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
> +			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
> +			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);
> +			input_mt_sync(ts->input_dev);
> +			all_touch_up = false;
> +		}
> +		
> +		if (i == (TPInfo->fingers -1) && all_touch_up == true)
> +		{
> +			input_mt_sync(ts->input_dev);
> +		}
> +	}
> +
> +	if(TPInfo->fingers == 0)
> +	{
> +		input_mt_sync(ts->input_dev);
> +	}
> +#else
> +	i = 0;
> +	do
> +	{
> +		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
> +		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
> +		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
> +		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
> +		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
> +		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id); /* Android 2.3 */
> +		input_mt_sync(ts->input_dev);
> +		i++;
> +	}
> +	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
> +#endif
> +	input_sync(ts->input_dev);
> +
> +err_free_allocate:
> +
> +    if (ts->use_irq)
> +    {
> +/* case 1 mode */
> +#ifdef _INT_MODE_1 
> +	    /*TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high */
> +	    ret = check_gpio_interrupt();	/* interrupt pin is still LOW, read data until interrupt pin is released. */
> +	    if (!ret)
> +	    {
> +	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	    }
> +	    else
> +	    {
> +			if (TPInfo->pre_keybit_state)
> +			{
> +				ts_report_key(ts->client, 0x0);	/* clear for interrupt */
> +			}
> +			
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +        	{
> +				enable_irq(ts->client->irq);
> +			}
> +	    }
> +/* case 2 mode */
> +#else
> +
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +		{
> +			enable_irq(ts->client->irq);
> +		}
> +#endif
> +	}
> +
> +	mutex_unlock(&ts->mutex_wq);
> +    return;
> +}
> +
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
> +{
> +	int i = 0;
> +	for(i = 0; i < max; i++)
> +	{
> +		TPInfo->pt[i].id = -1;
> +		TPInfo->pt[i].x = 0;
> +		TPInfo->pt[i].y = 0;
> +		TPInfo->pt[i].Pressure = 0;
> +		TPInfo->pt[i].Width = 0;
> +	}
> +	TPInfo->id = 0x0;
> +	TPInfo->fingers = 0;
> +}
> +
> +static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
> +{
> +	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
> +	queue_work(sis_wq, &ts->work);
> +	if (!ts->use_irq)
> +	{	/* For Polling mode */
> +	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	}
> +	return HRTIMER_NORESTART;
> +}
> +
> +static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
> +{
> +	struct sis_ts_data *ts = dev_id;
> +	
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif
> +	{
> +		disable_irq_nosync(ts->client->irq);
> +	}
> +	queue_work(sis_wq, &ts->work);
> +		
> +	return IRQ_HANDLED;
> +}
> +
> +static int initial_irq(void)
> +{
> +	int ret = 0;
> +#ifdef _I2C_INT_ENABLE
> +	/* initialize gpio and interrupt pins */
> +	ret = gpio_request(GPIO_IRQ, "GPIO_133");	/* ex. GPIO_133 for interrupt mode */
> +	if (ret < 0)
> +	{
> +		/* Set Active Low. Please reference the file include/linux/interrupt.h */
> +	}
> +	/* setting gpio direction here OR boardinfo file*/
> +
> +#else
> +	ret = -1;
> +#endif
> +	return ret;
> +}
> +
> +uint16_t cal_crc (char* cmd, int start, int end)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +	
> +	for (i = start; i <= end ; i++)
> +	{
> +		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
> +	}
> +	
> +	return crc;
> +}

How about making this CRC generally available?
> +
> +uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +	
> +	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
> +	for (i = start; i <= end ; i++)
> +	{
> +		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
> +	}
> +	
> +	return crc;
> +}
> +
> +void write_crc (unsigned char *buf, int start, int end)
> +{
> +	uint16_t crc = 0;
> +	
> +	crc = cal_crc (buf, start , end);
> +	buf[end+1] = (crc >> 8)& 0xff;
> +	buf[end+2] = crc & 0xff;

Please use the macro

> +}
> +
> +#ifdef _STD_RW_IO
> +#define BUFFER_SIZE MAX_BYTE
> +static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
> +{
> +	 int ret = 0;
> +	 char *kdata;
> +	 char cmd;
> +	 
> +	 printk(KERN_INFO "sis_cdev_write.\n");
> +	 
> +	 if (ts_bak == 0)
> +    	return -13;

You _must_ use symbolic values.

> +    	
> +    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +    if (!ret) {
> +        printk(KERN_ERR "cannot access user space memory\n");
> +        return -11;
> +    }
> +
> +	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +     if (kdata == 0)
> +    	return -12;
> +    	
> +     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +     if (ret) {
> +        printk(KERN_ERR "copy_from_user fail\n");
> +        kfree(kdata);
> +        return -14;
> +     } 
> +#if 0
> +	PrintBuffer(0, count, kdata);
> +#endif
> +		
> +	cmd = kdata[6];
> +
> +/* Write & Read */
> +    ret = sis_command_for_write(ts_bak->client, count, kdata);
> +    if (ret < 0) {
> +        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
> +		kfree(kdata);
> +		return -21;
> +	}
> +
> +    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +    {
> +        printk(KERN_ERR "copy_to_user fail\n" );
> +        ret = -19;
> +    }
> +
> +    kfree( kdata );
> +
> +	return ret;
> +}
> +
> +/* for get system time */
> +static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
> +{
> +	 int ret = 0;
> +	 char *kdata;
> +	 char cmd;
> +	 int i;
> +	 
> +	 printk(KERN_INFO "sis_cdev_read.\n");
> +	 
> +	 if (ts_bak == 0)
> +    	return -13;
> +    	
> +    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +    if (!ret) {
> +        printk(KERN_ERR "cannot access user space memory\n");
> +        return -11;
> +    }
> +
> +	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +     if (kdata == 0)
> +    	return -12;
> +    	
> +     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +     if (ret) {
> +        printk(KERN_ERR "copy_from_user fail\n");
> +        kfree(kdata);
> +        return -14;
> +     }    
> +#if 0
> +    PrintBuffer(0, count, kdata);
> +#endif
> +	 cmd = kdata[6];
> +	 /* for making sure AP communicates with SiS driver */
> +    if(cmd == 0xa2)
> +    {
> +		kdata[0] = 5;
> +		kdata[1] = 0;
> +		kdata[3] = 'S';
> +		kdata[4] = 'i';
> +		kdata[5] = 'S';
> +		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +		{
> +			printk(KERN_ERR "copy_to_user fail\n" );
> +			kfree( kdata );
> +			return -19;
> +		}
> +
> +		kfree( kdata );
> +		return 3;	
> +	}
> +/* Write & Read */
> +    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +    if (ret < 0) {
> +        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return -21;
> +	}
> +
> +	ret = kdata[0] | (kdata[1] << 8);
> +
> +    printk(KERN_INFO "%d\n", ret);
> +
> +    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
> +    {
> +        printk("%02x ", kdata[i]);
> +    }
> +
> +    printk( "\n" );
> +
> +    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
> +    {
> +        printk(KERN_ERR "copy_to_user fail\n" );
> +        ret = -19;
> +    }
> +
> +    kfree( kdata );
> +
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_open.\n");
> +	if ( ts_bak == 0 )
> +    	return -13;
> +
> +	msleep(200);
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif	
> +		{
> +			disable_irq(ts_bak->client->irq);
> +		}
> +		else
> +		{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
> +#else
> +			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
> +#endif	
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   
> +    
> +    msleep(200);
> +
> +	return 0; /* success */
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	printk(KERN_INFO "sis_cdev_release.\n");
> +	
> +	msleep(200);
> +	
> +    if (ts_bak == 0)
> +    	return -13;
> +
> +	if (ts_bak->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif	
> +		{
> +			enable_irq(ts_bak->client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +    return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int alloc_ret = 0;
> +	int cdev_err = 0;
> +	int input_err = 0;
> +	struct device *class_dev = NULL;
> +	void *ptr_err;
> +	
> +	printk("sis_setup_chardev.\n");
> +	
> +	if (ts == NULL) 
> +	{
> +	  input_err = -ENOMEM;
> +	  goto error;
> +	} 
> +	/* dynamic allocate driver handle */
> +	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
> +	if (alloc_ret)
> +		goto error;
> +		
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	
> +	if (cdev_err) 
> +		goto error;
> +	
> +	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
> +	
> +	/* register class */
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if(IS_ERR(ptr_err = sis_char_class)) 
> +	{
> +		goto err2;
> +	}
> +	
> +	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
> +	
> +	if(IS_ERR(ptr_err = class_dev)) 
> +	{
> +		goto err;
> +	}
> +	
> +	return 0;
> +error:
> +	if (cdev_err == 0)
> +		cdev_del(&sis_char_cdev);
> +	if (alloc_ret == 0)
> +		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
> +	if(input_err != 0)
> +	{
> +		printk("sis_ts_bak error!\n");
> +	}
> +err:
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +err2:
> +	class_destroy(sis_char_class);
> +	return -1;
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +    printk(KERN_INFO "sis_ts_probe\n");
> +
> +    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +    if (TPInfo == NULL) 
> +    {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +
> +	ts_bak = ts;
> +
> +	mutex_init(&ts->mutex_wq);
> +	
> +	/* 1. Init Work queue and necessary buffers */
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +    pdata = client->dev.platform_data;
> +
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) 
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0) 
> +		{
> +			printk(KERN_ERR "sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +
> +	/* 2. Allocate input device */
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) 
> +	{
> +		ret = -ENOMEM;
> +		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +
> +	/* This input device name should be the same to IDC file name. */
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +
> +#ifdef _ANDROID_4
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
> +#else
> +    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
> +    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
> +#endif
> +
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
> +    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
> +	
> +    /* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +
> +	/* 3. Register input device to core */
> +	ret = input_register_device(ts->input_dev);
> +
> +	if (ret) 
> +	{
> +		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	
> +	/* 4. irq or timer setup */
> +	ret = initial_irq();
> +	if (ret < 0) 
> +	{
> +
> +	}
> +	else
> +	{
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0) 
> +		{
> +		   ts->use_irq = 1;
> +		}
> +		else 
> +		{
> +			dev_err(&client->dev, "request_irq failed\n");
> +		}
> +	}
> +
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +
> +	if (!ts->use_irq) 
> +	{
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
> +	
> +	if (ts->use_irq)
> +	{
> +#ifdef _INT_MODE_1
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +	
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if(ret)
> +	{
> +		printk( KERN_INFO"sis_setup_chardev fail\n");
> +	}
> +#endif
> +
> +	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +
> +	return 0;
> +
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);
> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +	
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
> +#endif
> +		{
> +			disable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_cancel(&ts->timer);
> +	/* only flush sis_wq */
> +	flush_workqueue(sis_wq); 	   		
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_suspend power off failed\n");
> +	}
> +	
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power)
> +	{
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			printk(KERN_ERR "sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq)
> +	{
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#else
> +		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
> +#endif
> +		{
> +			enable_irq(client->irq);
> +		}
> +	}
> +	else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +	
> +	TPInfo->pre_keybit_state = 0x0;
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_suspend(ts->client, PMSG_SUSPEND);
> +}
> +
> +static void sis_ts_late_resume(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +	
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_resume(ts->client);
> +}
> +#endif
> +
> +static const struct i2c_device_id sis_ts_id[] = {
> +	{ SIS_I2C_NAME, 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, sis_ts_id);
> +
> +static struct i2c_driver sis_ts_driver = {
> +	.probe		= sis_ts_probe,
> +	.remove		= sis_ts_remove,
> +#ifndef CONFIG_HAS_EARLYSUSPEND
> +	.suspend	= sis_ts_suspend,
> +	.resume		= sis_ts_resume,
> +#endif
> +#ifdef CONFIG_X86
> +    .class      = I2C_CLASS_HWMON,
> +    .detect		= sis_ts_detect,
> +	.address_list	= normal_i2c,
> +#endif
> +	.id_table	= sis_ts_id,
> +	.driver = {
> +		.name	= SIS_I2C_NAME,
> +	},
> +};
> +
> +static int __init sis_ts_init(void)
> +{
> +	printk( KERN_INFO "sis_ts_init\n" );
> +	
> +	sis_wq = create_singlethread_workqueue("sis_wq");
> +
> +	if (!sis_wq)
> +		return -ENOMEM;
> +		
> +	return i2c_add_driver(&sis_ts_driver);
> +}
> +
> +#ifdef CONFIG_X86
> +/* Return 0 if detection is successful, -ENODEV otherwise */
> +static int sis_ts_detect(struct i2c_client *client,
> +		       struct i2c_board_info *info)
> +{
> +	const char *type_name;
> +	
> +    printk(KERN_INFO "sis_ts_detect\n");
> +	
> +	type_name = "sis_i2c_ts";
> +	strlcpy(info->type, type_name, I2C_NAME_SIZE);
> +	
> +	return 0;
> +}
> +#endif
> +
> +static void __exit sis_ts_exit(void)
> +{
> +#ifdef _STD_RW_IO
> +	dev_t dev;
> +#endif
> +
> +	printk(KERN_INFO "sis_ts_exit\n");
> +	
> +	i2c_del_driver(&sis_ts_driver);
> +	
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +
> +#ifdef _STD_RW_IO
> +	dev = MKDEV(sis_char_major, 0);
> +	cdev_del(&sis_char_cdev);
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
> +	class_destroy(sis_char_class);

This is a race condition. You must destroy the character devce
first, then the infrastructure it uses.
> +#endif
> +}
> +
> +module_init(sis_ts_init);
> +module_exit(sis_ts_exit);
> +MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
> new file mode 100644
> index 0000000..c1d65c4
> --- /dev/null
> +++ b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
> @@ -0,0 +1,215 @@
> +/*
> + * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * Date: 2015/01/15
> + * Version:	Android_v2.05.00-A639-1113
> + */
> +#include <linux/version.h>
> +
> +#ifndef _LINUX_SIS_I2C_H
> +#define _LINUX_SIS_I2C_H
> +
> +
> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +#define TIMER_NS    					10000000 //10ms
> +#define MAX_FINGERS						10
> +
> +
> +/* For Android 4.0 							*/
> +/* Only for Linux kernel 2.6.34 and later 	*/
> +#define _ANDROID_4					//  ON/OFF
> +
> +/* For standard R/W IO*/
> +#define _STD_RW_IO						//  ON/OFF
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					//  ON/OFF
> +#define GPIO_IRQ 						133
> +
> +/*  Enable if use interrupt case 1 mode.  */
> +/* 	Disable if use interrupt case 2 mode. */
> +//#define _INT_MODE_1					//	ON/OFF
> +
> +/* IRQ STATUS */
> +#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
> +#define IRQ_STATUS_DISABLED				0x200  
> +#else
> +#define IRQ_STATUS_DISABLED				(1<<16)
> +#endif
> +#define IRQ_STATUS_ENABLED				0x0
> +
> +/* Resolution mode */
> +// Constant value 
> +#define SIS_MAX_X						4095
> +#define SIS_MAX_Y						4095
> +
> +#define ONE_BYTE						1
> +#define FIVE_BYTE						5
> +#define EIGHT_BYTE  					8
> +#define SIXTEEN_BYTE					16
> +#define PACKET_BUFFER_SIZE				128
> +
> +#define SIS_CMD_NORMAL					0x0
> +#define SIS_CMD_SOFTRESET				0x82
> +#define SIS_CMD_RECALIBRATE				0x87
> +#define SIS_CMD_POWERMODE       		0x90
> +#define MSK_TOUCHNUM					0x0f
> +#define MSK_HAS_CRC						0x10
> +#define MSK_DATAFMT						0xe0
> +#define MSK_PSTATE						0x0f
> +#define MSK_PID	                		0xf0
> +#define RES_FMT							0x00
> +#define FIX_FMT							0x40
> +
> +/* for new i2c format */
> +#define TOUCHDOWN						0x3
> +#define TOUCHUP							0x0
> +#define MAX_BYTE						64
> +#define	PRESSURE_MAX					255
> +
> +#ifdef _ANDROID_4
> +#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
> +#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
> +#define AREA_UNIT						(5792/32)
> +#else
> +#define AREA_LENGTH_LONGER				31
> +#define AREA_LENGTH_SHORT				31
> +#endif
> +
> +
> +#define FORMAT_MODE						1
> +
> +#define MSK_NOBTN						0
> +#define MSK_COMP						1
> +#define MSK_BACK						2
> +#define MSK_MENU						4
> +#define MSK_HOME						8
> +
> +#define P_BYTECOUNT						0 
> +#define ALL_IN_ONE_PACKAGE				0x10
> +#define IS_TOUCH(x)						(x & 0x1)
> +#define IS_HIDI2C(x)					(x & 0x6)
> +#define IS_AREA(x)						((x >> 4) & 0x1)
> +#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
> +#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
> +//#define _DEBUG_PACKAGE				//  ON/OFF
> +//#define _DEBUG_REPORT					//  ON/OFF
> +#define NORMAL_LEN_PER_POINT			6
> +#define AREA_LEN_PER_POINT				2
> +#define PRESSURE_LEN_PER_POINT			1
> +
> +//#define _CHECK_CRC					//  ON/OFF
> +//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
> +#define TOUCH_FORMAT					0x1
> +#define BUTTON_FORMAT					0x4
> +#define HIDI2C_FORMAT					0x6
> +#define P_REPORT_ID						2
> +#define BUTTON_STATE					3
> +#define BUTTON_KEY_COUNT				16
> +#define BYTE_BYTECOUNT					2
> +#define BYTE_COUNT						1
> +#define BYTE_ReportID					1
> +#define BYTE_CRC_HIDI2C					0
> +#define BYTE_CRC_I2C					2
> +#define BYTE_SCANTIME					2
> +#define NO_TOUCH_BYTECOUNT				0x3
> +
> +/* TODO */
> +#define TOUCH_POWER_PIN					0
> +#define TOUCH_RESET_PIN					1
> +
> +/* CMD Define */
> +#define BUF_ACK_PLACE_L					4
> +#define BUF_ACK_PLACE_H					5
> +#define BUF_ACK_L						0xEF
> +#define BUF_ACK_H						0xBE
> +#define BUF_NACK_L						0xAD
> +#define BUF_NACK_H						0xDE
> +#define BUF_CRC_PLACE					7
> +
> +
> +
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +static const unsigned short crc16tab[256]= {
> +		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
> +        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
> +        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
> +        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
> +        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
> +        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
> +        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
> +        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
> +        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
> +        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
> +        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
> +        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
> +        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
> +        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
> +        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
> +        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
> +        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
> +        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
> +        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
> +        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
> +        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
> +        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
> +        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
> +        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
> +        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
> +        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
> +        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
> +        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
> +        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
> +        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
> +        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
> +        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
> +};
> +
> +struct Point {
> +	int id;
> +	unsigned short x, y;   	// uint16_t ?
> +	uint16_t Pressure;
> +	uint16_t Width;
> +	uint16_t Height;
> +};
> +
> +struct sisTP_driver_data {
> +	int id;
> +	int fingers;
> +	uint8_t pre_keybit_state;	
> +	struct Point pt[MAX_FINGERS];
> +};
> +
> +struct sis_ts_data {
> +	int (*power)(int on);
> +	int use_irq;
> +	struct i2c_client *client;
> +	struct input_dev *input_dev;
> +	struct hrtimer timer;
> +	struct irq_desc *desc;
> +	struct work_struct work;
> +	struct mutex mutex_wq;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif
> +};
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
> +static int sis_ts_resume(struct i2c_client *client);
> +
> +#endif /* _LINUX_SIS_I2C_H */


-- 
Oliver Neukum <oneukum@suse.de>

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
  2015-02-12  6:07               ` 曾婷葳 (tammy_tseng)
@ 2015-02-16 14:31                 ` Oliver Neukum
  -1 siblings, 0 replies; 21+ messages in thread
From: Oliver Neukum @ 2015-02-16 14:31 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: Dmitry Torokhov, lkml, linux-input, tammy0524

On Thu, 2015-02-12 at 14:07 +0800, 曾婷葳 (tammy_tseng) wrote:
> Hi, 
> 
> I've checked the coding style and modified the i2c and hid touch driver for sis touch controller.
> Please help review them. 
> Thanks a lot.

Sorry, I accidentally reviewed the old version first.

> 
> Tammy
> -----
> Here is the sis i2c driver in input:
> 
> linux-3.18.5/drivers/input/touchscreen/Kconfig   |    7 +
>  linux-3.18.5/drivers/input/touchscreen/Makefile  |    1 +
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.c | 1032 ++++++++++++++++++++++
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.h |  173 ++++
>  4 files changed, 1213 insertions(+)
> 
> 
> -----
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Kconfig b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> index e1d8003..5093ccc 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Kconfig
> +++ b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> @@ -962,4 +962,11 @@ config TOUCHSCREEN_ZFORCE
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called zforce_ts.
>  
> +config TOUCHSCREEN_SIS_I2C
> +	tristate "SiS 9200 family I2C touchscreen driver"
> +	depends on I2C
> +	default n
> +	help
> +	  This enables support for SiS 9200 family over I2C based touchscreens.
> +
>  endif
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Makefile b/linux-3.18.5/drivers/input/touchscreen/Makefile
> index 090e61c..25cfd9f 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Makefile
> +++ b/linux-3.18.5/drivers/input/touchscreen/Makefile
> @@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> new file mode 100644
> index 0000000..260a7b6
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> @@ -0,0 +1,1032 @@
> +/* drivers/input/touchscreen/sis_i2c.c
> + *  - I2C Touch panel driver for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif
> +#include <linux/hrtimer.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include "sis_i2c.h"
> +#include <linux/linkage.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/uaccess.h>
> +#include <linux/irq.h>
> +#include <asm/unaligned.h>
> +
> +#ifdef _STD_RW_IO
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#define DEVICE_NAME "sis_aegis_touch_device"
> +static const int sis_char_devs_count = 1;        /* device count */
> +static int sis_char_major;
> +static struct cdev sis_char_cdev;
> +static struct class *sis_char_class;
> +#endif
> +
> +/* Addresses to scan */
> +static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
> +static struct workqueue_struct *sis_wq;
> +struct sis_ts_data *ts_bak;
> +struct sisTP_driver_data *TPInfo;
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h);
> +static void sis_ts_late_resume(struct early_suspend *h);
> +#endif
> +
> +#ifdef _CHECK_CRC
> +static const unsigned short crc16tab[256] = {
> +	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
> +	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
> +	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
> +	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
> +	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
> +	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
> +	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
> +	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
> +	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
> +	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
> +	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
> +	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
> +	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
> +	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
> +	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
> +	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
> +	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
> +	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
> +	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
> +	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
> +	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
> +	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
> +	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
> +	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
> +	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
> +	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
> +	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
> +	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
> +	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
> +	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
> +	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
> +	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
> +};

If there are other users of this CRC polynom we'd like to have it in
a sparate module.

> +
> +static uint16_t cal_crc(char *cmd, int start, int end)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd[i]) & 0x00FF];
> +	return crc;
> +}
> +#endif
> +
> +#ifdef _DEBUG_PACKAGE
> +static void PrintBuffer(int start, int length, char *buf)
> +{
> +	int i;
> +
> +	for (i = start; i < length; i++) {
> +		pr_info("%02x ", buf[i]);
> +		if (i != 0 && i % 30 == 0)
> +			pr_info("\n");
> +	}
> +	pr_info("\n");
> +}
> +#endif
> +
> +static int sis_command_for_write(struct i2c_client *client, int wlength,
> +							unsigned char *wdata)
> +{
> +	int ret = SIS_ERR;
> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = 0; /*Write*/
> +	msg.len = wlength;
> +	msg.buf = (unsigned char *)wdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;
> +}
> +
> +static int sis_command_for_read(struct i2c_client *client, int rlength,
> +							unsigned char *rdata)
> +{
> +	int ret = SIS_ERR;
> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = I2C_M_RD; /*Read*/
> +	msg.len = rlength;
> +	msg.buf = rdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;
> +}
> +
> +static int sis_cul_unit(uint8_t report_id)
> +{
> +	int ret = NORMAL_LEN_PER_POINT;
> +
> +	if (report_id != ALL_IN_ONE_PACKAGE) {
> +		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
> +			ret += AREA_LEN_PER_POINT;
> +		if (IS_PRESSURE(report_id))
> +			ret += PRESSURE_LEN_PER_POINT;
> +	}
> +
> +	return ret;
> +}
> +
> +static int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t *buf)
> +{
> +	uint8_t tmpbuf[MAX_BYTE] = {0};	/*MAX_BYTE = 64;*/
> +	int ret = SIS_ERR;
> +	int touchnum = 0;
> +	int p_count = 0;
> +	int touc_formate_id = 0;
> +	int locate = 0;
> +	bool read_first = true;
> +	/*
> +	* New i2c format
> +	* buf[0] = Low 8 bits of byte count value
> +	* buf[1] = High 8 bits of byte counte value
> +	* buf[2] = Report ID
> +	* buf[touch num * 6 + 2 ] = Touch informations;
> +	* 1 touch point has 6 bytes, it could be none if no touch
> +	* buf[touch num * 6 + 3] = Touch numbers
> +	*
> +	* One touch point information include 6 bytes, the order is
> +	*
> +	* 1. status = touch down or touch up
> +	* 2. id = finger id
> +	* 3. x axis low 8 bits
> +	* 4. x axis high 8 bits
> +	* 5. y axis low 8 bits
> +	* 6. y axis high 8 bits
> +	* */
> +	do {
> +		if (locate >= PACKET_BUFFER_SIZE) {
> +			pr_err("sis_ReadPacket: Buf Overflow\n");
> +			return SIS_ERR;
> +		}
> +		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
> +#ifdef _DEBUG_PACKAGE
> +		pr_info("chaoban test: Buf_Data [0~63]\n");
> +		PrintBuffer(0, 64, tmpbuf);
> +#endif
> +		if (ret < 0) {
> +			pr_err("sis_ReadPacket: i2c transfer error\n");
> +			return ret;
> +		}
> +		/*error package length of receiving data*/
> +		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE) {
> +			pr_err("sis_ReadPacket: Error Bytecount\n");
> +			return SIS_ERR;
> +		}
> +		if (read_first) {
> +			/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
> +				return 0;	/*touchnum is 0*/
> +		}
> +		/*skip parsing data when two devices are registered
> +		 * at the same slave address*/
> +		/*parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT
> +		 * or P_REPORT_ID is ALL_IN_ONE_PACKAGE*/
> +		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
> +		if ((touc_formate_id != TOUCH_FORMAT)
> +		&& (touc_formate_id != HIDI2C_FORMAT)
> +		&& (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)) {
> +			pr_err("sis_ReadPacket: Error Report_ID\n");
> +			return SIS_ERR;
> +		}
> +		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/*start from 0*/
> +		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) {
> +			if (IS_TOUCH(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_I2C;/*delete 2 byte crc*/
> +			} else if (IS_HIDI2C(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_HIDI2C;
> +			} else {	/*should not be happen*/
> +				pr_err("sis_ReadPacket: delete crc error\n");
> +				return SIS_ERR;
> +			}
> +			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
> +				p_count -= BYTE_SCANTIME;
> +		}
> +		/*else {}*/ /*For ALL_IN_ONE_PACKAGE*/
> +		if (read_first) {
> +			touchnum = tmpbuf[p_count];
> +		} else {
> +			if (tmpbuf[p_count] != 0) {
> +				pr_err("sis_ReadPacket: get error package\n");
> +				return SIS_ERR;
> +			}
> +		}
> +
> +#ifdef _CHECK_CRC
> +		/* HID over I2C data foramt and no touch packet without CRC */
> +		if ((touc_formate_id != HIDI2C_FORMAT) &&
> +			(tmpbuf[P_BYTECOUNT] > 3)) {
> +			int crc_end = p_count + (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2);
> +			uint16_t buf_crc = cal_crc(
> +				tmpbuf, 2, crc_end);/*sub bytecount(2 byte)*/
> +			int l_package_crc = (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2) + p_count + 1;
> +			uint16_t package_crc = le16_to_cpu(get_unaligned_le16(
> +				&tmpbuf[l_package_crc]));
> +
> +			if (buf_crc != package_crc) {
> +				pr_err("sis_ReadPacket: CRC Error\n");
> +				return SIS_ERR;
> +			}
> +		}
> +#endif
> +		memcpy(&buf[locate], &tmpbuf[0], 64);
> +		/*Buf_Data [0~63] [64~128]*/
> +		locate += 64;
> +		read_first = false;
> +	} while (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE &&
> +			tmpbuf[p_count] > 5);
> +	return touchnum;
> +}
> +
> +#ifdef _INT_MODE_1
> +static void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
> +{
> +	int i = 0;
> +	uint8_t diff_keybit_state = 0x0;
> +	/*check keybit_state is difference with pre_keybit_state*/
> +	uint8_t key_value = 0x0; /*button location for binary*/
> +	uint8_t  key_pressed = 0x0; /*button is up or down*/
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (!ts) {
> +		pr_err("%s error: Missing Platform Data!\n", __func__);
> +		return;
> +	}
> +
> +	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
> +
> +	if (diff_keybit_state) {
> +		for (i = 0; i < BUTTON_KEY_COUNT; i++) {
> +			if ((diff_keybit_state >> i) & 0x01) {
> +				key_value = diff_keybit_state & (0x01 << i);
> +				key_pressed = (keybit_state >> i) & 0x01;
> +				switch (key_value) {
> +				case MSK_COMP:
> +					input_report_key(ts->input_dev,
> +						KEY_COMPOSE, key_pressed);
> +					break;
> +				case MSK_BACK:
> +					input_report_key(ts->input_dev,
> +						KEY_BACK, key_pressed);
> +					break;
> +				case MSK_MENU:
> +					input_report_key(ts->input_dev,
> +						KEY_MENU, key_pressed);
> +					break;
> +				case MSK_HOME:
> +					input_report_key(ts->input_dev,
> +						KEY_HOME, key_pressed);
> +					break;
> +				case MSK_NOBTN:
> +					/*Release the button if it touched.*/
> +				default:
> +					break;
> +				}
> +			}
> +		}
> +		TPInfo->pre_keybit_state = keybit_state;
> +	}
> +}
> +#endif
> +
> +static void sis_ts_work_func(struct work_struct *work)
> +{
> +	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
> +	int ret = SIS_ERR;
> +	int point_unit;
> +	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
> +	uint8_t i = 0, fingers = 0;
> +	uint8_t px = 0, py = 0, pstatus = 0;
> +	uint8_t p_area = 0;
> +	uint8_t p_preasure = 0;
> +	bool all_touch_up = true;
> +
> +	mutex_lock(&ts->mutex_wq);
> +    /* I2C or SMBUS block data read */
> +	ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
> +	/*Error Number*/
> +	if (ret < 0)
> +		goto err_free_allocate;
> +	/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +	else if (ret == 0) {
> +		fingers = 0;
> +		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +		goto label_send_report;
> +		/*need to report input_mt_sync()*/
> +	}
> +	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +
> +	/*Parser and Get the sis9200 data*/
> +	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
> +	fingers = ret;
> +
> +	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
> +
> +	/*fingers 10 =  0 ~ 9*/
> +	for (i = 0; i < fingers; i++) {
> +		if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5)) {
> +			/*Calc point status*/
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ ((i - 5) * point_unit);
> +			pstatus += 64;
> +		} else {
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ (i * point_unit);
> +					/*Calc point status*/
> +		}
> +	    px = pstatus + 2;	/*Calc point x_coord*/
> +	    py = px + 2;	/*Calc point y_coord*/
> +		if ((buf[pstatus]) == TOUCHUP) {
> +			TPInfo->pt[i].Width = 0;
> +			TPInfo->pt[i].Height = 0;
> +			TPInfo->pt[i].Pressure = 0;
> +		} else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE
> +					&& (buf[pstatus]) == TOUCHDOWN) {
> +			TPInfo->pt[i].Width = 1;
> +			TPInfo->pt[i].Height = 1;
> +			TPInfo->pt[i].Pressure = 1;
> +		} else if ((buf[pstatus]) == TOUCHDOWN) {
> +			p_area = py + 2;
> +			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
> +			/*area*/
> +			if (IS_AREA(buf[P_REPORT_ID])) {
> +				TPInfo->pt[i].Width = buf[p_area];
> +				TPInfo->pt[i].Height = buf[p_area + 1];
> +			} else {
> +				TPInfo->pt[i].Width = 1;
> +				TPInfo->pt[i].Height = 1;
> +			}
> +			/*preasure*/
> +			if (IS_PRESSURE(buf[P_REPORT_ID]))
> +				TPInfo->pt[i].Pressure = (buf[p_preasure]);
> +			else
> +				TPInfo->pt[i].Pressure = 1;
> +		} else {
> +			pr_err("sis_ts_work_func: Error Touch Status\n");
> +			goto err_free_allocate;
> +		}
> +		TPInfo->pt[i].id = (buf[pstatus + 1]);
> +		TPInfo->pt[i].x = le16_to_cpu(get_unaligned_le16(&buf[px]));

This is double. You must use only get_unaligned_le16().

> +		TPInfo->pt[i].y = le16_to_cpu(get_unaligned_le16(&buf[py]));
> +	}
> +
> +#ifdef _DEBUG_REPORT
> +	for (i = 0; i < TPInfo->fingers; i++)
> +		pr_info("chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d\n",
> +		i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y,
> +		buf[pstatus], TPInfo->pt[i].Width, TPInfo->pt[i].Height,
> +		TPInfo->pt[i].Pressure);
> +#endif
> +label_send_report:
> +/* Report co-ordinates to the multi-touch stack */
> +	for (i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++) {
> +		if (TPInfo->pt[i].Pressure) {
> +			TPInfo->pt[i].Width *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +							TPInfo->pt[i].Width);
> +			TPInfo->pt[i].Height *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +							TPInfo->pt[i].Height);
> +			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
> +							TPInfo->pt[i].Pressure);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
> +							TPInfo->pt[i].x);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
> +							TPInfo->pt[i].y);
> +			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
> +							TPInfo->pt[i].id);
> +			/*Android 2.3*/
> +			input_mt_sync(ts->input_dev);
> +			all_touch_up = false;
> +		}
> +		if (i == (TPInfo->fingers - 1) && all_touch_up == true)
> +			input_mt_sync(ts->input_dev);
> +	}
> +	if (TPInfo->fingers == 0)
> +		input_mt_sync(ts->input_dev);
> +	input_sync(ts->input_dev);
> +
> +err_free_allocate:
> +
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1	/*case 1 mode*/
> +		/*TODO: After interrupt status low,
> +		 * read i2c bus data by polling,
> +		 * until interrupt status is high*/
> +		ret =  gpio_get_value(GPIO_IRQ);
> +		/*interrupt pin is still LOW,
> +		 * read data until interrupt pin is released.*/
> +		if (!ret)
> +			hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS),
> +						HRTIMER_MODE_REL);
> +		else {
> +			if (TPInfo->pre_keybit_state)
> +				/*clear for interrupt*/
> +				ts_report_key(ts->client, 0x0);
> +
> +			if (irqd_irq_disabled(&ts->desc->irq_data))
> +				enable_irq(ts->client->irq);
> +		}
> +#else /*case 2 mode*/
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(ts->client->irq);
> +#endif
> +	}
> +
> +	mutex_unlock(&ts->mutex_wq);
> +}
> +
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
> +{
> +	int i = 0;
> +
> +	for (i = 0; i < max; i++) {
> +		TPInfo->pt[i].id = -1;
> +		TPInfo->pt[i].x = 0;
> +		TPInfo->pt[i].y = 0;
> +		TPInfo->pt[i].Pressure = 0;
> +		TPInfo->pt[i].Width = 0;
> +	}
> +	TPInfo->id = 0x0;
> +	TPInfo->fingers = 0;
> +}
> +
> +static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
> +{
> +	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
> +
> +	queue_work(sis_wq, &ts->work);
> +	if (!ts->use_irq)	/*For Polling mode*/
> +	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	return HRTIMER_NORESTART;
> +}
> +
> +static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
> +{
> +	struct sis_ts_data *ts = dev_id;
> +
> +	if (!irqd_irq_disabled(&ts->desc->irq_data))
> +		disable_irq_nosync(ts->client->irq);
> +	queue_work(sis_wq, &ts->work);
> +	return IRQ_HANDLED;
> +}
> +
> +static int initial_irq(void)
> +{
> +	int ret = 0;
> +#ifdef _I2C_INT_ENABLE
> +	/* initialize gpio and interrupt pins */
> +	/*ex. GPIO_133 for interrupt mode*/
> +	ret = gpio_request(GPIO_IRQ, "GPIO_133");
> +	if (ret < 0) {
> +		/*Set Active Low.
> +		 * Please reference the file include/linux/interrupt.h*/
> +		pr_err("sis_ts_probe: Failed to gpio_request\n");
> +		pr_err("sis_ts_probe: Fail : gpio_request was called before this driver call\n");
> +	}
> +	/* setting gpio direction here OR boardinfo file*/
> +
> +#else
> +	ret = SIS_ERR;
> +#endif
> +	return ret;
> +}
> +
> +/*static uint16_t cal_crc_with_cmd(char *data, int start, int end, uint8_t cmd)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd) & 0x00FF];
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ data[i]) & 0x00FF];
> +	return crc;
> +}*/
> +
> +/*static void write_crc(unsigned char *buf, int start, int end)
> +{
> +	uint16_t crc = 0;
> +
> +	crc = cal_crc(buf, start , end);
> +	buf[end+1] = (crc >> 8) & 0xff;
> +	buf[end+2] = crc & 0xff;

Please use an endianness macro.
> +}*/
> +
> +#ifdef _STD_RW_IO
> +#define BUFFER_SIZE MAX_BYTE
> +static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +	char cmd;
> +
> +	pr_info("sis_cdev_write.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +
> +	cmd = kdata[6];
> +
> +/*Write & Read*/
> +	ret = sis_command_for_write(ts_bak->client, count, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer write error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +	if (copy_to_user((char *) buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +/*for get system time*/
> +static ssize_t sis_cdev_read(struct file *file, char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +
> +	pr_info("sis_cdev_read.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +	/*Write & Read*/
> +	ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +
> +	ret = le16_to_cpu(get_unaligned_le16(kdata));
> +
> +	/*{
> +		int i;
> +
> +		pr_info("ret=%d\n", ret);
> +		for (i = 0; i < ret && i < BUFFER_SIZE; i++)
> +			pr_info("%02x ", kdata[i]);
> +		pr_info("\n");
> +	}*/
> +
> +	if (copy_to_user((char *)buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_open.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	if (ts_bak->use_irq) {
> +		if (!irqd_irq_disabled(&ts_bak->desc->irq_data))

Race condition

> +			disable_irq(ts_bak->client->irq);
> +		else {
> +			pr_info("sis_cdev_open: IRQ_STATUS: %x\n",
> +			irqd_irq_disabled(&ts_bak->desc->irq_data));
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +	return 0;	/*success*/
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_release.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	if (ts_bak->use_irq) {
> +		if (irqd_irq_disabled(&ts_bak->desc->irq_data))
> +			enable_irq(ts_bak->client->irq);
> +	} else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0),
> +					HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release	= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int ret = 0;
> +	struct device *class_dev = NULL;
> +
> +	pr_info("sis_setup_chardev.\n");
> +	if (ts == NULL)
> +		return -ENOMEM;
> +
> +	/*dynamic allocate driver handle*/
> +	ret = alloc_chrdev_region(&dev, 0,
> +				sis_char_devs_count, DEVICE_NAME);
> +	if (ret)
> +		return ret;
> +
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	ret = cdev_add(&sis_char_cdev, dev, sis_char_devs_count);
> +	if (ret)
> +		goto err1;
> +
> +	pr_info("%s driver(major %d) installed.\n",
> +			DEVICE_NAME, sis_char_major);
> +	/*register class*/
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if (IS_ERR(sis_char_class)) {
> +		ret = PTR_ERR(sis_char_class);
> +		goto err2;
> +	}
> +
> +	class_dev = device_create(sis_char_class, NULL, dev, NULL, DEVICE_NAME);
> +	if (IS_ERR(class_dev)) {
> +		ret = PTR_ERR(class_dev);
> +		goto err3;
> +	}
> +
> +	return 0;
> +err3:
> +	class_destroy(sis_char_class);
> +	sis_char_class = NULL;
> +err2:
> +	cdev_del(&sis_char_cdev);
> +	memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +err1:
> +	sis_char_major = 0;
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	return ret;
> +}
> +
> +static void sis_deinit_chardev(void)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +
> +	if (sis_char_class) {
> +		pr_info("sis_deinit_chardev\n");
> +		device_destroy(sis_char_class, dev);
> +		class_destroy(sis_char_class);
> +		sis_char_class = NULL;
> +		cdev_del(&sis_char_cdev);
> +		memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +		sis_char_major = 0;
> +		unregister_chrdev_region(dev, sis_char_devs_count);
> +	}
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +	pr_info("sis_ts_probe\n");
> +	TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +	if (TPInfo == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts_bak = ts;
> +	mutex_init(&ts->mutex_wq);
> +	/*1. Init Work queue and necessary buffers*/
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +	pdata = client->dev.platform_data;
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0) {
> +			pr_err("sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +	/*2. Allocate input device*/
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) {
> +		ret = -ENOMEM;
> +		pr_err("sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +	/*This input device name should be the same to IDC file name.*/
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +	set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +	set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +	set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,
> +						0, PRESSURE_MAX, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +						0, AREA_LENGTH_LONGER, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +						0, AREA_LENGTH_SHORT, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
> +						0, SIS_MAX_X, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
> +						0, SIS_MAX_Y, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
> +						0, 15, 0, 0);
> +	/* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +	/*3. Register input device to core*/
> +	ret = input_register_device(ts->input_dev);
> +	if (ret) {
> +		pr_err("sis_ts_probe: Unable to register %s input device\n",
> +				ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	/*4. irq or timer setup*/
> +	ret = initial_irq();
> +	if (ret >= 0) {
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler,
> +					IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0)
> +			ts->use_irq = 1;
> +		else
> +			dev_err(&client->dev, "request_irq failed\n");
> +	}
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +	if (!ts->use_irq)
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	pr_info("sis_ts_probe: Start touchscreen %s in %s mode\n",
> +			ts->input_dev->name,
> +			ts->use_irq ? "interrupt" : "polling");
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1
> +		pr_info("sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		pr_info("sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if (ret)
> +		pr_err("sis_setup_chardev fail\n");
> +#endif
> +	pr_info("sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +	return 0;
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);

memory leak in error case. TPinfo isn't freed.

> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +#ifdef _STD_RW_IO
> +	sis_deinit_chardev();
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);

The work can still be queued.

> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq) {
> +		if (!irqd_irq_disabled(&ts->desc->irq_data))
> +			disable_irq(client->irq);
> +	} else
> +		hrtimer_cancel(&ts->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			pr_err("sis_ts_suspend power off failed\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			pr_err("sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq) {
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(client->irq);
> +	} else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_suspend(ts->client, PMSG_SUSPEND);
> +}
> +
> +static void sis_ts_late_resume(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_resume(ts->client);
> +}
> +#endif
> +
> +#ifdef CONFIG_X86
> +/* Return 0 if detection is successful, -ENODEV otherwise */
> +static int sis_ts_detect(struct i2c_client *client,
> +		       struct i2c_board_info *info)
> +{
> +	const char *type_name;
> +
> +	pr_info("sis_ts_detect\n");
> +	type_name = "sis_i2c_ts";
> +	strlcpy(info->type, type_name, I2C_NAME_SIZE);
> +	return 0;
> +}
> +#endif
> +
> +static const struct i2c_device_id sis_ts_id[] = {
> +	{ SIS_I2C_NAME, 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, sis_ts_id);
> +
> +static struct i2c_driver sis_ts_driver = {
> +	.probe		= sis_ts_probe,
> +	.remove		= sis_ts_remove,
> +#ifndef CONFIG_HAS_EARLYSUSPEND
> +	.suspend	= sis_ts_suspend,
> +	.resume		= sis_ts_resume,
> +#endif
> +#ifdef CONFIG_X86
> +	.class		= I2C_CLASS_HWMON,
> +	.detect		= sis_ts_detect,
> +	.address_list	= normal_i2c,
> +#endif
> +	.id_table	= sis_ts_id,
> +	.driver = {
> +		.name	= SIS_I2C_NAME,
> +	},
> +};
> +
> +static int __init sis_ts_init(void)
> +{
> +	pr_info("sis_ts_init\n");
> +	sis_wq = create_singlethread_workqueue("sis_wq");
> +
> +	if (!sis_wq)
> +		return -ENOMEM;
> +	return i2c_add_driver(&sis_ts_driver);
> +}
> +
> +static void __exit sis_ts_exit(void)
> +{
> +	pr_info("sis_ts_exit\n");
> +	i2c_del_driver(&sis_ts_driver);
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +}
> +
> +module_init(sis_ts_init);
> +module_exit(sis_ts_exit);
> +MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> new file mode 100644
> index 0000000..7639a52
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> @@ -0,0 +1,173 @@
> +/*
> + * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * Date: 2015/01/15
> + * Version:	Android_v2.05.00-A639-1113
> + */
> +#include <linux/version.h>
> +
> +#ifndef _LINUX_SIS_I2C_H
> +#define _LINUX_SIS_I2C_H
> +
> +
> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +/*10ms*/
> +#define TIMER_NS						10000000
> +#define MAX_FINGERS						10
> +
> +/* For standard R/W IO ( SiS firmware application )*/
> +#define _STD_RW_IO						/*ON/OFF*/
> +
> +/* Check data CRC */
> +/*#define _CHECK_CRC*/						/*ON/OFF*/
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					/*ON/OFF*/
> +#define GPIO_IRQ						133
> +
> +/*	Enable if use interrupt case 1 mode.	*/
> +/*	Disable if use interrupt case 2 mode.	*/
> +/*#define _INT_MODE_1*/					/*ON/OFF*/
> +
> +/* Resolution mode */
> +/*Constant value*/
> +#define SIS_MAX_X						4095
> +#define SIS_MAX_Y						4095
> +
> +#define ONE_BYTE						1
> +#define FIVE_BYTE						5
> +#define EIGHT_BYTE						8
> +#define SIXTEEN_BYTE					16
> +#define PACKET_BUFFER_SIZE				128
> +
> +#define SIS_CMD_NORMAL					0x0
> +#define SIS_CMD_SOFTRESET				0x82
> +#define SIS_CMD_RECALIBRATE				0x87
> +#define SIS_CMD_POWERMODE				0x90
> +#define MSK_TOUCHNUM					0x0f
> +#define MSK_HAS_CRC						0x10
> +#define MSK_DATAFMT						0xe0
> +#define MSK_PSTATE						0x0f
> +#define MSK_PID							0xf0
> +#define RES_FMT							0x00
> +#define FIX_FMT							0x40
> +
> +/* for new i2c format */
> +#define TOUCHDOWN						0x3
> +#define TOUCHUP							0x0
> +#define MAX_BYTE						64
> +#define	PRESSURE_MAX					255
> +
> +/*Resolution diagonal */
> +#define AREA_LENGTH_LONGER				5792
> +/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
> +#define AREA_LENGTH_SHORT				5792
> +#define AREA_UNIT						(5792/32)
> +
> +
> +#define FORMAT_MODE						1
> +
> +#define MSK_NOBTN						0
> +#define MSK_COMP						1
> +#define MSK_BACK						2
> +#define MSK_MENU						4
> +#define MSK_HOME						8
> +
> +#define P_BYTECOUNT						0
> +#define ALL_IN_ONE_PACKAGE				0x10
> +#define IS_TOUCH(x)						(x & 0x1)
> +#define IS_HIDI2C(x)					((x & 0xF) == 0x06)
> +#define IS_AREA(x)						((x >> 4) & 0x1)
> +#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
> +#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
> +/*#define _DEBUG_PACKAGE*/				/*ON/OFF*/
> +/*#define _DEBUG_REPORT*/				/*ON/OFF*/
> +#define NORMAL_LEN_PER_POINT			6
> +#define AREA_LEN_PER_POINT				2
> +#define PRESSURE_LEN_PER_POINT			1
> +
> +#define TOUCH_FORMAT					0x1
> +#define BUTTON_FORMAT					0x4
> +#define HIDI2C_FORMAT					0x6
> +#define P_REPORT_ID						2
> +#define BUTTON_STATE					3
> +#define BUTTON_KEY_COUNT				16
> +#define BYTE_BYTECOUNT					2
> +#define BYTE_COUNT						1
> +#define BYTE_ReportID					1
> +#define BYTE_CRC_HIDI2C					0
> +#define BYTE_CRC_I2C					2
> +#define BYTE_SCANTIME					2
> +#define NO_TOUCH_BYTECOUNT				0x3
> +
> +/* TODO */
> +#define TOUCH_POWER_PIN					0
> +#define TOUCH_RESET_PIN					1
> +
> +/* CMD Define */
> +#define BUF_ACK_PLACE_L					4
> +#define BUF_ACK_PLACE_H					5
> +#define BUF_ACK_L						0xEF
> +#define BUF_ACK_H						0xBE
> +#define BUF_NACK_L						0xAD
> +#define BUF_NACK_H						0xDE
> +#define BUF_CRC_PLACE					7
> +
> +/* SiS i2c error code */
> +#define SIS_ERR						-1
> +#define SIS_ERR_ACCESS_USER_MEM		-11 /* Access user memory fail */
> +#define SIS_ERR_ALLOCATE_KERNEL_MEM	-12 /* Allocate memory fail */
> +#define SIS_ERR_CLIENT				-13 /* Client not created */
> +#define SIS_ERR_COPY_FROM_USER		-14 /* Copy data from user fail */
> +#define SIS_ERR_COPY_FROM_KERNEL	-19 /* Copy data from kernel fail */
> +#define SIS_ERR_TRANSMIT_I2C		-21 /* Transmit error in I2C */


Stop this. You _must_ use the symbolic names the kernel provides.

> +
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +struct Point {
> +	int id;
> +	unsigned short x, y;		/*uint16_t ?*/
> +	uint16_t Pressure;
> +	uint16_t Width;
> +	uint16_t Height;
> +};
> +
> +struct sisTP_driver_data {
> +	int id;
> +	int fingers;
> +	uint8_t pre_keybit_state;
> +	struct Point pt[MAX_FINGERS];
> +};
> +
> +struct sis_ts_data {
> +	int (*power)(int on);
> +	int use_irq;
> +	struct i2c_client *client;
> +	struct input_dev *input_dev;
> +	struct hrtimer timer;
> +	struct irq_desc *desc;
> +	struct work_struct work;
> +	struct mutex mutex_wq;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif
> +};
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
> +static int sis_ts_resume(struct i2c_client *client);
> +
> +#endif /* _LINUX_SIS_I2C_H */


-- 
Oliver Neukum <oneukum@suse.de>


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-02-16 14:31                 ` Oliver Neukum
  0 siblings, 0 replies; 21+ messages in thread
From: Oliver Neukum @ 2015-02-16 14:31 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: Dmitry Torokhov, lkml, linux-input, tammy0524

On Thu, 2015-02-12 at 14:07 +0800, 曾婷葳 (tammy_tseng) wrote:
> Hi, 
> 
> I've checked the coding style and modified the i2c and hid touch driver for sis touch controller.
> Please help review them. 
> Thanks a lot.

Sorry, I accidentally reviewed the old version first.

> 
> Tammy
> -----
> Here is the sis i2c driver in input:
> 
> linux-3.18.5/drivers/input/touchscreen/Kconfig   |    7 +
>  linux-3.18.5/drivers/input/touchscreen/Makefile  |    1 +
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.c | 1032 ++++++++++++++++++++++
>  linux-3.18.5/drivers/input/touchscreen/sis_i2c.h |  173 ++++
>  4 files changed, 1213 insertions(+)
> 
> 
> -----
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Kconfig b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> index e1d8003..5093ccc 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Kconfig
> +++ b/linux-3.18.5/drivers/input/touchscreen/Kconfig
> @@ -962,4 +962,11 @@ config TOUCHSCREEN_ZFORCE
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called zforce_ts.
>  
> +config TOUCHSCREEN_SIS_I2C
> +	tristate "SiS 9200 family I2C touchscreen driver"
> +	depends on I2C
> +	default n
> +	help
> +	  This enables support for SiS 9200 family over I2C based touchscreens.
> +
>  endif
> diff --git a/linux-3.18.5/drivers/input/touchscreen/Makefile b/linux-3.18.5/drivers/input/touchscreen/Makefile
> index 090e61c..25cfd9f 100644
> --- a/linux-3.18.5/drivers/input/touchscreen/Makefile
> +++ b/linux-3.18.5/drivers/input/touchscreen/Makefile
> @@ -79,3 +79,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> new file mode 100644
> index 0000000..260a7b6
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.c
> @@ -0,0 +1,1032 @@
> +/* drivers/input/touchscreen/sis_i2c.c
> + *  - I2C Touch panel driver for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif
> +#include <linux/hrtimer.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include "sis_i2c.h"
> +#include <linux/linkage.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/uaccess.h>
> +#include <linux/irq.h>
> +#include <asm/unaligned.h>
> +
> +#ifdef _STD_RW_IO
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#define DEVICE_NAME "sis_aegis_touch_device"
> +static const int sis_char_devs_count = 1;        /* device count */
> +static int sis_char_major;
> +static struct cdev sis_char_cdev;
> +static struct class *sis_char_class;
> +#endif
> +
> +/* Addresses to scan */
> +static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
> +static struct workqueue_struct *sis_wq;
> +struct sis_ts_data *ts_bak;
> +struct sisTP_driver_data *TPInfo;
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h);
> +static void sis_ts_late_resume(struct early_suspend *h);
> +#endif
> +
> +#ifdef _CHECK_CRC
> +static const unsigned short crc16tab[256] = {
> +	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
> +	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
> +	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
> +	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
> +	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
> +	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
> +	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
> +	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
> +	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
> +	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
> +	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
> +	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
> +	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
> +	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
> +	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
> +	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
> +	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
> +	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
> +	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
> +	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
> +	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
> +	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
> +	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
> +	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
> +	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
> +	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
> +	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
> +	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
> +	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
> +	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
> +	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
> +	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
> +};

If there are other users of this CRC polynom we'd like to have it in
a sparate module.

> +
> +static uint16_t cal_crc(char *cmd, int start, int end)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd[i]) & 0x00FF];
> +	return crc;
> +}
> +#endif
> +
> +#ifdef _DEBUG_PACKAGE
> +static void PrintBuffer(int start, int length, char *buf)
> +{
> +	int i;
> +
> +	for (i = start; i < length; i++) {
> +		pr_info("%02x ", buf[i]);
> +		if (i != 0 && i % 30 == 0)
> +			pr_info("\n");
> +	}
> +	pr_info("\n");
> +}
> +#endif
> +
> +static int sis_command_for_write(struct i2c_client *client, int wlength,
> +							unsigned char *wdata)
> +{
> +	int ret = SIS_ERR;
> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = 0; /*Write*/
> +	msg.len = wlength;
> +	msg.buf = (unsigned char *)wdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;
> +}
> +
> +static int sis_command_for_read(struct i2c_client *client, int rlength,
> +							unsigned char *rdata)
> +{
> +	int ret = SIS_ERR;
> +	struct i2c_msg msg;
> +
> +	msg.addr = client->addr;
> +	msg.flags = I2C_M_RD; /*Read*/
> +	msg.len = rlength;
> +	msg.buf = rdata;
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	return ret;
> +}
> +
> +static int sis_cul_unit(uint8_t report_id)
> +{
> +	int ret = NORMAL_LEN_PER_POINT;
> +
> +	if (report_id != ALL_IN_ONE_PACKAGE) {
> +		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
> +			ret += AREA_LEN_PER_POINT;
> +		if (IS_PRESSURE(report_id))
> +			ret += PRESSURE_LEN_PER_POINT;
> +	}
> +
> +	return ret;
> +}
> +
> +static int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t *buf)
> +{
> +	uint8_t tmpbuf[MAX_BYTE] = {0};	/*MAX_BYTE = 64;*/
> +	int ret = SIS_ERR;
> +	int touchnum = 0;
> +	int p_count = 0;
> +	int touc_formate_id = 0;
> +	int locate = 0;
> +	bool read_first = true;
> +	/*
> +	* New i2c format
> +	* buf[0] = Low 8 bits of byte count value
> +	* buf[1] = High 8 bits of byte counte value
> +	* buf[2] = Report ID
> +	* buf[touch num * 6 + 2 ] = Touch informations;
> +	* 1 touch point has 6 bytes, it could be none if no touch
> +	* buf[touch num * 6 + 3] = Touch numbers
> +	*
> +	* One touch point information include 6 bytes, the order is
> +	*
> +	* 1. status = touch down or touch up
> +	* 2. id = finger id
> +	* 3. x axis low 8 bits
> +	* 4. x axis high 8 bits
> +	* 5. y axis low 8 bits
> +	* 6. y axis high 8 bits
> +	* */
> +	do {
> +		if (locate >= PACKET_BUFFER_SIZE) {
> +			pr_err("sis_ReadPacket: Buf Overflow\n");
> +			return SIS_ERR;
> +		}
> +		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
> +#ifdef _DEBUG_PACKAGE
> +		pr_info("chaoban test: Buf_Data [0~63]\n");
> +		PrintBuffer(0, 64, tmpbuf);
> +#endif
> +		if (ret < 0) {
> +			pr_err("sis_ReadPacket: i2c transfer error\n");
> +			return ret;
> +		}
> +		/*error package length of receiving data*/
> +		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE) {
> +			pr_err("sis_ReadPacket: Error Bytecount\n");
> +			return SIS_ERR;
> +		}
> +		if (read_first) {
> +			/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
> +				return 0;	/*touchnum is 0*/
> +		}
> +		/*skip parsing data when two devices are registered
> +		 * at the same slave address*/
> +		/*parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT
> +		 * or P_REPORT_ID is ALL_IN_ONE_PACKAGE*/
> +		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
> +		if ((touc_formate_id != TOUCH_FORMAT)
> +		&& (touc_formate_id != HIDI2C_FORMAT)
> +		&& (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)) {
> +			pr_err("sis_ReadPacket: Error Report_ID\n");
> +			return SIS_ERR;
> +		}
> +		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	/*start from 0*/
> +		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) {
> +			if (IS_TOUCH(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_I2C;/*delete 2 byte crc*/
> +			} else if (IS_HIDI2C(tmpbuf[P_REPORT_ID])) {
> +				p_count -= BYTE_CRC_HIDI2C;
> +			} else {	/*should not be happen*/
> +				pr_err("sis_ReadPacket: delete crc error\n");
> +				return SIS_ERR;
> +			}
> +			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
> +				p_count -= BYTE_SCANTIME;
> +		}
> +		/*else {}*/ /*For ALL_IN_ONE_PACKAGE*/
> +		if (read_first) {
> +			touchnum = tmpbuf[p_count];
> +		} else {
> +			if (tmpbuf[p_count] != 0) {
> +				pr_err("sis_ReadPacket: get error package\n");
> +				return SIS_ERR;
> +			}
> +		}
> +
> +#ifdef _CHECK_CRC
> +		/* HID over I2C data foramt and no touch packet without CRC */
> +		if ((touc_formate_id != HIDI2C_FORMAT) &&
> +			(tmpbuf[P_BYTECOUNT] > 3)) {
> +			int crc_end = p_count + (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2);
> +			uint16_t buf_crc = cal_crc(
> +				tmpbuf, 2, crc_end);/*sub bytecount(2 byte)*/
> +			int l_package_crc = (IS_SCANTIME(
> +				tmpbuf[P_REPORT_ID]) * 2) + p_count + 1;
> +			uint16_t package_crc = le16_to_cpu(get_unaligned_le16(
> +				&tmpbuf[l_package_crc]));
> +
> +			if (buf_crc != package_crc) {
> +				pr_err("sis_ReadPacket: CRC Error\n");
> +				return SIS_ERR;
> +			}
> +		}
> +#endif
> +		memcpy(&buf[locate], &tmpbuf[0], 64);
> +		/*Buf_Data [0~63] [64~128]*/
> +		locate += 64;
> +		read_first = false;
> +	} while (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE &&
> +			tmpbuf[p_count] > 5);
> +	return touchnum;
> +}
> +
> +#ifdef _INT_MODE_1
> +static void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
> +{
> +	int i = 0;
> +	uint8_t diff_keybit_state = 0x0;
> +	/*check keybit_state is difference with pre_keybit_state*/
> +	uint8_t key_value = 0x0; /*button location for binary*/
> +	uint8_t  key_pressed = 0x0; /*button is up or down*/
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (!ts) {
> +		pr_err("%s error: Missing Platform Data!\n", __func__);
> +		return;
> +	}
> +
> +	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
> +
> +	if (diff_keybit_state) {
> +		for (i = 0; i < BUTTON_KEY_COUNT; i++) {
> +			if ((diff_keybit_state >> i) & 0x01) {
> +				key_value = diff_keybit_state & (0x01 << i);
> +				key_pressed = (keybit_state >> i) & 0x01;
> +				switch (key_value) {
> +				case MSK_COMP:
> +					input_report_key(ts->input_dev,
> +						KEY_COMPOSE, key_pressed);
> +					break;
> +				case MSK_BACK:
> +					input_report_key(ts->input_dev,
> +						KEY_BACK, key_pressed);
> +					break;
> +				case MSK_MENU:
> +					input_report_key(ts->input_dev,
> +						KEY_MENU, key_pressed);
> +					break;
> +				case MSK_HOME:
> +					input_report_key(ts->input_dev,
> +						KEY_HOME, key_pressed);
> +					break;
> +				case MSK_NOBTN:
> +					/*Release the button if it touched.*/
> +				default:
> +					break;
> +				}
> +			}
> +		}
> +		TPInfo->pre_keybit_state = keybit_state;
> +	}
> +}
> +#endif
> +
> +static void sis_ts_work_func(struct work_struct *work)
> +{
> +	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
> +	int ret = SIS_ERR;
> +	int point_unit;
> +	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
> +	uint8_t i = 0, fingers = 0;
> +	uint8_t px = 0, py = 0, pstatus = 0;
> +	uint8_t p_area = 0;
> +	uint8_t p_preasure = 0;
> +	bool all_touch_up = true;
> +
> +	mutex_lock(&ts->mutex_wq);
> +    /* I2C or SMBUS block data read */
> +	ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
> +	/*Error Number*/
> +	if (ret < 0)
> +		goto err_free_allocate;
> +	/*access NO TOUCH event unless BUTTON NO TOUCH event*/
> +	else if (ret == 0) {
> +		fingers = 0;
> +		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +		goto label_send_report;
> +		/*need to report input_mt_sync()*/
> +	}
> +	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
> +
> +	/*Parser and Get the sis9200 data*/
> +	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
> +	fingers = ret;
> +
> +	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
> +
> +	/*fingers 10 =  0 ~ 9*/
> +	for (i = 0; i < fingers; i++) {
> +		if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5)) {
> +			/*Calc point status*/
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ ((i - 5) * point_unit);
> +			pstatus += 64;
> +		} else {
> +			pstatus = BYTE_BYTECOUNT + BYTE_ReportID
> +					+ (i * point_unit);
> +					/*Calc point status*/
> +		}
> +	    px = pstatus + 2;	/*Calc point x_coord*/
> +	    py = px + 2;	/*Calc point y_coord*/
> +		if ((buf[pstatus]) == TOUCHUP) {
> +			TPInfo->pt[i].Width = 0;
> +			TPInfo->pt[i].Height = 0;
> +			TPInfo->pt[i].Pressure = 0;
> +		} else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE
> +					&& (buf[pstatus]) == TOUCHDOWN) {
> +			TPInfo->pt[i].Width = 1;
> +			TPInfo->pt[i].Height = 1;
> +			TPInfo->pt[i].Pressure = 1;
> +		} else if ((buf[pstatus]) == TOUCHDOWN) {
> +			p_area = py + 2;
> +			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
> +			/*area*/
> +			if (IS_AREA(buf[P_REPORT_ID])) {
> +				TPInfo->pt[i].Width = buf[p_area];
> +				TPInfo->pt[i].Height = buf[p_area + 1];
> +			} else {
> +				TPInfo->pt[i].Width = 1;
> +				TPInfo->pt[i].Height = 1;
> +			}
> +			/*preasure*/
> +			if (IS_PRESSURE(buf[P_REPORT_ID]))
> +				TPInfo->pt[i].Pressure = (buf[p_preasure]);
> +			else
> +				TPInfo->pt[i].Pressure = 1;
> +		} else {
> +			pr_err("sis_ts_work_func: Error Touch Status\n");
> +			goto err_free_allocate;
> +		}
> +		TPInfo->pt[i].id = (buf[pstatus + 1]);
> +		TPInfo->pt[i].x = le16_to_cpu(get_unaligned_le16(&buf[px]));

This is double. You must use only get_unaligned_le16().

> +		TPInfo->pt[i].y = le16_to_cpu(get_unaligned_le16(&buf[py]));
> +	}
> +
> +#ifdef _DEBUG_REPORT
> +	for (i = 0; i < TPInfo->fingers; i++)
> +		pr_info("chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d\n",
> +		i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y,
> +		buf[pstatus], TPInfo->pt[i].Width, TPInfo->pt[i].Height,
> +		TPInfo->pt[i].Pressure);
> +#endif
> +label_send_report:
> +/* Report co-ordinates to the multi-touch stack */
> +	for (i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++) {
> +		if (TPInfo->pt[i].Pressure) {
> +			TPInfo->pt[i].Width *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +							TPInfo->pt[i].Width);
> +			TPInfo->pt[i].Height *= AREA_UNIT;
> +			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +							TPInfo->pt[i].Height);
> +			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
> +							TPInfo->pt[i].Pressure);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
> +							TPInfo->pt[i].x);
> +			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
> +							TPInfo->pt[i].y);
> +			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
> +							TPInfo->pt[i].id);
> +			/*Android 2.3*/
> +			input_mt_sync(ts->input_dev);
> +			all_touch_up = false;
> +		}
> +		if (i == (TPInfo->fingers - 1) && all_touch_up == true)
> +			input_mt_sync(ts->input_dev);
> +	}
> +	if (TPInfo->fingers == 0)
> +		input_mt_sync(ts->input_dev);
> +	input_sync(ts->input_dev);
> +
> +err_free_allocate:
> +
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1	/*case 1 mode*/
> +		/*TODO: After interrupt status low,
> +		 * read i2c bus data by polling,
> +		 * until interrupt status is high*/
> +		ret =  gpio_get_value(GPIO_IRQ);
> +		/*interrupt pin is still LOW,
> +		 * read data until interrupt pin is released.*/
> +		if (!ret)
> +			hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS),
> +						HRTIMER_MODE_REL);
> +		else {
> +			if (TPInfo->pre_keybit_state)
> +				/*clear for interrupt*/
> +				ts_report_key(ts->client, 0x0);
> +
> +			if (irqd_irq_disabled(&ts->desc->irq_data))
> +				enable_irq(ts->client->irq);
> +		}
> +#else /*case 2 mode*/
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(ts->client->irq);
> +#endif
> +	}
> +
> +	mutex_unlock(&ts->mutex_wq);
> +}
> +
> +static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
> +{
> +	int i = 0;
> +
> +	for (i = 0; i < max; i++) {
> +		TPInfo->pt[i].id = -1;
> +		TPInfo->pt[i].x = 0;
> +		TPInfo->pt[i].y = 0;
> +		TPInfo->pt[i].Pressure = 0;
> +		TPInfo->pt[i].Width = 0;
> +	}
> +	TPInfo->id = 0x0;
> +	TPInfo->fingers = 0;
> +}
> +
> +static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
> +{
> +	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
> +
> +	queue_work(sis_wq, &ts->work);
> +	if (!ts->use_irq)	/*For Polling mode*/
> +	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
> +	return HRTIMER_NORESTART;
> +}
> +
> +static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
> +{
> +	struct sis_ts_data *ts = dev_id;
> +
> +	if (!irqd_irq_disabled(&ts->desc->irq_data))
> +		disable_irq_nosync(ts->client->irq);
> +	queue_work(sis_wq, &ts->work);
> +	return IRQ_HANDLED;
> +}
> +
> +static int initial_irq(void)
> +{
> +	int ret = 0;
> +#ifdef _I2C_INT_ENABLE
> +	/* initialize gpio and interrupt pins */
> +	/*ex. GPIO_133 for interrupt mode*/
> +	ret = gpio_request(GPIO_IRQ, "GPIO_133");
> +	if (ret < 0) {
> +		/*Set Active Low.
> +		 * Please reference the file include/linux/interrupt.h*/
> +		pr_err("sis_ts_probe: Failed to gpio_request\n");
> +		pr_err("sis_ts_probe: Fail : gpio_request was called before this driver call\n");
> +	}
> +	/* setting gpio direction here OR boardinfo file*/
> +
> +#else
> +	ret = SIS_ERR;
> +#endif
> +	return ret;
> +}
> +
> +/*static uint16_t cal_crc_with_cmd(char *data, int start, int end, uint8_t cmd)
> +{
> +	int i = 0;
> +	uint16_t crc = 0;
> +
> +	crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd) & 0x00FF];
> +	for (i = start; i <= end ; i++)
> +		crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ data[i]) & 0x00FF];
> +	return crc;
> +}*/
> +
> +/*static void write_crc(unsigned char *buf, int start, int end)
> +{
> +	uint16_t crc = 0;
> +
> +	crc = cal_crc(buf, start , end);
> +	buf[end+1] = (crc >> 8) & 0xff;
> +	buf[end+2] = crc & 0xff;

Please use an endianness macro.
> +}*/
> +
> +#ifdef _STD_RW_IO
> +#define BUFFER_SIZE MAX_BYTE
> +static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +	char cmd;
> +
> +	pr_info("sis_cdev_write.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +
> +	cmd = kdata[6];
> +
> +/*Write & Read*/
> +	ret = sis_command_for_write(ts_bak->client, count, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer write error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +	if (copy_to_user((char *) buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +/*for get system time*/
> +static ssize_t sis_cdev_read(struct file *file, char __user *buf,
> +								size_t count,
> +								loff_t *f_pos)
> +{
> +	int ret = 0;
> +	char *kdata;
> +
> +	pr_info("sis_cdev_read.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
> +	if (!ret) {
> +		pr_err("cannot access user space memory\n");
> +		return SIS_ERR_ACCESS_USER_MEM;
> +	}
> +	kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
> +	if (kdata == 0)
> +		return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +	ret = copy_from_user(kdata, buf, BUFFER_SIZE);
> +	if (ret) {
> +		pr_err("copy_from_user fail\n");
> +		kfree(kdata);
> +		return SIS_ERR_COPY_FROM_USER;
> +	}
> +#ifdef _DEBUG_PACKAGE
> +	PrintBuffer(0, count, kdata);
> +#endif
> +	/*Write & Read*/
> +	ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
> +	if (ret < 0) {
> +		pr_err("i2c_transfer read error %d\n", ret);
> +		kfree(kdata);
> +		return SIS_ERR_TRANSMIT_I2C;
> +	}
> +
> +	ret = le16_to_cpu(get_unaligned_le16(kdata));
> +
> +	/*{
> +		int i;
> +
> +		pr_info("ret=%d\n", ret);
> +		for (i = 0; i < ret && i < BUFFER_SIZE; i++)
> +			pr_info("%02x ", kdata[i]);
> +		pr_info("\n");
> +	}*/
> +
> +	if (copy_to_user((char *)buf, kdata, BUFFER_SIZE)) {
> +		pr_err("copy_to_user fail\n");
> +		ret = SIS_ERR_COPY_FROM_KERNEL;
> +	}
> +
> +	kfree(kdata);
> +	return ret;
> +}
> +
> +#undef BUFFER_SIZE
> +
> +static int sis_cdev_open(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_open.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +
> +	if (ts_bak->use_irq) {
> +		if (!irqd_irq_disabled(&ts_bak->desc->irq_data))

Race condition

> +			disable_irq(ts_bak->client->irq);
> +		else {
> +			pr_info("sis_cdev_open: IRQ_STATUS: %x\n",
> +			irqd_irq_disabled(&ts_bak->desc->irq_data));
> +		}
> +	}
> +	hrtimer_cancel(&ts_bak->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +	return 0;	/*success*/
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp)
> +{
> +	pr_info("sis_cdev_release.\n");
> +	if (ts_bak == 0)
> +		return SIS_ERR_CLIENT;
> +	if (ts_bak->use_irq) {
> +		if (irqd_irq_disabled(&ts_bak->desc->irq_data))
> +			enable_irq(ts_bak->client->irq);
> +	} else
> +		hrtimer_start(&ts_bak->timer, ktime_set(1, 0),
> +					HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +static const struct file_operations sis_cdev_fops = {
> +	.owner	= THIS_MODULE,
> +	.read	= sis_cdev_read,
> +	.write	= sis_cdev_write,
> +	.open	= sis_cdev_open,
> +	.release	= sis_cdev_release,
> +};
> +
> +static int sis_setup_chardev(struct sis_ts_data *ts)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +	int ret = 0;
> +	struct device *class_dev = NULL;
> +
> +	pr_info("sis_setup_chardev.\n");
> +	if (ts == NULL)
> +		return -ENOMEM;
> +
> +	/*dynamic allocate driver handle*/
> +	ret = alloc_chrdev_region(&dev, 0,
> +				sis_char_devs_count, DEVICE_NAME);
> +	if (ret)
> +		return ret;
> +
> +	sis_char_major = MAJOR(dev);
> +	cdev_init(&sis_char_cdev, &sis_cdev_fops);
> +	sis_char_cdev.owner = THIS_MODULE;
> +	ret = cdev_add(&sis_char_cdev, dev, sis_char_devs_count);
> +	if (ret)
> +		goto err1;
> +
> +	pr_info("%s driver(major %d) installed.\n",
> +			DEVICE_NAME, sis_char_major);
> +	/*register class*/
> +	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
> +	if (IS_ERR(sis_char_class)) {
> +		ret = PTR_ERR(sis_char_class);
> +		goto err2;
> +	}
> +
> +	class_dev = device_create(sis_char_class, NULL, dev, NULL, DEVICE_NAME);
> +	if (IS_ERR(class_dev)) {
> +		ret = PTR_ERR(class_dev);
> +		goto err3;
> +	}
> +
> +	return 0;
> +err3:
> +	class_destroy(sis_char_class);
> +	sis_char_class = NULL;
> +err2:
> +	cdev_del(&sis_char_cdev);
> +	memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +err1:
> +	sis_char_major = 0;
> +	unregister_chrdev_region(dev, sis_char_devs_count);
> +	return ret;
> +}
> +
> +static void sis_deinit_chardev(void)
> +{
> +	dev_t dev = MKDEV(sis_char_major, 0);
> +
> +	if (sis_char_class) {
> +		pr_info("sis_deinit_chardev\n");
> +		device_destroy(sis_char_class, dev);
> +		class_destroy(sis_char_class);
> +		sis_char_class = NULL;
> +		cdev_del(&sis_char_cdev);
> +		memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +		sis_char_major = 0;
> +		unregister_chrdev_region(dev, sis_char_devs_count);
> +	}
> +}
> +#endif
> +
> +static int sis_ts_probe(
> +	struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = NULL;
> +	struct sis_i2c_rmi_platform_data *pdata = NULL;
> +
> +	pr_info("sis_ts_probe\n");
> +	TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
> +	if (TPInfo == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
> +	if (ts == NULL) {
> +		ret = -ENOMEM;
> +		goto err_alloc_data_failed;
> +	}
> +	ts_bak = ts;
> +	mutex_init(&ts->mutex_wq);
> +	/*1. Init Work queue and necessary buffers*/
> +	INIT_WORK(&ts->work, sis_ts_work_func);
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +	pdata = client->dev.platform_data;
> +	if (pdata)
> +		ts->power = pdata->power;
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0) {
> +			pr_err("sis_ts_probe power on failed\n");
> +			goto err_power_failed;
> +		}
> +	}
> +	/*2. Allocate input device*/
> +	ts->input_dev = input_allocate_device();
> +	if (ts->input_dev == NULL) {
> +		ret = -ENOMEM;
> +		pr_err("sis_ts_probe: Failed to allocate input device\n");
> +		goto err_input_dev_alloc_failed;
> +	}
> +	/*This input device name should be the same to IDC file name.*/
> +	ts->input_dev->name = "sis_touch";
> +
> +	set_bit(EV_ABS, ts->input_dev->evbit);
> +	set_bit(EV_KEY, ts->input_dev->evbit);
> +	set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
> +	set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
> +	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
> +	set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
> +	set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
> +	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,
> +						0, PRESSURE_MAX, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
> +						0, AREA_LENGTH_LONGER, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR,
> +						0, AREA_LENGTH_SHORT, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
> +						0, SIS_MAX_X, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
> +						0, SIS_MAX_Y, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
> +						0, 15, 0, 0);
> +	/* add for touch keys */
> +	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
> +	set_bit(KEY_BACK, ts->input_dev->keybit);
> +	set_bit(KEY_MENU, ts->input_dev->keybit);
> +	set_bit(KEY_HOME, ts->input_dev->keybit);
> +	/*3. Register input device to core*/
> +	ret = input_register_device(ts->input_dev);
> +	if (ret) {
> +		pr_err("sis_ts_probe: Unable to register %s input device\n",
> +				ts->input_dev->name);
> +		goto err_input_register_device_failed;
> +	}
> +	/*4. irq or timer setup*/
> +	ret = initial_irq();
> +	if (ret >= 0) {
> +		client->irq = gpio_to_irq(GPIO_IRQ);
> +		ret = request_irq(client->irq, sis_ts_irq_handler,
> +					IRQF_TRIGGER_FALLING, client->name, ts);
> +		if (ret == 0)
> +			ts->use_irq = 1;
> +		else
> +			dev_err(&client->dev, "request_irq failed\n");
> +	}
> +	ts->desc = irq_to_desc(ts_bak->client->irq);
> +	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	ts->timer.function = sis_ts_timer_func;
> +	if (!ts->use_irq)
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +	ts->early_suspend.suspend = sis_ts_early_suspend;
> +	ts->early_suspend.resume = sis_ts_late_resume;
> +	register_early_suspend(&ts->early_suspend);
> +#endif
> +	pr_info("sis_ts_probe: Start touchscreen %s in %s mode\n",
> +			ts->input_dev->name,
> +			ts->use_irq ? "interrupt" : "polling");
> +	if (ts->use_irq) {
> +#ifdef _INT_MODE_1
> +		pr_info("sis_ts_probe: interrupt case 1 mode\n");
> +#else
> +		pr_info("sis_ts_probe: interrupt case 2 mode\n");
> +#endif
> +	}
> +#ifdef _STD_RW_IO
> +	ret = sis_setup_chardev(ts);
> +	if (ret)
> +		pr_err("sis_setup_chardev fail\n");
> +#endif
> +	pr_info("sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
> +	return 0;
> +err_input_register_device_failed:
> +	input_free_device(ts->input_dev);
> +err_input_dev_alloc_failed:
> +err_power_failed:
> +	kfree(ts);

memory leak in error case. TPinfo isn't freed.

> +err_alloc_data_failed:
> +	return ret;
> +}
> +
> +static int sis_ts_remove(struct i2c_client *client)
> +{
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif
> +#ifdef _STD_RW_IO
> +	sis_deinit_chardev();
> +#endif
> +	if (ts->use_irq)
> +		free_irq(client->irq, ts);
> +	else
> +		hrtimer_cancel(&ts->timer);

The work can still be queued.

> +	input_unregister_device(ts->input_dev);
> +	kfree(ts);
> +	return 0;
> +}
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +
> +	if (ts->use_irq) {
> +		if (!irqd_irq_disabled(&ts->desc->irq_data))
> +			disable_irq(client->irq);
> +	} else
> +		hrtimer_cancel(&ts->timer);
> +	flush_workqueue(sis_wq);		/*only flush sis_wq*/
> +
> +
> +	if (ts->power) {
> +		ret = ts->power(0);
> +		if (ret < 0)
> +			pr_err("sis_ts_suspend power off failed\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int sis_ts_resume(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct sis_ts_data *ts = i2c_get_clientdata(client);
> +
> +	if (ts->power) {
> +		ret = ts->power(1);
> +		if (ret < 0)
> +			pr_err("sis_ts_resume power on failed\n");
> +	}
> +
> +	if (ts->use_irq) {
> +		if (irqd_irq_disabled(&ts->desc->irq_data))
> +			enable_irq(client->irq);
> +	} else
> +		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void sis_ts_early_suspend(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	TPInfo->pre_keybit_state = 0x0;
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_suspend(ts->client, PMSG_SUSPEND);
> +}
> +
> +static void sis_ts_late_resume(struct early_suspend *h)
> +{
> +	struct sis_ts_data *ts;
> +
> +	ts = container_of(h, struct sis_ts_data, early_suspend);
> +	sis_ts_resume(ts->client);
> +}
> +#endif
> +
> +#ifdef CONFIG_X86
> +/* Return 0 if detection is successful, -ENODEV otherwise */
> +static int sis_ts_detect(struct i2c_client *client,
> +		       struct i2c_board_info *info)
> +{
> +	const char *type_name;
> +
> +	pr_info("sis_ts_detect\n");
> +	type_name = "sis_i2c_ts";
> +	strlcpy(info->type, type_name, I2C_NAME_SIZE);
> +	return 0;
> +}
> +#endif
> +
> +static const struct i2c_device_id sis_ts_id[] = {
> +	{ SIS_I2C_NAME, 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, sis_ts_id);
> +
> +static struct i2c_driver sis_ts_driver = {
> +	.probe		= sis_ts_probe,
> +	.remove		= sis_ts_remove,
> +#ifndef CONFIG_HAS_EARLYSUSPEND
> +	.suspend	= sis_ts_suspend,
> +	.resume		= sis_ts_resume,
> +#endif
> +#ifdef CONFIG_X86
> +	.class		= I2C_CLASS_HWMON,
> +	.detect		= sis_ts_detect,
> +	.address_list	= normal_i2c,
> +#endif
> +	.id_table	= sis_ts_id,
> +	.driver = {
> +		.name	= SIS_I2C_NAME,
> +	},
> +};
> +
> +static int __init sis_ts_init(void)
> +{
> +	pr_info("sis_ts_init\n");
> +	sis_wq = create_singlethread_workqueue("sis_wq");
> +
> +	if (!sis_wq)
> +		return -ENOMEM;
> +	return i2c_add_driver(&sis_ts_driver);
> +}
> +
> +static void __exit sis_ts_exit(void)
> +{
> +	pr_info("sis_ts_exit\n");
> +	i2c_del_driver(&sis_ts_driver);
> +	if (sis_wq)
> +		destroy_workqueue(sis_wq);
> +}
> +
> +module_init(sis_ts_init);
> +module_exit(sis_ts_exit);
> +MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> new file mode 100644
> index 0000000..7639a52
> --- /dev/null
> +++ b/linux-3.18.5/drivers/input/touchscreen/sis_i2c.h
> @@ -0,0 +1,173 @@
> +/*
> + * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
> + *
> + * Copyright (C) 2011 SiS, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + * Date: 2015/01/15
> + * Version:	Android_v2.05.00-A639-1113
> + */
> +#include <linux/version.h>
> +
> +#ifndef _LINUX_SIS_I2C_H
> +#define _LINUX_SIS_I2C_H
> +
> +
> +#define SIS_I2C_NAME "sis_i2c_ts"
> +#define SIS_SLAVE_ADDR					0x5c
> +/*10ms*/
> +#define TIMER_NS						10000000
> +#define MAX_FINGERS						10
> +
> +/* For standard R/W IO ( SiS firmware application )*/
> +#define _STD_RW_IO						/*ON/OFF*/
> +
> +/* Check data CRC */
> +/*#define _CHECK_CRC*/						/*ON/OFF*/
> +
> +/* Interrupt setting and modes */
> +#define _I2C_INT_ENABLE					/*ON/OFF*/
> +#define GPIO_IRQ						133
> +
> +/*	Enable if use interrupt case 1 mode.	*/
> +/*	Disable if use interrupt case 2 mode.	*/
> +/*#define _INT_MODE_1*/					/*ON/OFF*/
> +
> +/* Resolution mode */
> +/*Constant value*/
> +#define SIS_MAX_X						4095
> +#define SIS_MAX_Y						4095
> +
> +#define ONE_BYTE						1
> +#define FIVE_BYTE						5
> +#define EIGHT_BYTE						8
> +#define SIXTEEN_BYTE					16
> +#define PACKET_BUFFER_SIZE				128
> +
> +#define SIS_CMD_NORMAL					0x0
> +#define SIS_CMD_SOFTRESET				0x82
> +#define SIS_CMD_RECALIBRATE				0x87
> +#define SIS_CMD_POWERMODE				0x90
> +#define MSK_TOUCHNUM					0x0f
> +#define MSK_HAS_CRC						0x10
> +#define MSK_DATAFMT						0xe0
> +#define MSK_PSTATE						0x0f
> +#define MSK_PID							0xf0
> +#define RES_FMT							0x00
> +#define FIX_FMT							0x40
> +
> +/* for new i2c format */
> +#define TOUCHDOWN						0x3
> +#define TOUCHUP							0x0
> +#define MAX_BYTE						64
> +#define	PRESSURE_MAX					255
> +
> +/*Resolution diagonal */
> +#define AREA_LENGTH_LONGER				5792
> +/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
> +#define AREA_LENGTH_SHORT				5792
> +#define AREA_UNIT						(5792/32)
> +
> +
> +#define FORMAT_MODE						1
> +
> +#define MSK_NOBTN						0
> +#define MSK_COMP						1
> +#define MSK_BACK						2
> +#define MSK_MENU						4
> +#define MSK_HOME						8
> +
> +#define P_BYTECOUNT						0
> +#define ALL_IN_ONE_PACKAGE				0x10
> +#define IS_TOUCH(x)						(x & 0x1)
> +#define IS_HIDI2C(x)					((x & 0xF) == 0x06)
> +#define IS_AREA(x)						((x >> 4) & 0x1)
> +#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
> +#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
> +/*#define _DEBUG_PACKAGE*/				/*ON/OFF*/
> +/*#define _DEBUG_REPORT*/				/*ON/OFF*/
> +#define NORMAL_LEN_PER_POINT			6
> +#define AREA_LEN_PER_POINT				2
> +#define PRESSURE_LEN_PER_POINT			1
> +
> +#define TOUCH_FORMAT					0x1
> +#define BUTTON_FORMAT					0x4
> +#define HIDI2C_FORMAT					0x6
> +#define P_REPORT_ID						2
> +#define BUTTON_STATE					3
> +#define BUTTON_KEY_COUNT				16
> +#define BYTE_BYTECOUNT					2
> +#define BYTE_COUNT						1
> +#define BYTE_ReportID					1
> +#define BYTE_CRC_HIDI2C					0
> +#define BYTE_CRC_I2C					2
> +#define BYTE_SCANTIME					2
> +#define NO_TOUCH_BYTECOUNT				0x3
> +
> +/* TODO */
> +#define TOUCH_POWER_PIN					0
> +#define TOUCH_RESET_PIN					1
> +
> +/* CMD Define */
> +#define BUF_ACK_PLACE_L					4
> +#define BUF_ACK_PLACE_H					5
> +#define BUF_ACK_L						0xEF
> +#define BUF_ACK_H						0xBE
> +#define BUF_NACK_L						0xAD
> +#define BUF_NACK_H						0xDE
> +#define BUF_CRC_PLACE					7
> +
> +/* SiS i2c error code */
> +#define SIS_ERR						-1
> +#define SIS_ERR_ACCESS_USER_MEM		-11 /* Access user memory fail */
> +#define SIS_ERR_ALLOCATE_KERNEL_MEM	-12 /* Allocate memory fail */
> +#define SIS_ERR_CLIENT				-13 /* Client not created */
> +#define SIS_ERR_COPY_FROM_USER		-14 /* Copy data from user fail */
> +#define SIS_ERR_COPY_FROM_KERNEL	-19 /* Copy data from kernel fail */
> +#define SIS_ERR_TRANSMIT_I2C		-21 /* Transmit error in I2C */


Stop this. You _must_ use the symbolic names the kernel provides.

> +
> +struct sis_i2c_rmi_platform_data {
> +	int (*power)(int on);	/* Only valid in first array entry */
> +};
> +
> +struct Point {
> +	int id;
> +	unsigned short x, y;		/*uint16_t ?*/
> +	uint16_t Pressure;
> +	uint16_t Width;
> +	uint16_t Height;
> +};
> +
> +struct sisTP_driver_data {
> +	int id;
> +	int fingers;
> +	uint8_t pre_keybit_state;
> +	struct Point pt[MAX_FINGERS];
> +};
> +
> +struct sis_ts_data {
> +	int (*power)(int on);
> +	int use_irq;
> +	struct i2c_client *client;
> +	struct input_dev *input_dev;
> +	struct hrtimer timer;
> +	struct irq_desc *desc;
> +	struct work_struct work;
> +	struct mutex mutex_wq;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif
> +};
> +
> +static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
> +static int sis_ts_resume(struct i2c_client *client);
> +
> +#endif /* _LINUX_SIS_I2C_H */


-- 
Oliver Neukum <oneukum@suse.de>

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-09 10:37 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-09 10:37 UTC (permalink / raw)
  To: linux-kernel, linux-input; +Cc: tammy0524

Hi,
This package of patch is to add support for multitouch behavior for SiS touch products.
The patch of SiS i2c multitouch driver is in input/touchscreen.

Signed-off-by: Tammy Tseng <tammy_tseng@sis.com>
--

diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index edc8e27..e1d8003 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,18 +962,4 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
-config TOUCHSCREEN_SIS_I2C
-	tristate "SiS 9200 family I2C touchscreen driver"
-	depends on I2C
-	default y
-	help
-	  This enables support for SiS 9200 family over I2C based touchscreens.
-
-config FW_SUPPORT_POWERMODE
-		default n
-        bool "SiS FW support power mode"
-        depends on TOUCHSCREEN_SIS_I2C
-        help
-          This enables support power mode provided by SiS firmwave
-
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index e316477..090e61c 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -6,10 +6,6 @@
 
 wm97xx-ts-y := wm97xx-core.o
 
-ifdef CONFIG_TOUCHSCREEN_SIS_I2C
-obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
-endif
-
 obj-$(CONFIG_OF_TOUCHSCREEN)		+= of_touchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
deleted file mode 100644
index 2e6fc1a..0000000
--- a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
+++ /dev/null
@@ -1,1725 +0,0 @@
-/* drivers/input/touchscreen/sis_i2c.c - I2C Touch panel driver for SiS 9200 family
- *
- * Copyright (C) 2011 SiS, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * Date: 2012/11/13
- * Version:	Android_v2.05.00-A639-1113
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#ifdef CONFIG_HAS_EARLYSUSPEND
-#include <linux/earlysuspend.h>
-#endif
-#include <linux/hrtimer.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "sis_i2c.h"
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <asm/uaccess.h>
-#include <linux/irq.h>
-
-#ifdef _STD_RW_IO
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#define DEVICE_NAME "sis_aegis_touch_device"
-static int sis_char_devs_count = 1;        /* device count */
-static int sis_char_major = 0;
-static struct cdev sis_char_cdev;
-static struct class *sis_char_class = NULL;
-#endif
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
-static struct workqueue_struct *sis_wq;
-struct sis_ts_data *ts_bak = 0;
-struct sisTP_driver_data *TPInfo = NULL;
-static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void sis_ts_early_suspend(struct early_suspend *h);
-static void sis_ts_late_resume(struct early_suspend *h);
-#endif
-
-#ifdef CONFIG_X86
-//static const struct i2c_client_address_data addr_data;
-/* Insmod parameters */
-static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
-#endif
-
-#ifdef _CHECK_CRC
-uint16_t cal_crc (char* cmd, int start, int end);
-#endif
-
-void PrintBuffer(int start, int length, char* buf)
-{
-	int i;
-	for ( i = start; i < length; i++ )
-	{
-		printk("%02x ", buf[i]);
-		if (i != 0 && i % 30 == 0)
-			printk("\n");
-	}
-	printk("\n");	
-}
-
-int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
-{
-    int ret = -1;
-    struct i2c_msg msg[1];
-
-    msg[0].addr = client->addr;
-    msg[0].flags = 0; //Write
-    msg[0].len = wlength;
-    msg[0].buf = (unsigned char *)wdata;
-
-    ret = i2c_transfer(client->adapter, msg, 1);
-
-    return ret;
-}
-
-int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
-{
-    int ret = -1;
-    struct i2c_msg msg[1];
-
-    msg[0].addr = client->addr;
-    msg[0].flags = I2C_M_RD; //Read
-    msg[0].len = rlength;
-    msg[0].buf = rdata;
-
-    ret = i2c_transfer(client->adapter, msg, 1);
-
-    return ret;
-}
-
-int sis_cul_unit(uint8_t report_id)
-{
-	int basic = 6;
-	int area = 2;
-	int pressure = 1;
-	int ret = basic;
-	
-	if (report_id != ALL_IN_ONE_PACKAGE)
-	{
-		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
-		{
-			ret += area;
-		}
-		if (IS_PRESSURE(report_id))
-		{
-			ret += pressure;
-		}
-	}
-	
-	return ret;	
-}
-
-int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
-{
-	uint8_t tmpbuf[MAX_BYTE] = {0};	//MAX_BYTE = 64;
-#ifdef _CHECK_CRC
-	uint16_t buf_crc = 0;
-	uint16_t package_crc = 0;
-	int l_package_crc = 0;
-	int crc_end = 0;
-#endif
-    int ret = -1;
-    int touchnum = 0;
-    int p_count = 0;
-    int touc_formate_id = 0;
-    int locate = 0;
-    bool read_first = true;
-    
-/*
-		New i2c format 
-	* buf[0] = Low 8 bits of byte count value
-	* buf[1] = High 8 bits of byte counte value
-	* buf[2] = Report ID
-	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
-	* buf[touch num * 6 + 3] = Touch numbers
-	* 
-	* One touch point information include 6 bytes, the order is 
-	* 
-	* 1. status = touch down or touch up
-	* 2. id = finger id 
-	* 3. x axis low 8 bits
-	* 4. x axis high 8 bits
-	* 5. y axis low 8 bits
-	* 6. y axis high 8 bits
-	* 
-*/
-	do
-	{
-		if (locate >= PACKET_BUFFER_SIZE)
-		{
-			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
-			return -1;
-		}
-		
-		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
-
-#ifdef _DEBUG_PACKAGE
-		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
-		PrintBuffer(0, 64, tmpbuf);	
-#endif			
-
-		if(ret < 0 )
-		{
-			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
-			return ret;
-		}
-		// error package length of receiving data
-		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
-		{
-			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
-			return -1;	
-		}
-		
-		if (read_first)
-		{
-#ifdef _SUPPORT_BUTTON_TOUCH
-			// access BUTTON TOUCH event and BUTTON NO TOUCH event
-			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
-			{
-				memcpy(&buf[0], &tmpbuf[0], 7);
-				return touchnum; 	//touchnum is 0
-			}
-#endif 
-			// access NO TOUCH event unless BUTTON NO TOUCH event
-			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
-			{
-				return touchnum;	//touchnum is 0
-			}
-		}
-
-		//skip parsing data when two devices are registered at the same slave address
-		//parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
-		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
-		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
-		{
-			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
-			return -1;		
-		}
-		
-		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	//start from 0
-		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
-		{
-			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
-			{
-				p_count -= BYTE_CRC_I2C;	//delete 2 byte crc
-			}
-			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
-			{
-				p_count -= BYTE_CRC_HIDI2C;
-			}
-			else	//should not be happen
-			{
-				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
-				return -1;
-			}
-
-			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
-			{
-				p_count -= BYTE_SCANTIME;
-			}
-		}
-		//else {}    						// For ALL_IN_ONE_PACKAGE
-		
-		if (read_first)
-		{
-			touchnum = tmpbuf[p_count]; 	
-		}
-		else
-		{
-			if (tmpbuf[p_count] != 0)
-			{
-				printk(KERN_ERR "sis_ReadPacket: get error package\n");
-				return -1;
-			}
-		}
-
-#ifdef _CHECK_CRC
-		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
-		buf_crc = cal_crc(tmpbuf, 2, crc_end); //sub bytecount (2 byte)
-		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
-		package_crc = ((tmpbuf[l_package_crc] & 0xff) | ((tmpbuf[l_package_crc + 1] & 0xff) << 8));
-			
-		if (buf_crc != package_crc)
-		{
-			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
-			return -1;
-		}
-#endif	
-		memcpy(&buf[locate], &tmpbuf[0], 64);	//Buf_Data [0~63] [64~128]
-		locate += 64;
-		read_first = false;
-		
-	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
-
-	return touchnum;
-}	
-
-
-int check_gpio_interrupt(void)
-{
-    int ret = 0;
-    //TODO
-    //CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING.
-    ret = gpio_get_value(GPIO_IRQ);
-    return ret;
-}
-
-void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
-{
-	int i = 0;
-	uint8_t diff_keybit_state= 0x0; //check keybit_state is difference with pre_keybit_state
-	uint8_t key_value = 0x0; //button location for binary
-	uint8_t  key_pressed = 0x0; //button is up or down
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-
-	if (!ts)
-	{
-		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
-		return;
-	}
-
-	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
-
-	if (diff_keybit_state)
-	{
-		for (i = 0; i < BUTTON_KEY_COUNT; i++)
-		{
-		    if ((diff_keybit_state >> i) & 0x01)
-			{
-				key_value = diff_keybit_state & (0x01 << i);
-				key_pressed = (keybit_state >> i) & 0x01;
-				switch (key_value)
-				{
-					case MSK_COMP:
-						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
-						printk(KERN_ERR "%s : MSK_COMP %d \n", __func__ , key_pressed);
-						break;
-					case MSK_BACK:
-						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
-						printk(KERN_ERR "%s : MSK_BACK %d \n", __func__ , key_pressed);
-						break;
-					case MSK_MENU:
-						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
-						printk(KERN_ERR "%s : MSK_MENU %d \n", __func__ , key_pressed);
-						break;
-					case MSK_HOME:
-						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
-						printk(KERN_ERR "%s : MSK_HOME %d \n", __func__ , key_pressed);
-						break;
-					case MSK_NOBTN:
-						//Release the button if it touched.
-					default:
-						break;
-				}
-			}
-		}
-		TPInfo->pre_keybit_state = keybit_state;
-	}
-}
-
-
-static void sis_ts_work_func(struct work_struct *work)
-{
-	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
-    int ret = -1;
-    int point_unit;  
-	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
-	uint8_t i = 0, fingers = 0;
-	uint8_t px = 0, py = 0, pstatus = 0;
-	uint8_t p_area = 0;
-    uint8_t p_preasure = 0;
-#ifdef _SUPPORT_BUTTON_TOUCH	
-	int button_key;
-	uint8_t button_buf[10] = {0};
-#endif
-
-#ifdef _ANDROID_4
-	bool all_touch_up = true;
-#endif
-	
-	mutex_lock(&ts->mutex_wq); 
-
-    /* I2C or SMBUS block data read */
-    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
-#ifdef _DEBUG_PACKAGE_WORKFUNC
-	printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
-	PrintBuffer(0, 64, buf);			
-	if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (ret > 5))
-	{
-		printk(KERN_INFO "chaoban test: Buf_Data [64~125] \n");
-		PrintBuffer(64, 128, buf);	
-	}
-#endif
-
-// add 
-#ifdef _SUPPORT_BUTTON_TOUCH
-	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
-#endif
-
-	if (ret < 0) // Error Number
-	{
-	    printk(KERN_INFO "chaoban test: ret = -1\n");
-		goto err_free_allocate;
-	}
-#ifdef _SUPPORT_BUTTON_TOUCH
-	// access BUTTON TOUCH event and BUTTON NO TOUCH even
-	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
-	{
-		//fingers = 0; //modify
-		button_key = ((button_buf[BUTTON_STATE] & 0xff) | ((button_buf[BUTTON_STATE + 1] & 0xff)<< 8));		
-		ts_report_key(ts->client, button_key);
-		//goto err_free_allocate; //modify
-	}
-#endif
-	// access NO TOUCH event unless BUTTON NO TOUCH event
-	else if (ret == 0)
-	{
-		fingers = 0;
-		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
-		goto label_send_report;  //need to report input_mt_sync()
-	}
-	
-	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
-	
-	/* Parser and Get the sis9200 data */
-	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
-	fingers = ret;
-	
-	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
-	
-	for (i = 0; i < fingers; i++) // fingers 10 =  0 ~ 9
-	{
-        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
-        {
-			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	// Calc point status
-			pstatus += 64;
-		}
-		else 
-		{
-			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	// Calc point status
-		}
-
-	    px = pstatus + 2;                   			// Calc point x_coord
-	    py = px + 2;                        			// Calc point y_coord
-
-		if ((buf[pstatus]) == TOUCHUP)
-		{
-			TPInfo->pt[i].Width = 0;
-			TPInfo->pt[i].Height = 0;
-			TPInfo->pt[i].Pressure = 0;
-		}
-		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
-		{
-			TPInfo->pt[i].Width = 1;
-			TPInfo->pt[i].Height = 1;
-			TPInfo->pt[i].Pressure = 1;			
-		}
-		else if ((buf[pstatus]) == TOUCHDOWN)
-		{	
-			p_area = py + 2;
-			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
-
-			//area		
-			if (IS_AREA(buf[P_REPORT_ID]))
-			{
-				TPInfo->pt[i].Width = buf[p_area] & 0xff;
-				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
-			}
-			else 
-			{
-				TPInfo->pt[i].Width = 1;
-				TPInfo->pt[i].Height = 1;
-			}
-			//preasure
-			if (IS_PRESSURE(buf[P_REPORT_ID]))
-				TPInfo->pt[i].Pressure = (buf[p_preasure]);
-			else 
-				TPInfo->pt[i].Pressure = 1;				
-		}
-		else
-		{
-			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
-			goto err_free_allocate;
-		}
-		
-		TPInfo->pt[i].id = (buf[pstatus + 1]);
-		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
-        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
-	}
-		
-#ifdef _DEBUG_REPORT
-	for (i = 0; i < TPInfo->fingers; i++)
-	{
-		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
-	}
-#endif
-
-label_send_report:
-/* Report co-ordinates to the multi-touch stack */
-#ifdef _ANDROID_4	
-	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
-	{
-		if(TPInfo->pt[i].Pressure)
-		{
-			TPInfo->pt[i].Width *= AREA_UNIT;	
-			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
-			TPInfo->pt[i].Height *= AREA_UNIT;
-			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
-			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
-			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
-			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
-			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);     //Android 2.3
-			input_mt_sync(ts->input_dev);
-			all_touch_up = false;
-		}
-		
-		if (i == (TPInfo->fingers -1) && all_touch_up == true)
-		{
-			input_mt_sync(ts->input_dev);
-		}
-	}
-
-	if(TPInfo->fingers == 0)
-	{
-		input_mt_sync(ts->input_dev);
-	}
-#else
-	i = 0;
-	do
-	{
-		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
-		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
-		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
-		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
-		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
-		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);		//Android 2.3
-		input_mt_sync(ts->input_dev);
-		i++;
-	}
-	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
-#endif
-	input_sync(ts->input_dev);
-
-err_free_allocate:
-
-    if (ts->use_irq)
-    {
-#ifdef _INT_MODE_1 //case 1 mode
-	    //TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high
-	    ret = check_gpio_interrupt();	//interrupt pin is still LOW, read data until interrupt pin is released.
-	    if (!ret)
-	    {
-	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
-	    }
-	    else
-	    {
-			if (TPInfo->pre_keybit_state)
-			{
-				ts_report_key(ts->client, 0x0);	//clear for interrupt
-			}
-			
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-        	{
-				enable_irq(ts->client->irq);
-			}
-	    }
-#else // case 2 mode
-
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-		{
-			enable_irq(ts->client->irq);
-		}
-#endif
-	}
-
-	mutex_unlock(&ts->mutex_wq);
-    return;
-}
-
-static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
-{
-	int i = 0;
-	for(i = 0; i < max; i++)
-	{
-		TPInfo->pt[i].id = -1;
-		TPInfo->pt[i].x = 0;
-		TPInfo->pt[i].y = 0;
-		TPInfo->pt[i].Pressure = 0;
-		TPInfo->pt[i].Width = 0;
-	}
-	TPInfo->id = 0x0;
-	TPInfo->fingers = 0;
-}
-
-static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
-{
-	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
-	queue_work(sis_wq, &ts->work);
-	if (!ts->use_irq)
-	{	// For Polling mode
-	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
-	}
-	return HRTIMER_NORESTART;
-}
-
-static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
-{
-	struct sis_ts_data *ts = dev_id;
-	
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#else
-	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#endif
-	{
-		disable_irq_nosync(ts->client->irq);
-	}
-	queue_work(sis_wq, &ts->work);
-		
-	return IRQ_HANDLED;
-}
-
-static int initial_irq(void)
-{
-	int ret = 0;
-#ifdef _I2C_INT_ENABLE
-	/* initialize gpio and interrupt pins */
-	/* TODO */
-	ret = gpio_request(GPIO_IRQ, "GPIO_133");	// ex. GPIO_133 for interrupt mode
-	if (ret < 0)
-	{
-		// Set Active Low. Please reference the file include/linux/interrupt.h
-		printk(KERN_ERR "sis_ts_probe: Failed to gpio_request\n");
-		printk(KERN_ERR "sis_ts_probe: Fail : gpio_request was called before this driver call\n");
-	}	
-	/* setting gpio direction here OR boardinfo file*/
-	/* TODO */
-#else
-	ret = -1;
-#endif
-	return ret;
-}
-
-uint16_t cal_crc (char* cmd, int start, int end)
-{
-	int i = 0;
-	uint16_t crc = 0;
-	for (i = start; i <= end ; i++)
-	{
-		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
-	}
-	return crc;
-}
-
-uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
-{
-	int i = 0;
-	uint16_t crc = 0;
-	
-	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
-	for (i = start; i <= end ; i++)
-	{
-		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
-	}
-	return crc;
-}
-
-void write_crc (unsigned char *buf, int start, int end)
-{
-	uint16_t crc = 0;
-	crc = cal_crc (buf, start , end);
-	buf[end+1] = (crc >> 8)& 0xff;
-	buf[end+2] = crc & 0xff;
-}
-
-/*
- * When you will send commad to chip, you should use this function on 
- * the first time.
- * 
- * Return:If switch success return ture, else return false.
- */
-bool sis_switch_to_cmd_mode(struct i2c_client *client)
-{
-	int ret = -1;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
-		0x00, 0x85, 0x0d, 0x51, 0x09};
-	uint8_t sis817_cmd_enable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
-		0x00, 0x09, 0x00, 0x85, 0x5c, 0x21, 0x01};
-	
-	
-	
-	//Send 85 CMD - PWR_CMD_ACTIVE
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}
-	
-	msleep(100);
-	memset(tmpbuf, 0, sizeof(tmpbuf));
-	
-	//Send 85 CMD - ENABLE_DIAGNOSIS_MODE
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_enable_diagnosis), sis817_cmd_enable_diagnosis);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	msleep(50);
-	return true;	
-}
-
-/*
- * When chip in the command mode will switch to work, you should use 
- * this function.
- * 
- * Return:If switch success return ture, else return false.
- */
-bool sis_switch_to_work_mode(struct i2c_client *client)
-{
-	int ret = -1;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
-		0x00, 0x85, 0x3c, 0x50, 0x09};
-	uint8_t sis817_cmd_disable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
-		0x00, 0x09, 0x00, 0x85, 0x6d, 0x20, 0x01};
-	
-	
-	//Send 85 CMD - PWR_CMD_FW_CTRL
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}
-
-	memset(tmpbuf, 0, sizeof(tmpbuf));
-	
-	//Send 85 CMD - DISABLE_DIAGNOSIS_MODE
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_disable_diagnosis), sis817_cmd_disable_diagnosis);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	msleep(50);
-	return true;
-}
-
-/*
- * Use this function get FW ID.
- */
-bool sis_get_fw_id(struct i2c_client *client)
-{
-  	int ret = 0;
-  	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_get_FW_ID[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
-		0x00, 0x86, 0x00, 0x0c, 0xc0, 0x00, 0xa0, 0x04, 0x00};
-	
-	sis817_cmd_get_FW_ID[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_get_FW_ID, 8, 13, 0x86));
-
-	if(!sis_switch_to_cmd_mode(client)){
-		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
-		return false;
-	}
-	
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_get_FW_ID), sis817_cmd_get_FW_ID);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
-	}
-
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	printk(KERN_INFO "SiS FW ID : ");
-	PrintBuffer(8, 12, tmpbuf);	
-
-	if(!sis_switch_to_work_mode(client)){
-		printk(KERN_ERR "SiS Switch to Work mode error.\n");
-		return false;
-	}
-	
-	if(ret < 0) return false;
-	return true;
-		
-}
-
-/*
- * Use this function check chip status.
- * 
- * Return:Ture is chip on the work function, else is chip not ready.
- */
-bool sis_check_fw_ready(struct i2c_client *client)
-{
-  	int ret = 0;
-  	int check_num = 10;
-  	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_check_ready[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
-		0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
-	
-	
-	sis817_cmd_check_ready[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_ready, 8, 13, 0x86));
-	
-
-	if(!sis_switch_to_cmd_mode(client)){
-		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
-		return false;
-	}
-	
-	while(check_num--){
-		printk(KERN_ERR "SiS Check FW Ready.\n");
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_check_ready), sis817_cmd_check_ready);
-		if(ret < 0){
-			printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
-		}
-		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-		if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return NACK\n");
-		}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return Unknow\n");
-		}else{
-			if(tmpbuf[9] == 1){
-				printk(KERN_ERR "SiS FW READY.\n");
-				break;
-			}
-		}
-		printk(KERN_ERR "SiS CHECK FW READY - Retry:%d.\n", (10-check_num));	
-		msleep(50);
-	}
-	
-	if(!sis_switch_to_work_mode(client)){
-		printk(KERN_ERR "SiS Switch to Work mode error.\n");
-		return false;
-	}
-	
-	if(check_num == 0) return false;
-	return true;
-		
-}
-
-/*
- * Use this function to change chip power mode. 
- * 
- * mode:POWER_MODE_FWCTRL, power control by FW.
- * 		POWER_MODE_ACTIVE, chip always work on time.
- * 		POWER_MODE_SLEEP,  chip on the sleep mode.
- * 
- * Return:Ture is change power mode success.
- */
-bool sis_change_fw_mode(struct i2c_client *client, enum SIS_817_POWER_MODE mode)
-{
-	int ret = -1;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x3c, 0x50, 0x09};
-	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x0d, 0x51, 0x09};
-	uint8_t sis817_cmd_sleep[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x5e, 0x52, 0x09};
-	
-	
-	switch(mode)
-	{
-	case POWER_MODE_FWCTRL:
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
-		break;
-	case POWER_MODE_ACTIVE:
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
-		break;
-	case POWER_MODE_SLEEP:
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_sleep), sis817_cmd_sleep);
-		break;
-	default:
-		return false;
-		break;
-	}
-
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Power CMD Faile - 85\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Power CMD Faile - 85\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Power CMD Return NACK - 85\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Power CMD Return Unknow- 85\n");
-		return false;
-	}
-	
-	msleep(100);
-	
-	return true;
-}
-
-/*
- * Use this function to get chip work status. 
- * 
- * Return:-1 is get firmware work status error.
- * 		  POWER_MODE_FWCTRL, power control by FW.
- * 		  POWER_MODE_ACTIVE, chip always work on time.
- * 		  POWER_MODE_SLEEP,  chip on the sleep mode.
- */
-enum SIS_817_POWER_MODE sis_get_fw_mode(struct i2c_client *client)
-{
-	int ret;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_check_power_mode[14] = {0x04, 0x00, 0x0c, 0x00, 
-		0x09, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
-
-	printk(KERN_INFO "SiS Get FW Mode.\n");	
-	sis817_cmd_check_power_mode[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_power_mode, 8, 13, 0x86));
-	
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_check_power_mode), sis817_cmd_check_power_mode);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Get FW Mode CMD Faile - 86\n");
-	}else{
-		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-		if(ret < 0){
-			printk(KERN_ERR "SiS READ Get FW Mode CMD Faile - 86\n");
-		}else{
-			if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return NACK\n");
-			}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return Unknow\n");
-				PrintBuffer(0, sizeof(tmpbuf), tmpbuf);
-			}
-		}
-	}
-	
-	switch(tmpbuf[10])
-	{
-	case POWER_MODE_FWCTRL:
-		return POWER_MODE_FWCTRL;
-	case POWER_MODE_ACTIVE:
-		return POWER_MODE_ACTIVE;
-	case POWER_MODE_SLEEP:
-		return POWER_MODE_SLEEP;
-	default:
-		break;
-	}
-
-	return -1;
-}
-
-/*
- * Use this function to reset chip. 
- */
-void sis_fw_softreset(struct i2c_client *client)
-{
-
-	int ret = 0;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_reset[8] = {0x04, 0x00, 0x06, 0x00, 0x09, 0x00, 0x82, 0x00};
-	
-
-	sis817_cmd_reset[BUF_CRC_PLACE] = (0xFF & cal_crc(sis817_cmd_reset, 6, 6));
-
-	printk(KERN_ERR "SiS Software Reset.\n");
-	if(!sis_switch_to_cmd_mode(client)){
-		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
-		return;
-	}
-	
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_reset), sis817_cmd_reset);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Reset CMD Faile - 82\n");
-	}
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Reset CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Reset CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
-	}	
-	msleep(2000);
-}
-
-
-#ifdef _STD_RW_IO
-#define BUFFER_SIZE MAX_BYTE
-static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
-{
-	 int ret = 0;
-	 char *kdata;
-	 char cmd;
-	 
-	 printk(KERN_INFO "sis_cdev_write.\n");
-	 
-	 if (ts_bak == 0)
-    	return -13;
-    	
-    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
-    if (!ret) {
-        printk(KERN_ERR "cannot access user space memory\n");
-        return -11;
-    }
-
-	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-     if (kdata == 0)
-    	return -12;
-    	
-     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
-     if (ret) {
-        printk(KERN_ERR "copy_from_user fail\n");
-        kfree(kdata);
-        return -14;
-     } 
-#if 0
-	PrintBuffer(0, count, kdata);
-#endif
-		
-	cmd = kdata[6];
-
-    printk(KERN_INFO "io cmd=%02x\n", cmd);
-
-//Write & Read
-    ret = sis_command_for_write(ts_bak->client, count, kdata);
-    if (ret < 0) {
-        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
-		kfree(kdata);
-		return -21;
-	}
-
-    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
-    {
-        printk(KERN_ERR "copy_to_user fail\n" );
-        ret = -19;
-    }
-
-    kfree( kdata );
-
-	return ret;
-}
-
-//for get system time
-static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
-{
-	 int ret = 0;
-	 char *kdata;
-	 char cmd;
-	 int i;
-	 printk(KERN_INFO "sis_cdev_read.\n");
-	 
-	 if (ts_bak == 0)
-    	return -13;
-    	
-    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
-    if (!ret) {
-        printk(KERN_ERR "cannot access user space memory\n");
-        return -11;
-    }
-
-	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-     if (kdata == 0)
-    	return -12;
-    	
-     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
-     if (ret) {
-        printk(KERN_ERR "copy_from_user fail\n");
-        kfree(kdata);
-        return -14;
-     }    
-#if 0
-    PrintBuffer(0, count, kdata);
-#endif
-	 cmd = kdata[6];
-	 //for making sure AP communicates with SiS driver
-    if(cmd == 0xa2)
-    {
-		kdata[0] = 5;
-		kdata[1] = 0;
-		kdata[3] = 'S';
-		kdata[4] = 'i';
-		kdata[5] = 'S';
-		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
-		{
-			printk(KERN_ERR "copy_to_user fail\n" );
-			kfree( kdata );
-			return -19;
-		}
-
-		kfree( kdata );
-		return 3;	
-	}
-//Write & Read
-    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
-    if (ret < 0) {
-        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
-		kfree(kdata);
-		return -21;
-	}
-
-	ret = kdata[0] | (kdata[1] << 8);
-
-/*
-    for ( i = 0; i < BUFFER_SIZE - 1; i++ ) {
-	    kdata[i] = kdata[i+1];
-    }
-*/
-
-    printk(KERN_INFO "%d\n", ret);
-
-    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
-    {
-        printk("%02x ", kdata[i]);
-    }
-
-    printk( "\n" );
-
-    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
-    {
-        printk(KERN_ERR "copy_to_user fail\n" );
-        ret = -19;
-    }
-
-    kfree( kdata );
-
-	return ret;
-}
-
-#undef BUFFER_SIZE
-
-static int sis_cdev_open(struct inode *inode, struct file *filp)
-{
-	printk(KERN_INFO "sis_cdev_open.\n");
-	if ( ts_bak == 0 )
-    	return -13;
-
-	msleep(200);
-	if (ts_bak->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#else
-		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#endif	
-		{
-			disable_irq(ts_bak->client->irq);
-		}
-		else
-		{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
-#else
-			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
-#endif	
-		}
-	}
-	hrtimer_cancel(&ts_bak->timer);
-
-	flush_workqueue(sis_wq); 	   // only flush sis_wq
-    
-    msleep(200);
-
-	return 0; /* success */
-}
-
-static int sis_cdev_release(struct inode *inode, struct file *filp)
-{
-	printk(KERN_INFO "sis_cdev_release.\n");
-	 msleep(200);
-    if (ts_bak == 0)
-    	return -13;
-
-	if (ts_bak->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif	
-		{
-			enable_irq(ts_bak->client->irq);
-		}
-	}
-	else
-		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-
-    return 0;
-}
-
-static const struct file_operations sis_cdev_fops = {
-	.owner	= THIS_MODULE,
-	.read	= sis_cdev_read,
-	.write	= sis_cdev_write,
-	.open	= sis_cdev_open,
-	.release= sis_cdev_release,
-};
-
-static int sis_setup_chardev(struct sis_ts_data *ts)
-{
-	
-	dev_t dev = MKDEV(sis_char_major, 0);
-	int alloc_ret = 0;
-	int cdev_err = 0;
-	int input_err = 0;
-	struct device *class_dev = NULL;
-	void *ptr_err;
-	
-	printk("sis_setup_chardev.\n");
-	
-	if (ts == NULL) 
-	{
-	  input_err = -ENOMEM;
-	  goto error;
-	} 
-	 // dynamic allocate driver handle
-	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
-	if (alloc_ret)
-		goto error;
-		
-	sis_char_major = MAJOR(dev);
-	cdev_init(&sis_char_cdev, &sis_cdev_fops);
-	sis_char_cdev.owner = THIS_MODULE;
-	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
-	
-	if (cdev_err) 
-		goto error;
-	
-	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
-	
-	// register class
-	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
-	if(IS_ERR(ptr_err = sis_char_class)) 
-	{
-		goto err2;
-	}
-	
-	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
-	
-	if(IS_ERR(ptr_err = class_dev)) 
-	{
-		goto err;
-	}
-	
-	return 0;
-error:
-	if (cdev_err == 0)
-		cdev_del(&sis_char_cdev);
-	if (alloc_ret == 0)
-		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
-	if(input_err != 0)
-	{
-		printk("sis_ts_bak error!\n");
-	}
-err:
-	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
-err2:
-	class_destroy(sis_char_class);
-	return -1;
-}
-#endif
-
-static int sis_ts_probe(
-	struct i2c_client *client, const struct i2c_device_id *id)
-{
-	int ret = 0;
-	struct sis_ts_data *ts = NULL;
-	struct sis_i2c_rmi_platform_data *pdata = NULL;
-
-    printk(KERN_INFO "sis_ts_probe\n");
-
-    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
-    if (TPInfo == NULL) 
-    {
-		ret = -ENOMEM;
-		goto err_alloc_data_failed;
-	}
-
-	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
-	if (ts == NULL) 
-	{
-		ret = -ENOMEM;
-		goto err_alloc_data_failed;
-	}
-
-	ts_bak = ts;
-
-	mutex_init(&ts->mutex_wq);
-	
-	//1. Init Work queue and necessary buffers
-	INIT_WORK(&ts->work, sis_ts_work_func);
-	ts->client = client;
-	i2c_set_clientdata(client, ts);
-    pdata = client->dev.platform_data;
-
-	if (pdata)
-		ts->power = pdata->power;
-	if (ts->power) 
-	{
-		ret = ts->power(1);
-		if (ret < 0) 
-		{
-			printk(KERN_ERR "sis_ts_probe power on failed\n");
-			goto err_power_failed;
-		}
-	}
-
-	//2. Allocate input device
-	ts->input_dev = input_allocate_device();
-	if (ts->input_dev == NULL) 
-	{
-		ret = -ENOMEM;
-		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
-		goto err_input_dev_alloc_failed;
-	}
-
-	//This input device name should be the same to IDC file name.
-	ts->input_dev->name = "sis_touch";//"SiS9200-i2c-touchscreen";
-
-	sis_get_fw_id(client);
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-		//sis_check_fw_ready(client);
-#endif
-
-	set_bit(EV_ABS, ts->input_dev->evbit);
-	set_bit(EV_KEY, ts->input_dev->evbit);
-    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
-    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
-    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
-
-#ifdef _ANDROID_4
-	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
-    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
-    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
-    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
-    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
-#else
-    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
-    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
-    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
-    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
-#endif
-
-    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
-	
-    /* add for touch keys */
-	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
-	set_bit(KEY_BACK, ts->input_dev->keybit);
-	set_bit(KEY_MENU, ts->input_dev->keybit);
-	set_bit(KEY_HOME, ts->input_dev->keybit);
-
-	//3. Register input device to core
-	ret = input_register_device(ts->input_dev);
-
-	if (ret) 
-	{
-		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
-		goto err_input_register_device_failed;
-	}
-	
-	//4. irq or timer setup
-	ret = initial_irq();
-	if (ret < 0) 
-	{
-
-	}
-	else
-	{
-		client->irq = gpio_to_irq(GPIO_IRQ);
-		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
-		if (ret == 0) 
-		{
-		   ts->use_irq = 1;
-		}
-		else 
-		{
-			dev_err(&client->dev, "request_irq failed\n");
-		}
-	}
-
-	ts->desc = irq_to_desc(ts_bak->client->irq);
-	
-	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	ts->timer.function = sis_ts_timer_func;
-
-	if (!ts->use_irq) 
-	{
-		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-	}
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
-	ts->early_suspend.suspend = sis_ts_early_suspend;
-	ts->early_suspend.resume = sis_ts_late_resume;
-	register_early_suspend(&ts->early_suspend);
-#endif
-	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
-	
-	if (ts->use_irq)
-	{
-#ifdef _INT_MODE_1
-		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
-#else
-		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
-#endif
-	}
-	
-#ifdef _STD_RW_IO
-	ret = sis_setup_chardev(ts);
-	if(ret)
-	{
-		printk( KERN_INFO"sis_setup_chardev fail\n");
-	}
-#endif
-
-	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
-
-	return 0;
-
-err_input_register_device_failed:
-	input_free_device(ts->input_dev);
-
-err_input_dev_alloc_failed:
-err_power_failed:
-	kfree(ts);
-err_alloc_data_failed:
-	return ret;
-}
-
-static int sis_ts_remove(struct i2c_client *client)
-{
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	unregister_early_suspend(&ts->early_suspend);
-#endif
-	if (ts->use_irq)
-		free_irq(client->irq, ts);
-	else
-		hrtimer_cancel(&ts->timer);
-	input_unregister_device(ts->input_dev);
-	kfree(ts);
-	return 0;
-}
-
-static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
-{
-	int ret = 0;
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-	int retry = 5;
-#endif
-
-	TPInfo->pre_keybit_state = 0x0;
-
-	if (ts->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#endif
-		{
-			disable_irq(client->irq);
-		}
-	}
-	else
-		hrtimer_cancel(&ts->timer);
-	flush_workqueue(sis_wq); 	   		// only flush sis_wq
-//	flush_scheduled_work(); 		   	// flush all of workqueue in kernel
-//	ret = cancel_work_sync(&ts->work); 	// only cancel one work(sis_ts_work_func), 
-										// but there maybe are others in workqueue.
-/*
-	// For cancel_work_sync()
-	if (ret && ts->use_irq) //if work was pending disable-count is now 2
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-		{
-			enable_irq(client->irq);
-		}
-	}
-*/
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-		while ((sis_get_fw_mode(client) != POWER_MODE_SLEEP))
-		{
-			
-			if(sis_change_fw_mode(client, POWER_MODE_SLEEP)){
-				printk(KERN_ERR "sis_ts_suspend: change mode retry - %d\n", 5-retry);
-			}
-
-			if (retry == 0){
-				printk(KERN_ERR "sis_ts_suspend: change mode failed\n");
-				break;
-			}
-
-			retry--;
-			msleep(50);
-		}
-#endif
-
-
-#if 0
-	/* Turn off SiS Chip*/
-	/* TODO */
-	gpio_direction_output(TOUCH_RESET_PIN, 0);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
-//	msleep(5);
-	gpio_direction_output(TOUCH_POWER_PIN, 0);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power off\n");
-#endif
-
-	if (ts->power) {
-		ret = ts->power(0);
-		if (ret < 0)
-			printk(KERN_ERR "sis_ts_suspend power off failed\n");
-	}
-	
-	return 0;
-}
-
-static int sis_ts_resume(struct i2c_client *client)
-{
-	int ret = 0;
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-	int retry = 5;
-#endif
-
-	if (ts->power)
-	{
-		ret = ts->power(1);
-		if (ret < 0)
-			printk(KERN_ERR "sis_ts_resume power on failed\n");
-	}
-
-#if 0
-	/* Turn on SiS Chip*/
-	/* TODO */
-	gpio_direction_output(TOUCH_POWER_PIN, 1);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power on\n");
-	msleep(5);
-	gpio_direction_output(TOUCH_RESET_PIN, 1);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
-	msleep(5);
-	gpio_direction_output(TOUCH_RESET_PIN, 0);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
-	msleep(5);
-	gpio_direction_output(TOUCH_RESET_PIN, 1);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
-#endif
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-		while ((sis_get_fw_mode(client) != POWER_MODE_FWCTRL))
-		{
-			
-			if(sis_change_fw_mode(client, POWER_MODE_FWCTRL)){
-				printk(KERN_ERR "sis_ts_resume: change mode retry - %d\n", 5-retry);
-			}
-
-			if (retry == 0){
-				printk(KERN_ERR "sis_ts_resume: change mode failed\n");
-				break;
-			}
-				
-			retry--;
-			msleep(50);
-		}
-#endif
-		//sis_fw_softreset(client);
-
-	if (ts->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-		{
-			enable_irq(client->irq);
-		}
-	}
-	else
-		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-
-	return 0;
-}
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void sis_ts_early_suspend(struct early_suspend *h)
-{
-	struct sis_ts_data *ts;
-	TPInfo->pre_keybit_state = 0x0;
-	ts = container_of(h, struct sis_ts_data, early_suspend);
-	sis_ts_suspend(ts->client, PMSG_SUSPEND);
-}
-
-static void sis_ts_late_resume(struct early_suspend *h)
-{
-	struct sis_ts_data *ts;
-	ts = container_of(h, struct sis_ts_data, early_suspend);
-	sis_ts_resume(ts->client);
-}
-#endif
-
-static const struct i2c_device_id sis_ts_id[] = {
-	{ SIS_I2C_NAME, 0 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(i2c, sis_ts_id);
-
-static struct i2c_driver sis_ts_driver = {
-	.probe		= sis_ts_probe,
-	.remove		= sis_ts_remove,
-#ifndef CONFIG_HAS_EARLYSUSPEND
-	.suspend	= sis_ts_suspend,
-	.resume		= sis_ts_resume,
-#endif
-#ifdef CONFIG_X86
-    .class      = I2C_CLASS_HWMON,
-    .detect		= sis_ts_detect,
-	.address_list	= normal_i2c,
-#endif
-	.id_table	= sis_ts_id,
-	.driver = {
-		.name	= SIS_I2C_NAME,
-	},
-};
-
-static int __devinit sis_ts_init(void)
-{
-	printk( KERN_INFO "sis_ts_init\n" );
-	sis_wq = create_singlethread_workqueue("sis_wq");
-
-	if (!sis_wq)
-		return -ENOMEM;
-	return i2c_add_driver(&sis_ts_driver);
-}
-
-#ifdef CONFIG_X86
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int sis_ts_detect(struct i2c_client *client,
-		       struct i2c_board_info *info)
-{
-	const char *type_name;
-    printk(KERN_INFO "sis_ts_detect\n");
-	type_name = "sis_i2c_ts";
-	strlcpy(info->type, type_name, I2C_NAME_SIZE);
-	return 0;
-}
-#endif
-
-static void __exit sis_ts_exit(void)
-{
-#ifdef _STD_RW_IO
-	dev_t dev;
-#endif
-
-	printk(KERN_INFO "sis_ts_exit\n");
-	i2c_del_driver(&sis_ts_driver);
-	if (sis_wq)
-		destroy_workqueue(sis_wq);
-
-#ifdef _STD_RW_IO
-	dev = MKDEV(sis_char_major, 0);
-	cdev_del(&sis_char_cdev);
-	unregister_chrdev_region(dev, sis_char_devs_count);
-	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
-	class_destroy(sis_char_class);
-#endif
-}
-
-module_init(sis_ts_init);
-module_exit(sis_ts_exit);
-MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
-MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
deleted file mode 100644
index 1ace42a..0000000
--- a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
- *
- * Copyright (C) 2011 SiS, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * Date: 2012/11/13
- * Version:	Android_v2.05.00-A639-1113
- */
-#include <linux/version.h>
-
-#ifndef _LINUX_SIS_I2C_H
-#define _LINUX_SIS_I2C_H
-
-
-#define SIS_I2C_NAME "sis_i2c_ts"
-#define SIS_SLAVE_ADDR					0x5c
-#define TIMER_NS    					10000000 //10ms
-#define MAX_FINGERS						10
-
-
-/* For Android 4.0 							*/
-/* Only for Linux kernel 2.6.34 and later 	*/
-#define _ANDROID_4					//  ON/OFF
-
-/* For standard R/W IO*/
-#define _STD_RW_IO						//  ON/OFF
-
-/* Interrupt setting and modes */
-#define _I2C_INT_ENABLE					//  ON/OFF
-#define GPIO_IRQ 						133
-
-/*  Enable if use interrupt case 1 mode.  */
-/* 	Disable if use interrupt case 2 mode. */
-//#define _INT_MODE_1					//	ON/OFF
-
-/* IRQ STATUS */
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-#define IRQ_STATUS_DISABLED				0x200  
-#else
-#define IRQ_STATUS_DISABLED				(1<<16)
-#endif
-#define IRQ_STATUS_ENABLED				0x0
-
-/* Resolution mode */
-// Constant value 
-#define SIS_MAX_X						4095
-#define SIS_MAX_Y						4095
-
-#define ONE_BYTE						1
-#define FIVE_BYTE						5
-#define EIGHT_BYTE  					8
-#define SIXTEEN_BYTE					16
-#define PACKET_BUFFER_SIZE				128
-
-#define SIS_CMD_NORMAL					0x0
-#define SIS_CMD_SOFTRESET				0x82
-#define SIS_CMD_RECALIBRATE				0x87
-#define SIS_CMD_POWERMODE       		0x90
-#define MSK_TOUCHNUM					0x0f
-#define MSK_HAS_CRC						0x10
-#define MSK_DATAFMT						0xe0
-#define MSK_PSTATE						0x0f
-#define MSK_PID	                		0xf0
-#define RES_FMT							0x00
-#define FIX_FMT							0x40
-
-/* for new i2c format */
-#define TOUCHDOWN						0x3
-#define TOUCHUP							0x0
-#define MAX_BYTE						64
-#define	PRESSURE_MAX					255
-
-#ifdef _ANDROID_4
-#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
-#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
-#define AREA_UNIT						(5792/32)
-#else
-#define AREA_LENGTH_LONGER				31
-#define AREA_LENGTH_SHORT				31
-#endif
-
-
-#define FORMAT_MODE						1
-
-#define MSK_NOBTN						0
-#define MSK_COMP						1
-#define MSK_BACK						2
-#define MSK_MENU						4
-#define MSK_HOME						8
-
-#define P_BYTECOUNT						0 
-#define ALL_IN_ONE_PACKAGE				0x10
-#define IS_TOUCH(x)						(x & 0x1)
-#define IS_HIDI2C(x)					(x & 0x6)
-#define IS_AREA(x)						((x >> 4) & 0x1)
-#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
-#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
-//#define _DEBUG_PACKAGE				//  ON/OFF
-//#define _DEBUG_PACKAGE_WORKFUNC		//  ON/OFF
-//#define _DEBUG_REPORT					//  ON/OFF
-
-#ifdef OLD_FORMAT_AEGIS
-#define TOUCH_NUM						1
-#define BUTTON_KEY_COUNT				8
-#define BUTTON_TOUCH					0x05
-#define BUTTON_TOUCH_ONE_POINT			0x0A
-#define BUTTON_TOUCH_MULTI_TOUCH		0x0F
-#define MSK_BUTTON_POINT				0xf0
-#define BUTTON_TOUCH_SERIAL				0x70
-#define BUTTON_STATE					(CMD_BASE + 1)
-
-#else
-//#define _CHECK_CRC					//  ON/OFF
-//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
-#define TOUCH_FORMAT					0x1
-#define BUTTON_FORMAT					0x4
-#define HIDI2C_FORMAT					0x6
-#define P_REPORT_ID						2
-#define BUTTON_STATE					3
-#define BUTTON_KEY_COUNT				16
-#define BYTE_BYTECOUNT					2
-#define BYTE_COUNT						1
-#define BYTE_ReportID					1
-#define BYTE_CRC_HIDI2C					0
-#define BYTE_CRC_I2C					2
-#define BYTE_SCANTIME					2
-#define NO_TOUCH_BYTECOUNT				0x3
-#endif
-
-/* TODO */
-#define TOUCH_POWER_PIN					0
-#define TOUCH_RESET_PIN					1
-
-/* CMD Define */
-#define BUF_ACK_PLACE_L					4
-#define BUF_ACK_PLACE_H					5
-#define BUF_ACK_L						0xEF
-#define BUF_ACK_H						0xBE
-#define BUF_NACK_L						0xAD
-#define BUF_NACK_H						0xDE
-#define BUF_CRC_PLACE					7
-
-#endif /* _LINUX_SIS_I2C_H */
-
-enum SIS_817_POWER_MODE{
-	POWER_MODE_FWCTRL = 0x50,
-	POWER_MODE_ACTIVE = 0x51,
-	POWER_MODE_SLEEP  = 0x52
-};
-
-struct sis_i2c_rmi_platform_data {
-	int (*power)(int on);	/* Only valid in first array entry */
-};
-
-static const unsigned short crc16tab[256]= {
-		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
-        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
-        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
-        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
-        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
-        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
-        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
-        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
-        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
-        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
-        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
-        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
-        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
-        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
-        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
-        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
-        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
-        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
-        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
-        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
-        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
-        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
-        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
-        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
-        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
-        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
-        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
-        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
-        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
-        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
-        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
-        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
-};
-
-struct Point {
-	int id;
-	unsigned short x, y;   	// uint16_t ?
-	uint16_t Pressure;
-	uint16_t Width;
-	uint16_t Height;
-};
-
-struct sisTP_driver_data {
-	int id;
-	int fingers;
-	uint8_t pre_keybit_state;	
-	struct Point pt[MAX_FINGERS];
-};
-
-struct sis_ts_data {
-	int (*power)(int on);
-	int use_irq;
-	struct i2c_client *client;
-	struct input_dev *input_dev;
-	struct hrtimer timer;
-	struct irq_desc *desc;
-	struct work_struct work;
-	struct mutex mutex_wq;
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	struct early_suspend early_suspend;
-#endif
-};
-
-static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
-static int sis_ts_resume(struct i2c_client *client);

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-09 10:37 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 21+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-09 10:37 UTC (permalink / raw)
  To: linux-kernel, linux-input; +Cc: tammy0524

Hi,
This package of patch is to add support for multitouch behavior for SiS touch products.
The patch of SiS i2c multitouch driver is in input/touchscreen.

Signed-off-by: Tammy Tseng <tammy_tseng@sis.com>
--

diff --git a/linux-3.18.1/drivers/input/touchscreen/Kconfig b/linux-3.18.1/drivers/input/touchscreen/Kconfig
index edc8e27..e1d8003 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Kconfig
+++ b/linux-3.18.1/drivers/input/touchscreen/Kconfig
@@ -962,18 +962,4 @@ config TOUCHSCREEN_ZFORCE
 	  To compile this driver as a module, choose M here: the
 	  module will be called zforce_ts.
 
-config TOUCHSCREEN_SIS_I2C
-	tristate "SiS 9200 family I2C touchscreen driver"
-	depends on I2C
-	default y
-	help
-	  This enables support for SiS 9200 family over I2C based touchscreens.
-
-config FW_SUPPORT_POWERMODE
-		default n
-        bool "SiS FW support power mode"
-        depends on TOUCHSCREEN_SIS_I2C
-        help
-          This enables support power mode provided by SiS firmwave
-
 endif
diff --git a/linux-3.18.1/drivers/input/touchscreen/Makefile b/linux-3.18.1/drivers/input/touchscreen/Makefile
index e316477..090e61c 100644
--- a/linux-3.18.1/drivers/input/touchscreen/Makefile
+++ b/linux-3.18.1/drivers/input/touchscreen/Makefile
@@ -6,10 +6,6 @@
 
 wm97xx-ts-y := wm97xx-core.o
 
-ifdef CONFIG_TOUCHSCREEN_SIS_I2C
-obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)   += sis_i2c.o
-endif
-
 obj-$(CONFIG_OF_TOUCHSCREEN)		+= of_touchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
deleted file mode 100644
index 2e6fc1a..0000000
--- a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.c
+++ /dev/null
@@ -1,1725 +0,0 @@
-/* drivers/input/touchscreen/sis_i2c.c - I2C Touch panel driver for SiS 9200 family
- *
- * Copyright (C) 2011 SiS, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * Date: 2012/11/13
- * Version:	Android_v2.05.00-A639-1113
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#ifdef CONFIG_HAS_EARLYSUSPEND
-#include <linux/earlysuspend.h>
-#endif
-#include <linux/hrtimer.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "sis_i2c.h"
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <asm/uaccess.h>
-#include <linux/irq.h>
-
-#ifdef _STD_RW_IO
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#define DEVICE_NAME "sis_aegis_touch_device"
-static int sis_char_devs_count = 1;        /* device count */
-static int sis_char_major = 0;
-static struct cdev sis_char_cdev;
-static struct class *sis_char_class = NULL;
-#endif
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { SIS_SLAVE_ADDR, I2C_CLIENT_END };
-static struct workqueue_struct *sis_wq;
-struct sis_ts_data *ts_bak = 0;
-struct sisTP_driver_data *TPInfo = NULL;
-static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max);
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void sis_ts_early_suspend(struct early_suspend *h);
-static void sis_ts_late_resume(struct early_suspend *h);
-#endif
-
-#ifdef CONFIG_X86
-//static const struct i2c_client_address_data addr_data;
-/* Insmod parameters */
-static int sis_ts_detect(struct i2c_client *client, struct i2c_board_info *info);
-#endif
-
-#ifdef _CHECK_CRC
-uint16_t cal_crc (char* cmd, int start, int end);
-#endif
-
-void PrintBuffer(int start, int length, char* buf)
-{
-	int i;
-	for ( i = start; i < length; i++ )
-	{
-		printk("%02x ", buf[i]);
-		if (i != 0 && i % 30 == 0)
-			printk("\n");
-	}
-	printk("\n");	
-}
-
-int sis_command_for_write(struct i2c_client *client, int wlength, unsigned char *wdata)
-{
-    int ret = -1;
-    struct i2c_msg msg[1];
-
-    msg[0].addr = client->addr;
-    msg[0].flags = 0; //Write
-    msg[0].len = wlength;
-    msg[0].buf = (unsigned char *)wdata;
-
-    ret = i2c_transfer(client->adapter, msg, 1);
-
-    return ret;
-}
-
-int sis_command_for_read(struct i2c_client *client, int rlength, unsigned char *rdata)
-{
-    int ret = -1;
-    struct i2c_msg msg[1];
-
-    msg[0].addr = client->addr;
-    msg[0].flags = I2C_M_RD; //Read
-    msg[0].len = rlength;
-    msg[0].buf = rdata;
-
-    ret = i2c_transfer(client->adapter, msg, 1);
-
-    return ret;
-}
-
-int sis_cul_unit(uint8_t report_id)
-{
-	int basic = 6;
-	int area = 2;
-	int pressure = 1;
-	int ret = basic;
-	
-	if (report_id != ALL_IN_ONE_PACKAGE)
-	{
-		if (IS_AREA(report_id) /*&& IS_TOUCH(report_id)*/)
-		{
-			ret += area;
-		}
-		if (IS_PRESSURE(report_id))
-		{
-			ret += pressure;
-		}
-	}
-	
-	return ret;	
-}
-
-int sis_ReadPacket(struct i2c_client *client, uint8_t cmd, uint8_t* buf)
-{
-	uint8_t tmpbuf[MAX_BYTE] = {0};	//MAX_BYTE = 64;
-#ifdef _CHECK_CRC
-	uint16_t buf_crc = 0;
-	uint16_t package_crc = 0;
-	int l_package_crc = 0;
-	int crc_end = 0;
-#endif
-    int ret = -1;
-    int touchnum = 0;
-    int p_count = 0;
-    int touc_formate_id = 0;
-    int locate = 0;
-    bool read_first = true;
-    
-/*
-		New i2c format 
-	* buf[0] = Low 8 bits of byte count value
-	* buf[1] = High 8 bits of byte counte value
-	* buf[2] = Report ID
-	* buf[touch num * 6 + 2 ] = Touch informations; 1 touch point has 6 bytes, it could be none if no touch 
-	* buf[touch num * 6 + 3] = Touch numbers
-	* 
-	* One touch point information include 6 bytes, the order is 
-	* 
-	* 1. status = touch down or touch up
-	* 2. id = finger id 
-	* 3. x axis low 8 bits
-	* 4. x axis high 8 bits
-	* 5. y axis low 8 bits
-	* 6. y axis high 8 bits
-	* 
-*/
-	do
-	{
-		if (locate >= PACKET_BUFFER_SIZE)
-		{
-			printk(KERN_ERR "sis_ReadPacket: Buf Overflow\n");
-			return -1;
-		}
-		
-		ret = sis_command_for_read(client, MAX_BYTE, tmpbuf);
-
-#ifdef _DEBUG_PACKAGE
-		printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
-		PrintBuffer(0, 64, tmpbuf);	
-#endif			
-
-		if(ret < 0 )
-		{
-			printk(KERN_ERR "sis_ReadPacket: i2c transfer error\n");
-			return ret;
-		}
-		// error package length of receiving data
-		else if (tmpbuf[P_BYTECOUNT] > MAX_BYTE)
-		{
-			printk(KERN_ERR "sis_ReadPacket: Error Bytecount\n");
-			return -1;	
-		}
-		
-		if (read_first)
-		{
-#ifdef _SUPPORT_BUTTON_TOUCH
-			// access BUTTON TOUCH event and BUTTON NO TOUCH event
-			if (tmpbuf[P_REPORT_ID] ==  BUTTON_FORMAT)
-			{
-				memcpy(&buf[0], &tmpbuf[0], 7);
-				return touchnum; 	//touchnum is 0
-			}
-#endif 
-			// access NO TOUCH event unless BUTTON NO TOUCH event
-			if (tmpbuf[P_BYTECOUNT] == 0/*NO_TOUCH_BYTECOUNT*/)
-			{
-				return touchnum;	//touchnum is 0
-			}
-		}
-
-		//skip parsing data when two devices are registered at the same slave address
-		//parsing data when P_REPORT_ID && 0xf is TOUCH_FORMAT or P_REPORT_ID is ALL_IN_ONE_PACKAGE
-		touc_formate_id = tmpbuf[P_REPORT_ID] & 0xf;
-		if ((touc_formate_id != TOUCH_FORMAT) && (touc_formate_id != HIDI2C_FORMAT) && (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE))
-		{
-			printk(KERN_ERR "sis_ReadPacket: Error Report_ID\n");
-			return -1;		
-		}
-		
-		p_count = (int) tmpbuf[P_BYTECOUNT] - 1;	//start from 0
-		if (tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE)
-		{
-			if (IS_TOUCH(tmpbuf[P_REPORT_ID]))
-			{
-				p_count -= BYTE_CRC_I2C;	//delete 2 byte crc
-			}
-			else if (IS_HIDI2C(tmpbuf[P_REPORT_ID]))
-			{
-				p_count -= BYTE_CRC_HIDI2C;
-			}
-			else	//should not be happen
-			{
-				printk(KERN_ERR "sis_ReadPacket: delete crc error\n");
-				return -1;
-			}
-
-			if (IS_SCANTIME(tmpbuf[P_REPORT_ID]))
-			{
-				p_count -= BYTE_SCANTIME;
-			}
-		}
-		//else {}    						// For ALL_IN_ONE_PACKAGE
-		
-		if (read_first)
-		{
-			touchnum = tmpbuf[p_count]; 	
-		}
-		else
-		{
-			if (tmpbuf[p_count] != 0)
-			{
-				printk(KERN_ERR "sis_ReadPacket: get error package\n");
-				return -1;
-			}
-		}
-
-#ifdef _CHECK_CRC
-		crc_end = p_count + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
-		buf_crc = cal_crc(tmpbuf, 2, crc_end); //sub bytecount (2 byte)
-		l_package_crc = p_count + 1 + (IS_SCANTIME(tmpbuf[P_REPORT_ID]) * 2);
-		package_crc = ((tmpbuf[l_package_crc] & 0xff) | ((tmpbuf[l_package_crc + 1] & 0xff) << 8));
-			
-		if (buf_crc != package_crc)
-		{
-			printk(KERN_ERR "sis_ReadPacket: CRC Error\n");
-			return -1;
-		}
-#endif	
-		memcpy(&buf[locate], &tmpbuf[0], 64);	//Buf_Data [0~63] [64~128]
-		locate += 64;
-		read_first = false;
-		
-	}while(tmpbuf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE  &&  tmpbuf[p_count] > 5);
-
-	return touchnum;
-}	
-
-
-int check_gpio_interrupt(void)
-{
-    int ret = 0;
-    //TODO
-    //CHECK GPIO INTERRUPT STATUS BY YOUR PLATFORM SETTING.
-    ret = gpio_get_value(GPIO_IRQ);
-    return ret;
-}
-
-void ts_report_key(struct i2c_client *client, uint8_t keybit_state)
-{
-	int i = 0;
-	uint8_t diff_keybit_state= 0x0; //check keybit_state is difference with pre_keybit_state
-	uint8_t key_value = 0x0; //button location for binary
-	uint8_t  key_pressed = 0x0; //button is up or down
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-
-	if (!ts)
-	{
-		printk(KERN_ERR "%s error: Missing Platform Data!\n", __func__);
-		return;
-	}
-
-	diff_keybit_state = TPInfo->pre_keybit_state ^ keybit_state;
-
-	if (diff_keybit_state)
-	{
-		for (i = 0; i < BUTTON_KEY_COUNT; i++)
-		{
-		    if ((diff_keybit_state >> i) & 0x01)
-			{
-				key_value = diff_keybit_state & (0x01 << i);
-				key_pressed = (keybit_state >> i) & 0x01;
-				switch (key_value)
-				{
-					case MSK_COMP:
-						input_report_key(ts->input_dev, KEY_COMPOSE, key_pressed);
-						printk(KERN_ERR "%s : MSK_COMP %d \n", __func__ , key_pressed);
-						break;
-					case MSK_BACK:
-						input_report_key(ts->input_dev, KEY_BACK, key_pressed);
-						printk(KERN_ERR "%s : MSK_BACK %d \n", __func__ , key_pressed);
-						break;
-					case MSK_MENU:
-						input_report_key(ts->input_dev, KEY_MENU, key_pressed);
-						printk(KERN_ERR "%s : MSK_MENU %d \n", __func__ , key_pressed);
-						break;
-					case MSK_HOME:
-						input_report_key(ts->input_dev, KEY_HOME, key_pressed);
-						printk(KERN_ERR "%s : MSK_HOME %d \n", __func__ , key_pressed);
-						break;
-					case MSK_NOBTN:
-						//Release the button if it touched.
-					default:
-						break;
-				}
-			}
-		}
-		TPInfo->pre_keybit_state = keybit_state;
-	}
-}
-
-
-static void sis_ts_work_func(struct work_struct *work)
-{
-	struct sis_ts_data *ts = container_of(work, struct sis_ts_data, work);
-    int ret = -1;
-    int point_unit;  
-	uint8_t buf[PACKET_BUFFER_SIZE] = {0};
-	uint8_t i = 0, fingers = 0;
-	uint8_t px = 0, py = 0, pstatus = 0;
-	uint8_t p_area = 0;
-    uint8_t p_preasure = 0;
-#ifdef _SUPPORT_BUTTON_TOUCH	
-	int button_key;
-	uint8_t button_buf[10] = {0};
-#endif
-
-#ifdef _ANDROID_4
-	bool all_touch_up = true;
-#endif
-	
-	mutex_lock(&ts->mutex_wq); 
-
-    /* I2C or SMBUS block data read */
-    ret = sis_ReadPacket(ts->client, SIS_CMD_NORMAL, buf);
-#ifdef _DEBUG_PACKAGE_WORKFUNC
-	printk(KERN_INFO "chaoban test: Buf_Data [0~63] \n");
-	PrintBuffer(0, 64, buf);			
-	if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (ret > 5))
-	{
-		printk(KERN_INFO "chaoban test: Buf_Data [64~125] \n");
-		PrintBuffer(64, 128, buf);	
-	}
-#endif
-
-// add 
-#ifdef _SUPPORT_BUTTON_TOUCH
-	 sis_ReadPacket(ts->client, SIS_CMD_NORMAL, button_buf);
-#endif
-
-	if (ret < 0) // Error Number
-	{
-	    printk(KERN_INFO "chaoban test: ret = -1\n");
-		goto err_free_allocate;
-	}
-#ifdef _SUPPORT_BUTTON_TOUCH
-	// access BUTTON TOUCH event and BUTTON NO TOUCH even
-	else if (button_buf[P_REPORT_ID] == BUTTON_FORMAT)
-	{
-		//fingers = 0; //modify
-		button_key = ((button_buf[BUTTON_STATE] & 0xff) | ((button_buf[BUTTON_STATE + 1] & 0xff)<< 8));		
-		ts_report_key(ts->client, button_key);
-		//goto err_free_allocate; //modify
-	}
-#endif
-	// access NO TOUCH event unless BUTTON NO TOUCH event
-	else if (ret == 0)
-	{
-		fingers = 0;
-		sis_tpinfo_clear(TPInfo, MAX_FINGERS);
-		goto label_send_report;  //need to report input_mt_sync()
-	}
-	
-	sis_tpinfo_clear(TPInfo, MAX_FINGERS);
-	
-	/* Parser and Get the sis9200 data */
-	point_unit = sis_cul_unit(buf[P_REPORT_ID]);
-	fingers = ret;
-	
-	TPInfo->fingers = fingers = (fingers > MAX_FINGERS ? 0 : fingers);
-	
-	for (i = 0; i < fingers; i++) // fingers 10 =  0 ~ 9
-	{
-        if ((buf[P_REPORT_ID] != ALL_IN_ONE_PACKAGE) && (i >= 5))
-        {
-			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + ((i - 5) * point_unit);    	// Calc point status
-			pstatus += 64;
-		}
-		else 
-		{
-			pstatus = BYTE_BYTECOUNT + BYTE_ReportID + (i * point_unit);          	// Calc point status
-		}
-
-	    px = pstatus + 2;                   			// Calc point x_coord
-	    py = px + 2;                        			// Calc point y_coord
-
-		if ((buf[pstatus]) == TOUCHUP)
-		{
-			TPInfo->pt[i].Width = 0;
-			TPInfo->pt[i].Height = 0;
-			TPInfo->pt[i].Pressure = 0;
-		}
-		else if (buf[P_REPORT_ID] == ALL_IN_ONE_PACKAGE && (buf[pstatus]) == TOUCHDOWN)
-		{
-			TPInfo->pt[i].Width = 1;
-			TPInfo->pt[i].Height = 1;
-			TPInfo->pt[i].Pressure = 1;			
-		}
-		else if ((buf[pstatus]) == TOUCHDOWN)
-		{	
-			p_area = py + 2;
-			p_preasure = py + 2 + (IS_AREA(buf[P_REPORT_ID]) * 2);
-
-			//area		
-			if (IS_AREA(buf[P_REPORT_ID]))
-			{
-				TPInfo->pt[i].Width = buf[p_area] & 0xff;
-				TPInfo->pt[i].Height = buf[p_area + 1] & 0xff;
-			}
-			else 
-			{
-				TPInfo->pt[i].Width = 1;
-				TPInfo->pt[i].Height = 1;
-			}
-			//preasure
-			if (IS_PRESSURE(buf[P_REPORT_ID]))
-				TPInfo->pt[i].Pressure = (buf[p_preasure]);
-			else 
-				TPInfo->pt[i].Pressure = 1;				
-		}
-		else
-		{
-			printk(KERN_ERR "sis_ts_work_func: Error Touch Status\n");
-			goto err_free_allocate;
-		}
-		
-		TPInfo->pt[i].id = (buf[pstatus + 1]);
-		TPInfo->pt[i].x = ((buf[px] & 0xff) | ((buf[px + 1] & 0xff)<< 8));
-        TPInfo->pt[i].y = ((buf[py] & 0xff) | ((buf[py + 1] & 0xff)<< 8));      
-	}
-		
-#ifdef _DEBUG_REPORT
-	for (i = 0; i < TPInfo->fingers; i++)
-	{
-		 printk(KERN_INFO "chaoban test: i = %d, id = %d, x = %d, y = %d, pstatus = %d, width = %d, height = %d, pressure = %d, \n", i, TPInfo->pt[i].id, TPInfo->pt[i].x, TPInfo->pt[i].y, buf[pstatus], TPInfo->pt[i].Width,  TPInfo->pt[i].Height, TPInfo->pt[i].Pressure);
-	}
-#endif
-
-label_send_report:
-/* Report co-ordinates to the multi-touch stack */
-#ifdef _ANDROID_4	
-	for(i = 0; ((i < TPInfo->fingers) && (i < MAX_FINGERS)); i++)
-	{
-		if(TPInfo->pt[i].Pressure)
-		{
-			TPInfo->pt[i].Width *= AREA_UNIT;	
-			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Width);
-			TPInfo->pt[i].Height *= AREA_UNIT;
-			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, TPInfo->pt[i].Height);			
-			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, TPInfo->pt[i].Pressure);
-			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
-			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
-			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);     //Android 2.3
-			input_mt_sync(ts->input_dev);
-			all_touch_up = false;
-		}
-		
-		if (i == (TPInfo->fingers -1) && all_touch_up == true)
-		{
-			input_mt_sync(ts->input_dev);
-		}
-	}
-
-	if(TPInfo->fingers == 0)
-	{
-		input_mt_sync(ts->input_dev);
-	}
-#else
-	i = 0;
-	do
-	{
-		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, TPInfo->pt[i].Pressure);
-		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, TPInfo->pt[i].Width);
-		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MINOR, TPInfo->pt[i].Height);
-		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, TPInfo->pt[i].x);
-		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, TPInfo->pt[i].y);
-		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, TPInfo->pt[i].id);		//Android 2.3
-		input_mt_sync(ts->input_dev);
-		i++;
-	}
-	while ((i < TPInfo->fingers) && (i < MAX_FINGERS));
-#endif
-	input_sync(ts->input_dev);
-
-err_free_allocate:
-
-    if (ts->use_irq)
-    {
-#ifdef _INT_MODE_1 //case 1 mode
-	    //TODO: After interrupt status low, read i2c bus data by polling, until interrupt status is high
-	    ret = check_gpio_interrupt();	//interrupt pin is still LOW, read data until interrupt pin is released.
-	    if (!ret)
-	    {
-	        hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
-	    }
-	    else
-	    {
-			if (TPInfo->pre_keybit_state)
-			{
-				ts_report_key(ts->client, 0x0);	//clear for interrupt
-			}
-			
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-        	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-        	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-        	{
-				enable_irq(ts->client->irq);
-			}
-	    }
-#else // case 2 mode
-
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-		{
-			enable_irq(ts->client->irq);
-		}
-#endif
-	}
-
-	mutex_unlock(&ts->mutex_wq);
-    return;
-}
-
-static void sis_tpinfo_clear(struct sisTP_driver_data *TPInfo, int max)
-{
-	int i = 0;
-	for(i = 0; i < max; i++)
-	{
-		TPInfo->pt[i].id = -1;
-		TPInfo->pt[i].x = 0;
-		TPInfo->pt[i].y = 0;
-		TPInfo->pt[i].Pressure = 0;
-		TPInfo->pt[i].Width = 0;
-	}
-	TPInfo->id = 0x0;
-	TPInfo->fingers = 0;
-}
-
-static enum hrtimer_restart sis_ts_timer_func(struct hrtimer *timer)
-{
-	struct sis_ts_data *ts = container_of(timer, struct sis_ts_data, timer);
-	queue_work(sis_wq, &ts->work);
-	if (!ts->use_irq)
-	{	// For Polling mode
-	    hrtimer_start(&ts->timer, ktime_set(0, TIMER_NS), HRTIMER_MODE_REL);
-	}
-	return HRTIMER_NORESTART;
-}
-
-static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
-{
-	struct sis_ts_data *ts = dev_id;
-	
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-	if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#else
-	if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#endif
-	{
-		disable_irq_nosync(ts->client->irq);
-	}
-	queue_work(sis_wq, &ts->work);
-		
-	return IRQ_HANDLED;
-}
-
-static int initial_irq(void)
-{
-	int ret = 0;
-#ifdef _I2C_INT_ENABLE
-	/* initialize gpio and interrupt pins */
-	/* TODO */
-	ret = gpio_request(GPIO_IRQ, "GPIO_133");	// ex. GPIO_133 for interrupt mode
-	if (ret < 0)
-	{
-		// Set Active Low. Please reference the file include/linux/interrupt.h
-		printk(KERN_ERR "sis_ts_probe: Failed to gpio_request\n");
-		printk(KERN_ERR "sis_ts_probe: Fail : gpio_request was called before this driver call\n");
-	}	
-	/* setting gpio direction here OR boardinfo file*/
-	/* TODO */
-#else
-	ret = -1;
-#endif
-	return ret;
-}
-
-uint16_t cal_crc (char* cmd, int start, int end)
-{
-	int i = 0;
-	uint16_t crc = 0;
-	for (i = start; i <= end ; i++)
-	{
-		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd[i] )&0x00FF];
-	}
-	return crc;
-}
-
-uint16_t cal_crc_with_cmd (char* data, int start, int end, uint8_t cmd)
-{
-	int i = 0;
-	uint16_t crc = 0;
-	
-	crc = (crc<<8) ^ crc16tab[((crc>>8) ^ cmd)&0x00FF];
-	for (i = start; i <= end ; i++)
-	{
-		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ data[i] )&0x00FF];
-	}
-	return crc;
-}
-
-void write_crc (unsigned char *buf, int start, int end)
-{
-	uint16_t crc = 0;
-	crc = cal_crc (buf, start , end);
-	buf[end+1] = (crc >> 8)& 0xff;
-	buf[end+2] = crc & 0xff;
-}
-
-/*
- * When you will send commad to chip, you should use this function on 
- * the first time.
- * 
- * Return:If switch success return ture, else return false.
- */
-bool sis_switch_to_cmd_mode(struct i2c_client *client)
-{
-	int ret = -1;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
-		0x00, 0x85, 0x0d, 0x51, 0x09};
-	uint8_t sis817_cmd_enable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
-		0x00, 0x09, 0x00, 0x85, 0x5c, 0x21, 0x01};
-	
-	
-	
-	//Send 85 CMD - PWR_CMD_ACTIVE
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_ACTIVE)\n");
-		return false;
-	}
-	
-	msleep(100);
-	memset(tmpbuf, 0, sizeof(tmpbuf));
-	
-	//Send 85 CMD - ENABLE_DIAGNOSIS_MODE
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_enable_diagnosis), sis817_cmd_enable_diagnosis);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(ENABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	msleep(50);
-	return true;	
-}
-
-/*
- * When chip in the command mode will switch to work, you should use 
- * this function.
- * 
- * Return:If switch success return ture, else return false.
- */
-bool sis_switch_to_work_mode(struct i2c_client *client)
-{
-	int ret = -1;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 
-		0x00, 0x85, 0x3c, 0x50, 0x09};
-	uint8_t sis817_cmd_disable_diagnosis[10] 	= {0x04, 0x00, 0x08, 
-		0x00, 0x09, 0x00, 0x85, 0x6d, 0x20, 0x01};
-	
-	
-	//Send 85 CMD - PWR_CMD_FW_CTRL
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(PWR_CMD_FW_CTRL)\n");
-		return false;
-	}
-
-	memset(tmpbuf, 0, sizeof(tmpbuf));
-	
-	//Send 85 CMD - DISABLE_DIAGNOSIS_MODE
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_disable_diagnosis), sis817_cmd_disable_diagnosis);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Switch CMD Faile - 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Switch CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
-		return false;
-	}
-	
-	msleep(50);
-	return true;
-}
-
-/*
- * Use this function get FW ID.
- */
-bool sis_get_fw_id(struct i2c_client *client)
-{
-  	int ret = 0;
-  	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_get_FW_ID[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
-		0x00, 0x86, 0x00, 0x0c, 0xc0, 0x00, 0xa0, 0x04, 0x00};
-	
-	sis817_cmd_get_FW_ID[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_get_FW_ID, 8, 13, 0x86));
-
-	if(!sis_switch_to_cmd_mode(client)){
-		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
-		return false;
-	}
-	
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_get_FW_ID), sis817_cmd_get_FW_ID);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
-	}
-
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	printk(KERN_INFO "SiS FW ID : ");
-	PrintBuffer(8, 12, tmpbuf);	
-
-	if(!sis_switch_to_work_mode(client)){
-		printk(KERN_ERR "SiS Switch to Work mode error.\n");
-		return false;
-	}
-	
-	if(ret < 0) return false;
-	return true;
-		
-}
-
-/*
- * Use this function check chip status.
- * 
- * Return:Ture is chip on the work function, else is chip not ready.
- */
-bool sis_check_fw_ready(struct i2c_client *client)
-{
-  	int ret = 0;
-  	int check_num = 10;
-  	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_check_ready[14] = {0x04, 0x00, 0x0c, 0x00, 0x09, 
-		0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
-	
-	
-	sis817_cmd_check_ready[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_ready, 8, 13, 0x86));
-	
-
-	if(!sis_switch_to_cmd_mode(client)){
-		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
-		return false;
-	}
-	
-	while(check_num--){
-		printk(KERN_ERR "SiS Check FW Ready.\n");
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_check_ready), sis817_cmd_check_ready);
-		if(ret < 0){
-			printk(KERN_ERR "SiS SEND Check FW Ready CMD Faile - 86\n");
-		}
-		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-		if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return NACK\n");
-		}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-			printk(KERN_ERR "SiS SEND Check FW Ready CMD Return Unknow\n");
-		}else{
-			if(tmpbuf[9] == 1){
-				printk(KERN_ERR "SiS FW READY.\n");
-				break;
-			}
-		}
-		printk(KERN_ERR "SiS CHECK FW READY - Retry:%d.\n", (10-check_num));	
-		msleep(50);
-	}
-	
-	if(!sis_switch_to_work_mode(client)){
-		printk(KERN_ERR "SiS Switch to Work mode error.\n");
-		return false;
-	}
-	
-	if(check_num == 0) return false;
-	return true;
-		
-}
-
-/*
- * Use this function to change chip power mode. 
- * 
- * mode:POWER_MODE_FWCTRL, power control by FW.
- * 		POWER_MODE_ACTIVE, chip always work on time.
- * 		POWER_MODE_SLEEP,  chip on the sleep mode.
- * 
- * Return:Ture is change power mode success.
- */
-bool sis_change_fw_mode(struct i2c_client *client, enum SIS_817_POWER_MODE mode)
-{
-	int ret = -1;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_fwctrl[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x3c, 0x50, 0x09};
-	uint8_t sis817_cmd_active[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x0d, 0x51, 0x09};
-	uint8_t sis817_cmd_sleep[10] 	= {0x04, 0x00, 0x08, 0x00, 0x09, 0x00, 0x85, 0x5e, 0x52, 0x09};
-	
-	
-	switch(mode)
-	{
-	case POWER_MODE_FWCTRL:
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_fwctrl), sis817_cmd_fwctrl);
-		break;
-	case POWER_MODE_ACTIVE:
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_active), sis817_cmd_active);
-		break;
-	case POWER_MODE_SLEEP:
-		ret = sis_command_for_write(client, sizeof(sis817_cmd_sleep), sis817_cmd_sleep);
-		break;
-	default:
-		return false;
-		break;
-	}
-
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Power CMD Faile - 85\n");
-		return false;
-	}
-	
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if(ret < 0){
-		printk(KERN_ERR "SiS READ Power CMD Faile - 85\n");
-		return false;
-	}
-	
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Power CMD Return NACK - 85\n");
-		return false;
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Power CMD Return Unknow- 85\n");
-		return false;
-	}
-	
-	msleep(100);
-	
-	return true;
-}
-
-/*
- * Use this function to get chip work status. 
- * 
- * Return:-1 is get firmware work status error.
- * 		  POWER_MODE_FWCTRL, power control by FW.
- * 		  POWER_MODE_ACTIVE, chip always work on time.
- * 		  POWER_MODE_SLEEP,  chip on the sleep mode.
- */
-enum SIS_817_POWER_MODE sis_get_fw_mode(struct i2c_client *client)
-{
-	int ret;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_check_power_mode[14] = {0x04, 0x00, 0x0c, 0x00, 
-		0x09, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x50, 0x34, 0x00};
-
-	printk(KERN_INFO "SiS Get FW Mode.\n");	
-	sis817_cmd_check_power_mode[BUF_CRC_PLACE] = (0xFF & cal_crc_with_cmd(sis817_cmd_check_power_mode, 8, 13, 0x86));
-	
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_check_power_mode), sis817_cmd_check_power_mode);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Get FW Mode CMD Faile - 86\n");
-	}else{
-		ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-		if(ret < 0){
-			printk(KERN_ERR "SiS READ Get FW Mode CMD Faile - 86\n");
-		}else{
-			if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return NACK\n");
-			}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-				printk(KERN_ERR "SiS SEND Get FW Mode CMD Return Unknow\n");
-				PrintBuffer(0, sizeof(tmpbuf), tmpbuf);
-			}
-		}
-	}
-	
-	switch(tmpbuf[10])
-	{
-	case POWER_MODE_FWCTRL:
-		return POWER_MODE_FWCTRL;
-	case POWER_MODE_ACTIVE:
-		return POWER_MODE_ACTIVE;
-	case POWER_MODE_SLEEP:
-		return POWER_MODE_SLEEP;
-	default:
-		break;
-	}
-
-	return -1;
-}
-
-/*
- * Use this function to reset chip. 
- */
-void sis_fw_softreset(struct i2c_client *client)
-{
-
-	int ret = 0;
-	uint8_t tmpbuf[MAX_BYTE] = {0};
-	uint8_t sis817_cmd_reset[8] = {0x04, 0x00, 0x06, 0x00, 0x09, 0x00, 0x82, 0x00};
-	
-
-	sis817_cmd_reset[BUF_CRC_PLACE] = (0xFF & cal_crc(sis817_cmd_reset, 6, 6));
-
-	printk(KERN_ERR "SiS Software Reset.\n");
-	if(!sis_switch_to_cmd_mode(client)){
-		printk(KERN_ERR "SiS Switch to CMD mode error.\n");
-		return;
-	}
-	
-	ret = sis_command_for_write(client, sizeof(sis817_cmd_reset), sis817_cmd_reset);
-	if(ret < 0){
-		printk(KERN_ERR "SiS SEND Reset CMD Faile - 82\n");
-	}
-	ret = sis_command_for_read(client, sizeof(tmpbuf), tmpbuf);
-	if((tmpbuf[BUF_ACK_PLACE_L] == BUF_NACK_L) && (tmpbuf[BUF_ACK_PLACE_H] == BUF_NACK_H)){
-		printk(KERN_ERR "SiS SEND Reset CMD Return NACK - 85(DISABLE_DIAGNOSIS_MODE)\n");
-	}else if((tmpbuf[BUF_ACK_PLACE_L] != BUF_ACK_L) || (tmpbuf[BUF_ACK_PLACE_H] != BUF_ACK_H)){
-		printk(KERN_ERR "SiS SEND Reset CMD Return Unknow- 85(DISABLE_DIAGNOSIS_MODE)\n");
-	}	
-	msleep(2000);
-}
-
-
-#ifdef _STD_RW_IO
-#define BUFFER_SIZE MAX_BYTE
-static ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
-{
-	 int ret = 0;
-	 char *kdata;
-	 char cmd;
-	 
-	 printk(KERN_INFO "sis_cdev_write.\n");
-	 
-	 if (ts_bak == 0)
-    	return -13;
-    	
-    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
-    if (!ret) {
-        printk(KERN_ERR "cannot access user space memory\n");
-        return -11;
-    }
-
-	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-     if (kdata == 0)
-    	return -12;
-    	
-     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
-     if (ret) {
-        printk(KERN_ERR "copy_from_user fail\n");
-        kfree(kdata);
-        return -14;
-     } 
-#if 0
-	PrintBuffer(0, count, kdata);
-#endif
-		
-	cmd = kdata[6];
-
-    printk(KERN_INFO "io cmd=%02x\n", cmd);
-
-//Write & Read
-    ret = sis_command_for_write(ts_bak->client, count, kdata);
-    if (ret < 0) {
-        printk(KERN_ERR "i2c_transfer write error %d\n", ret);
-		kfree(kdata);
-		return -21;
-	}
-
-    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
-    {
-        printk(KERN_ERR "copy_to_user fail\n" );
-        ret = -19;
-    }
-
-    kfree( kdata );
-
-	return ret;
-}
-
-//for get system time
-static ssize_t sis_cdev_read( struct file *file, char __user *buf, size_t count, loff_t *f_pos )
-{
-	 int ret = 0;
-	 char *kdata;
-	 char cmd;
-	 int i;
-	 printk(KERN_INFO "sis_cdev_read.\n");
-	 
-	 if (ts_bak == 0)
-    	return -13;
-    	
-    ret = access_ok(VERIFY_WRITE, buf, BUFFER_SIZE);
-    if (!ret) {
-        printk(KERN_ERR "cannot access user space memory\n");
-        return -11;
-    }
-
-	 kdata = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-     if (kdata == 0)
-    	return -12;
-    	
-     ret = copy_from_user(kdata, buf, BUFFER_SIZE);
-     if (ret) {
-        printk(KERN_ERR "copy_from_user fail\n");
-        kfree(kdata);
-        return -14;
-     }    
-#if 0
-    PrintBuffer(0, count, kdata);
-#endif
-	 cmd = kdata[6];
-	 //for making sure AP communicates with SiS driver
-    if(cmd == 0xa2)
-    {
-		kdata[0] = 5;
-		kdata[1] = 0;
-		kdata[3] = 'S';
-		kdata[4] = 'i';
-		kdata[5] = 'S';
-		if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
-		{
-			printk(KERN_ERR "copy_to_user fail\n" );
-			kfree( kdata );
-			return -19;
-		}
-
-		kfree( kdata );
-		return 3;	
-	}
-//Write & Read
-    ret = sis_command_for_read(ts_bak->client, MAX_BYTE, kdata);
-    if (ret < 0) {
-        printk(KERN_ERR "i2c_transfer read error %d\n", ret);
-		kfree(kdata);
-		return -21;
-	}
-
-	ret = kdata[0] | (kdata[1] << 8);
-
-/*
-    for ( i = 0; i < BUFFER_SIZE - 1; i++ ) {
-	    kdata[i] = kdata[i+1];
-    }
-*/
-
-    printk(KERN_INFO "%d\n", ret);
-
-    for ( i = 0; i < ret && i < BUFFER_SIZE; i++ )
-    {
-        printk("%02x ", kdata[i]);
-    }
-
-    printk( "\n" );
-
-    if ( copy_to_user((char*) buf, kdata, BUFFER_SIZE ) )
-    {
-        printk(KERN_ERR "copy_to_user fail\n" );
-        ret = -19;
-    }
-
-    kfree( kdata );
-
-	return ret;
-}
-
-#undef BUFFER_SIZE
-
-static int sis_cdev_open(struct inode *inode, struct file *filp)
-{
-	printk(KERN_INFO "sis_cdev_open.\n");
-	if ( ts_bak == 0 )
-    	return -13;
-
-	msleep(200);
-	if (ts_bak->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#else
-		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#endif	
-		{
-			disable_irq(ts_bak->client->irq);
-		}
-		else
-		{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->status & IRQ_DISABLED));
-#else
-			printk(KERN_INFO "sis_cdev_open: IRQ_STATUS: %x\n",(ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED));
-#endif	
-		}
-	}
-	hrtimer_cancel(&ts_bak->timer);
-
-	flush_workqueue(sis_wq); 	   // only flush sis_wq
-    
-    msleep(200);
-
-	return 0; /* success */
-}
-
-static int sis_cdev_release(struct inode *inode, struct file *filp)
-{
-	printk(KERN_INFO "sis_cdev_release.\n");
-	 msleep(200);
-    if (ts_bak == 0)
-    	return -13;
-
-	if (ts_bak->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-        if ((ts_bak->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts_bak->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif	
-		{
-			enable_irq(ts_bak->client->irq);
-		}
-	}
-	else
-		hrtimer_start(&ts_bak->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-
-    return 0;
-}
-
-static const struct file_operations sis_cdev_fops = {
-	.owner	= THIS_MODULE,
-	.read	= sis_cdev_read,
-	.write	= sis_cdev_write,
-	.open	= sis_cdev_open,
-	.release= sis_cdev_release,
-};
-
-static int sis_setup_chardev(struct sis_ts_data *ts)
-{
-	
-	dev_t dev = MKDEV(sis_char_major, 0);
-	int alloc_ret = 0;
-	int cdev_err = 0;
-	int input_err = 0;
-	struct device *class_dev = NULL;
-	void *ptr_err;
-	
-	printk("sis_setup_chardev.\n");
-	
-	if (ts == NULL) 
-	{
-	  input_err = -ENOMEM;
-	  goto error;
-	} 
-	 // dynamic allocate driver handle
-	alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, DEVICE_NAME);
-	if (alloc_ret)
-		goto error;
-		
-	sis_char_major = MAJOR(dev);
-	cdev_init(&sis_char_cdev, &sis_cdev_fops);
-	sis_char_cdev.owner = THIS_MODULE;
-	cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
-	
-	if (cdev_err) 
-		goto error;
-	
-	printk(KERN_INFO "%s driver(major %d) installed.\n", DEVICE_NAME, sis_char_major);
-	
-	// register class
-	sis_char_class = class_create(THIS_MODULE, DEVICE_NAME);
-	if(IS_ERR(ptr_err = sis_char_class)) 
-	{
-		goto err2;
-	}
-	
-	class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, DEVICE_NAME);
-	
-	if(IS_ERR(ptr_err = class_dev)) 
-	{
-		goto err;
-	}
-	
-	return 0;
-error:
-	if (cdev_err == 0)
-		cdev_del(&sis_char_cdev);
-	if (alloc_ret == 0)
-		unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
-	if(input_err != 0)
-	{
-		printk("sis_ts_bak error!\n");
-	}
-err:
-	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
-err2:
-	class_destroy(sis_char_class);
-	return -1;
-}
-#endif
-
-static int sis_ts_probe(
-	struct i2c_client *client, const struct i2c_device_id *id)
-{
-	int ret = 0;
-	struct sis_ts_data *ts = NULL;
-	struct sis_i2c_rmi_platform_data *pdata = NULL;
-
-    printk(KERN_INFO "sis_ts_probe\n");
-
-    TPInfo = kzalloc(sizeof(struct sisTP_driver_data), GFP_KERNEL);
-    if (TPInfo == NULL) 
-    {
-		ret = -ENOMEM;
-		goto err_alloc_data_failed;
-	}
-
-	ts = kzalloc(sizeof(struct sis_ts_data), GFP_KERNEL);
-	if (ts == NULL) 
-	{
-		ret = -ENOMEM;
-		goto err_alloc_data_failed;
-	}
-
-	ts_bak = ts;
-
-	mutex_init(&ts->mutex_wq);
-	
-	//1. Init Work queue and necessary buffers
-	INIT_WORK(&ts->work, sis_ts_work_func);
-	ts->client = client;
-	i2c_set_clientdata(client, ts);
-    pdata = client->dev.platform_data;
-
-	if (pdata)
-		ts->power = pdata->power;
-	if (ts->power) 
-	{
-		ret = ts->power(1);
-		if (ret < 0) 
-		{
-			printk(KERN_ERR "sis_ts_probe power on failed\n");
-			goto err_power_failed;
-		}
-	}
-
-	//2. Allocate input device
-	ts->input_dev = input_allocate_device();
-	if (ts->input_dev == NULL) 
-	{
-		ret = -ENOMEM;
-		printk(KERN_ERR "sis_ts_probe: Failed to allocate input device\n");
-		goto err_input_dev_alloc_failed;
-	}
-
-	//This input device name should be the same to IDC file name.
-	ts->input_dev->name = "sis_touch";//"SiS9200-i2c-touchscreen";
-
-	sis_get_fw_id(client);
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-		//sis_check_fw_ready(client);
-#endif
-
-	set_bit(EV_ABS, ts->input_dev->evbit);
-	set_bit(EV_KEY, ts->input_dev->evbit);
-    set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
-    set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
-    set_bit(ABS_MT_TRACKING_ID, ts->input_dev->absbit);
-
-#ifdef _ANDROID_4
-	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
-    set_bit(ABS_MT_PRESSURE, ts->input_dev->absbit);
-    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
-    set_bit(ABS_MT_TOUCH_MINOR, ts->input_dev->absbit);
-    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, PRESSURE_MAX, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);   
-#else
-    set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
-    set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
-    set_bit(ABS_MT_WIDTH_MINOR, ts->input_dev->absbit);
-    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESSURE_MAX, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, AREA_LENGTH_LONGER, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MINOR, 0, AREA_LENGTH_SHORT, 0, 0);
-#endif
-
-    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
-	
-    /* add for touch keys */
-	set_bit(KEY_COMPOSE, ts->input_dev->keybit);
-	set_bit(KEY_BACK, ts->input_dev->keybit);
-	set_bit(KEY_MENU, ts->input_dev->keybit);
-	set_bit(KEY_HOME, ts->input_dev->keybit);
-
-	//3. Register input device to core
-	ret = input_register_device(ts->input_dev);
-
-	if (ret) 
-	{
-		printk(KERN_ERR "sis_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
-		goto err_input_register_device_failed;
-	}
-	
-	//4. irq or timer setup
-	ret = initial_irq();
-	if (ret < 0) 
-	{
-
-	}
-	else
-	{
-		client->irq = gpio_to_irq(GPIO_IRQ);
-		ret = request_irq(client->irq, sis_ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
-		if (ret == 0) 
-		{
-		   ts->use_irq = 1;
-		}
-		else 
-		{
-			dev_err(&client->dev, "request_irq failed\n");
-		}
-	}
-
-	ts->desc = irq_to_desc(ts_bak->client->irq);
-	
-	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	ts->timer.function = sis_ts_timer_func;
-
-	if (!ts->use_irq) 
-	{
-		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-	}
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
-	ts->early_suspend.suspend = sis_ts_early_suspend;
-	ts->early_suspend.resume = sis_ts_late_resume;
-	register_early_suspend(&ts->early_suspend);
-#endif
-	printk(KERN_INFO "sis_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
-	
-	if (ts->use_irq)
-	{
-#ifdef _INT_MODE_1
-		printk(KERN_INFO "sis_ts_probe: interrupt case 1 mode\n");
-#else
-		printk(KERN_INFO "sis_ts_probe: interrupt case 2 mode\n");
-#endif
-	}
-	
-#ifdef _STD_RW_IO
-	ret = sis_setup_chardev(ts);
-	if(ret)
-	{
-		printk( KERN_INFO"sis_setup_chardev fail\n");
-	}
-#endif
-
-	printk( KERN_INFO"sis SIS_SLAVE_ADDR: %d\n", SIS_SLAVE_ADDR);
-
-	return 0;
-
-err_input_register_device_failed:
-	input_free_device(ts->input_dev);
-
-err_input_dev_alloc_failed:
-err_power_failed:
-	kfree(ts);
-err_alloc_data_failed:
-	return ret;
-}
-
-static int sis_ts_remove(struct i2c_client *client)
-{
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	unregister_early_suspend(&ts->early_suspend);
-#endif
-	if (ts->use_irq)
-		free_irq(client->irq, ts);
-	else
-		hrtimer_cancel(&ts->timer);
-	input_unregister_device(ts->input_dev);
-	kfree(ts);
-	return 0;
-}
-
-static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg)
-{
-	int ret = 0;
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-	int retry = 5;
-#endif
-
-	TPInfo->pre_keybit_state = 0x0;
-
-	if (ts->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_ENABLED)
-#endif
-		{
-			disable_irq(client->irq);
-		}
-	}
-	else
-		hrtimer_cancel(&ts->timer);
-	flush_workqueue(sis_wq); 	   		// only flush sis_wq
-//	flush_scheduled_work(); 		   	// flush all of workqueue in kernel
-//	ret = cancel_work_sync(&ts->work); 	// only cancel one work(sis_ts_work_func), 
-										// but there maybe are others in workqueue.
-/*
-	// For cancel_work_sync()
-	if (ret && ts->use_irq) //if work was pending disable-count is now 2
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-		{
-			enable_irq(client->irq);
-		}
-	}
-*/
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-		while ((sis_get_fw_mode(client) != POWER_MODE_SLEEP))
-		{
-			
-			if(sis_change_fw_mode(client, POWER_MODE_SLEEP)){
-				printk(KERN_ERR "sis_ts_suspend: change mode retry - %d\n", 5-retry);
-			}
-
-			if (retry == 0){
-				printk(KERN_ERR "sis_ts_suspend: change mode failed\n");
-				break;
-			}
-
-			retry--;
-			msleep(50);
-		}
-#endif
-
-
-#if 0
-	/* Turn off SiS Chip*/
-	/* TODO */
-	gpio_direction_output(TOUCH_RESET_PIN, 0);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
-//	msleep(5);
-	gpio_direction_output(TOUCH_POWER_PIN, 0);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power off\n");
-#endif
-
-	if (ts->power) {
-		ret = ts->power(0);
-		if (ret < 0)
-			printk(KERN_ERR "sis_ts_suspend power off failed\n");
-	}
-	
-	return 0;
-}
-
-static int sis_ts_resume(struct i2c_client *client)
-{
-	int ret = 0;
-	struct sis_ts_data *ts = i2c_get_clientdata(client);
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-	int retry = 5;
-#endif
-
-	if (ts->power)
-	{
-		ret = ts->power(1);
-		if (ret < 0)
-			printk(KERN_ERR "sis_ts_resume power on failed\n");
-	}
-
-#if 0
-	/* Turn on SiS Chip*/
-	/* TODO */
-	gpio_direction_output(TOUCH_POWER_PIN, 1);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Power on\n");
-	msleep(5);
-	gpio_direction_output(TOUCH_RESET_PIN, 1);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
-	msleep(5);
-	gpio_direction_output(TOUCH_RESET_PIN, 0);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset Low\n");
-	msleep(5);
-	gpio_direction_output(TOUCH_RESET_PIN, 1);
-	printk(KERN_INFO "[MSI TOUCH] SiS Touch Reset HI\n");
-#endif
-
-#ifdef CONFIG_FW_SUPPORT_POWERMODE
-		while ((sis_get_fw_mode(client) != POWER_MODE_FWCTRL))
-		{
-			
-			if(sis_change_fw_mode(client, POWER_MODE_FWCTRL)){
-				printk(KERN_ERR "sis_ts_resume: change mode retry - %d\n", 5-retry);
-			}
-
-			if (retry == 0){
-				printk(KERN_ERR "sis_ts_resume: change mode failed\n");
-				break;
-			}
-				
-			retry--;
-			msleep(50);
-		}
-#endif
-		//sis_fw_softreset(client);
-
-	if (ts->use_irq)
-	{
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-		if ((ts->desc->status & IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#else
-		if ((ts->desc->irq_data.state_use_accessors & IRQD_IRQ_DISABLED) == IRQ_STATUS_DISABLED)
-#endif
-		{
-			enable_irq(client->irq);
-		}
-	}
-	else
-		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-
-	return 0;
-}
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void sis_ts_early_suspend(struct early_suspend *h)
-{
-	struct sis_ts_data *ts;
-	TPInfo->pre_keybit_state = 0x0;
-	ts = container_of(h, struct sis_ts_data, early_suspend);
-	sis_ts_suspend(ts->client, PMSG_SUSPEND);
-}
-
-static void sis_ts_late_resume(struct early_suspend *h)
-{
-	struct sis_ts_data *ts;
-	ts = container_of(h, struct sis_ts_data, early_suspend);
-	sis_ts_resume(ts->client);
-}
-#endif
-
-static const struct i2c_device_id sis_ts_id[] = {
-	{ SIS_I2C_NAME, 0 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(i2c, sis_ts_id);
-
-static struct i2c_driver sis_ts_driver = {
-	.probe		= sis_ts_probe,
-	.remove		= sis_ts_remove,
-#ifndef CONFIG_HAS_EARLYSUSPEND
-	.suspend	= sis_ts_suspend,
-	.resume		= sis_ts_resume,
-#endif
-#ifdef CONFIG_X86
-    .class      = I2C_CLASS_HWMON,
-    .detect		= sis_ts_detect,
-	.address_list	= normal_i2c,
-#endif
-	.id_table	= sis_ts_id,
-	.driver = {
-		.name	= SIS_I2C_NAME,
-	},
-};
-
-static int __devinit sis_ts_init(void)
-{
-	printk( KERN_INFO "sis_ts_init\n" );
-	sis_wq = create_singlethread_workqueue("sis_wq");
-
-	if (!sis_wq)
-		return -ENOMEM;
-	return i2c_add_driver(&sis_ts_driver);
-}
-
-#ifdef CONFIG_X86
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int sis_ts_detect(struct i2c_client *client,
-		       struct i2c_board_info *info)
-{
-	const char *type_name;
-    printk(KERN_INFO "sis_ts_detect\n");
-	type_name = "sis_i2c_ts";
-	strlcpy(info->type, type_name, I2C_NAME_SIZE);
-	return 0;
-}
-#endif
-
-static void __exit sis_ts_exit(void)
-{
-#ifdef _STD_RW_IO
-	dev_t dev;
-#endif
-
-	printk(KERN_INFO "sis_ts_exit\n");
-	i2c_del_driver(&sis_ts_driver);
-	if (sis_wq)
-		destroy_workqueue(sis_wq);
-
-#ifdef _STD_RW_IO
-	dev = MKDEV(sis_char_major, 0);
-	cdev_del(&sis_char_cdev);
-	unregister_chrdev_region(dev, sis_char_devs_count);
-	device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
-	class_destroy(sis_char_class);
-#endif
-}
-
-module_init(sis_ts_init);
-module_exit(sis_ts_exit);
-MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
-MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h b/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
deleted file mode 100644
index 1ace42a..0000000
--- a/linux-3.18.1/drivers/input/touchscreen/sis_i2c.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * include/linux/sis_i2c.h - platform data structure for SiS 9200 family
- *
- * Copyright (C) 2011 SiS, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * Date: 2012/11/13
- * Version:	Android_v2.05.00-A639-1113
- */
-#include <linux/version.h>
-
-#ifndef _LINUX_SIS_I2C_H
-#define _LINUX_SIS_I2C_H
-
-
-#define SIS_I2C_NAME "sis_i2c_ts"
-#define SIS_SLAVE_ADDR					0x5c
-#define TIMER_NS    					10000000 //10ms
-#define MAX_FINGERS						10
-
-
-/* For Android 4.0 							*/
-/* Only for Linux kernel 2.6.34 and later 	*/
-#define _ANDROID_4					//  ON/OFF
-
-/* For standard R/W IO*/
-#define _STD_RW_IO						//  ON/OFF
-
-/* Interrupt setting and modes */
-#define _I2C_INT_ENABLE					//  ON/OFF
-#define GPIO_IRQ 						133
-
-/*  Enable if use interrupt case 1 mode.  */
-/* 	Disable if use interrupt case 2 mode. */
-//#define _INT_MODE_1					//	ON/OFF
-
-/* IRQ STATUS */
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 39) )
-#define IRQ_STATUS_DISABLED				0x200  
-#else
-#define IRQ_STATUS_DISABLED				(1<<16)
-#endif
-#define IRQ_STATUS_ENABLED				0x0
-
-/* Resolution mode */
-// Constant value 
-#define SIS_MAX_X						4095
-#define SIS_MAX_Y						4095
-
-#define ONE_BYTE						1
-#define FIVE_BYTE						5
-#define EIGHT_BYTE  					8
-#define SIXTEEN_BYTE					16
-#define PACKET_BUFFER_SIZE				128
-
-#define SIS_CMD_NORMAL					0x0
-#define SIS_CMD_SOFTRESET				0x82
-#define SIS_CMD_RECALIBRATE				0x87
-#define SIS_CMD_POWERMODE       		0x90
-#define MSK_TOUCHNUM					0x0f
-#define MSK_HAS_CRC						0x10
-#define MSK_DATAFMT						0xe0
-#define MSK_PSTATE						0x0f
-#define MSK_PID	                		0xf0
-#define RES_FMT							0x00
-#define FIX_FMT							0x40
-
-/* for new i2c format */
-#define TOUCHDOWN						0x3
-#define TOUCHUP							0x0
-#define MAX_BYTE						64
-#define	PRESSURE_MAX					255
-
-#ifdef _ANDROID_4
-#define AREA_LENGTH_LONGER				5792 //Resolution diagonal 
-#define AREA_LENGTH_SHORT				5792 // ((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5
-#define AREA_UNIT						(5792/32)
-#else
-#define AREA_LENGTH_LONGER				31
-#define AREA_LENGTH_SHORT				31
-#endif
-
-
-#define FORMAT_MODE						1
-
-#define MSK_NOBTN						0
-#define MSK_COMP						1
-#define MSK_BACK						2
-#define MSK_MENU						4
-#define MSK_HOME						8
-
-#define P_BYTECOUNT						0 
-#define ALL_IN_ONE_PACKAGE				0x10
-#define IS_TOUCH(x)						(x & 0x1)
-#define IS_HIDI2C(x)					(x & 0x6)
-#define IS_AREA(x)						((x >> 4) & 0x1)
-#define IS_PRESSURE(x)				    ((x >> 5) & 0x1)
-#define IS_SCANTIME(x)			        ((x >> 6) & 0x1)
-//#define _DEBUG_PACKAGE				//  ON/OFF
-//#define _DEBUG_PACKAGE_WORKFUNC		//  ON/OFF
-//#define _DEBUG_REPORT					//  ON/OFF
-
-#ifdef OLD_FORMAT_AEGIS
-#define TOUCH_NUM						1
-#define BUTTON_KEY_COUNT				8
-#define BUTTON_TOUCH					0x05
-#define BUTTON_TOUCH_ONE_POINT			0x0A
-#define BUTTON_TOUCH_MULTI_TOUCH		0x0F
-#define MSK_BUTTON_POINT				0xf0
-#define BUTTON_TOUCH_SERIAL				0x70
-#define BUTTON_STATE					(CMD_BASE + 1)
-
-#else
-//#define _CHECK_CRC					//  ON/OFF
-//#define _SUPPORT_BUTTON_TOUCH			//  ON/OFF
-#define TOUCH_FORMAT					0x1
-#define BUTTON_FORMAT					0x4
-#define HIDI2C_FORMAT					0x6
-#define P_REPORT_ID						2
-#define BUTTON_STATE					3
-#define BUTTON_KEY_COUNT				16
-#define BYTE_BYTECOUNT					2
-#define BYTE_COUNT						1
-#define BYTE_ReportID					1
-#define BYTE_CRC_HIDI2C					0
-#define BYTE_CRC_I2C					2
-#define BYTE_SCANTIME					2
-#define NO_TOUCH_BYTECOUNT				0x3
-#endif
-
-/* TODO */
-#define TOUCH_POWER_PIN					0
-#define TOUCH_RESET_PIN					1
-
-/* CMD Define */
-#define BUF_ACK_PLACE_L					4
-#define BUF_ACK_PLACE_H					5
-#define BUF_ACK_L						0xEF
-#define BUF_ACK_H						0xBE
-#define BUF_NACK_L						0xAD
-#define BUF_NACK_H						0xDE
-#define BUF_CRC_PLACE					7
-
-#endif /* _LINUX_SIS_I2C_H */
-
-enum SIS_817_POWER_MODE{
-	POWER_MODE_FWCTRL = 0x50,
-	POWER_MODE_ACTIVE = 0x51,
-	POWER_MODE_SLEEP  = 0x52
-};
-
-struct sis_i2c_rmi_platform_data {
-	int (*power)(int on);	/* Only valid in first array entry */
-};
-
-static const unsigned short crc16tab[256]= {
-		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
-        0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
-        0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
-        0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
-        0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
-        0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
-        0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
-        0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
-        0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
-        0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
-        0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
-        0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
-        0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
-        0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
-        0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
-        0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
-        0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
-        0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
-        0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
-        0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
-        0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
-        0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
-        0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
-        0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
-        0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
-        0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
-        0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
-        0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
-        0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
-        0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
-        0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
-        0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
-};
-
-struct Point {
-	int id;
-	unsigned short x, y;   	// uint16_t ?
-	uint16_t Pressure;
-	uint16_t Width;
-	uint16_t Height;
-};
-
-struct sisTP_driver_data {
-	int id;
-	int fingers;
-	uint8_t pre_keybit_state;	
-	struct Point pt[MAX_FINGERS];
-};
-
-struct sis_ts_data {
-	int (*power)(int on);
-	int use_irq;
-	struct i2c_client *client;
-	struct input_dev *input_dev;
-	struct hrtimer timer;
-	struct irq_desc *desc;
-	struct work_struct work;
-	struct mutex mutex_wq;
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	struct early_suspend early_suspend;
-#endif
-};
-
-static int sis_ts_suspend(struct i2c_client *client, pm_message_t mesg);
-static int sis_ts_resume(struct i2c_client *client);

^ permalink raw reply related	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2015-02-16 14:32 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-12 10:53 [PATCH 1/2] INPUT/HID: add touch support for SiS touch driver 曾婷葳 (tammy_tseng)
2015-01-12 10:53 ` 曾婷葳 (tammy_tseng)
2015-01-12 11:50 ` Oliver Neukum
     [not found]   ` <CAKR5kVFXy4GdZdHFnW2AAjqkcHfgfM5b0NhkOa079bftOoKqUQ@mail.gmail.com>
     [not found]     ` <8322374EB97AA24A95D0DDBFC8F1CA1DBF9DE5@SISMBEV01.sis.com.tw>
2015-01-16 10:59       ` 曾婷葳 (tammy_tseng)
2015-01-16 10:59         ` 曾婷葳 (tammy_tseng)
2015-01-16 13:11         ` Oliver Neukum
2015-01-16 13:11           ` Oliver Neukum
2015-01-17  0:04           ` Dmitry Torokhov
2015-01-17  0:04             ` Dmitry Torokhov
2015-02-12  6:07             ` 曾婷葳 (tammy_tseng)
2015-02-12  6:07               ` 曾婷葳 (tammy_tseng)
2015-02-12  7:02               ` Dmitry Torokhov
2015-02-12  7:02                 ` Dmitry Torokhov
2015-02-16 14:31               ` Oliver Neukum
2015-02-16 14:31                 ` Oliver Neukum
2015-02-16 14:16         ` Oliver Neukum
2015-02-16 14:16           ` Oliver Neukum
2015-01-16 11:19       ` 曾婷葳 (tammy_tseng)
2015-01-16 11:19         ` 曾婷葳 (tammy_tseng)
  -- strict thread matches above, loose matches on Subject: below --
2015-01-09 10:37 曾婷葳 (tammy_tseng)
2015-01-09 10:37 ` 曾婷葳 (tammy_tseng)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.