All of lore.kernel.org
 help / color / mirror / Atom feed
* RE: [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-12 10:55 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 13+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-12 10:55 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 hid multitouch driver is in hid.

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

diff --git a/linux-3.18.1/drivers/hid/Kconfig b/linux-3.18.1/drivers/hid/Kconfig
index f42df4d..2be7677 100644
--- a/linux-3.18.1/drivers/hid/Kconfig
+++ b/linux-3.18.1/drivers/hid/Kconfig
@@ -494,7 +494,35 @@ config HID_MULTITOUCH
 	  If unsure, say N.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called hid-multitouch.
+	  module will be called hid-multitouch.  
+	  
+config HID_MT_DBG_POINT
+	bool "HID Multitouch panels debug for touch point"
+	depends on HID_MULTITOUCH
+	default n
+	---help---
+	  Show debug message for touch point information.
+
+config HID_MT_DBG_MAP_INIT
+	bool "HID Multitouch panels debug mapping initial"
+	depends on HID_MULTITOUCH
+	default n
+	---help---
+	  Show debug message for mapping initial information.  
+
+config HID_SIS_CTRL
+	tristate "SiS Touch Device Controller"
+	depends on HID_MULTITOUCH
+	---help---
+	Support for SiS Touch devices update FW.
+
+config DEBUG_HID_SIS_UPDATE_FW
+	bool "SiS Touch device debug message(update firmware)"
+	depends on HID_SIS_CTRL
+	default n
+	---help---
+	  Say Y here if you want to enable debug message(update firmware) for SiS Touch 
+          devices. Must enable config HID_SIS_UPDATE_FW first.
 
 config HID_NTRIG
 	tristate "N-Trig touch screen"
diff --git a/linux-3.18.1/drivers/hid/Makefile b/linux-3.18.1/drivers/hid/Makefile
index e2850d8..02dc20d 100644
--- a/linux-3.18.1/drivers/hid/Makefile
+++ b/linux-3.18.1/drivers/hid/Makefile
@@ -33,6 +33,7 @@ ifdef CONFIG_DEBUG_FS
 	hid-wiimote-y	+= hid-wiimote-debug.o
 endif
 
+obj-$(CONFIG_HID_SIS_CTRL)	+= hid-sis_ctrl.o
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
 obj-$(CONFIG_HID_ACRUX)		+= hid-axff.o
 obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
diff --git a/linux-3.18.1/drivers/hid/hid-ids.h b/linux-3.18.1/drivers/hid/hid-ids.h
index 7c86373..c598e8d 100644
--- a/linux-3.18.1/drivers/hid/hid-ids.h
+++ b/linux-3.18.1/drivers/hid/hid-ids.h
@@ -807,6 +807,7 @@
 #define USB_VENDOR_ID_SIS_TOUCH		0x0457
 #define USB_DEVICE_ID_SIS9200_TOUCH	0x9200
 #define USB_DEVICE_ID_SIS817_TOUCH	0x0817
+#define USB_PRODUCT_ID_SISF817_TOUCH	0xF817
 #define USB_DEVICE_ID_SIS_TS		0x1013
 #define USB_DEVICE_ID_SIS1030_TOUCH	0x1030
 
diff --git a/linux-3.18.1/drivers/hid/hid-multitouch.c b/linux-3.18.1/drivers/hid/hid-multitouch.c
index 51e25b9..31e28dd 100644
--- a/linux-3.18.1/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.1/drivers/hid/hid-multitouch.c
@@ -45,7 +45,7 @@
 #include <linux/usb.h>
 #include <linux/input/mt.h>
 #include <linux/string.h>
-
+#include "hid-sis_ctrl.h"
 
 MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
@@ -1003,6 +1003,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (ret != 0)
 		return ret;
 
+	//SiS set noget for not init reports
+	hdev->quirks |= HID_QUIRK_NOGET;
+	printk(KERN_INFO "sis:sis-probe: quirk = %x\n", hdev->quirks);
+
+	//SiS FW update
+#ifdef CONFIG_HID_SIS_CTRL
+	ret = sis_setup_chardev(hdev);
+	if(ret)
+	{
+		printk( KERN_INFO "sis_setup_chardev fail\n");
+	}
+#endif	//CONFIG_HID_SIS_CTRL
+
 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 	if (ret)
 		return ret;
@@ -1041,6 +1054,10 @@ static int mt_resume(struct hid_device *hdev)
 
 static void mt_remove(struct hid_device *hdev)
 {
+	//SiS FW update
+#ifdef CONFIG_HID_SIS_CTRL
+	sis_deinit_chardev();
+#endif	//CONFIG_HID_SIS_CTRL
 	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
 	hid_hw_stop(hdev);
 }
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.c b/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
new file mode 100644
index 0000000..2794b65
--- /dev/null
+++ b/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
@@ -0,0 +1,397 @@
+/*
+ *  Character device driver for SIS multitouch panels control
+ *
+ *  Copyright (c) 2009 SIS, Ltd.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/init.h>
+
+//update FW
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <asm/uaccess.h>	//copy_from_user() & copy_to_user()
+
+#include "hid-ids.h"
+#include "hid-sis_ctrl.h"
+
+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;
+
+static struct hid_device *hid_dev_backup = NULL;  //backup address
+static struct urb *backup_urb = NULL;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+	#define DBG_FW(fmt, arg...)	printk( fmt, ##arg )
+	void sis_dbg_dump_array( u8 *ptr, u32 size)
+	{
+		u32 i;
+		for (i=0; i<size; i++)  
+		{
+			DBG_FW ("%02X ", ptr[i]);
+			if( ((i+1)&0xF) == 0)
+				DBG_FW ("\n");
+		}
+		if( size & 0xF)
+			DBG_FW ("\n");
+	}
+#else
+	#define DBG_FW(...)
+	#define sis_dbg_dump_array(...)
+#endif	// CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+
+int sis_cdev_open(struct inode *inode, struct file *filp)	//20120306 Yuger ioctl for tool
+{
+	struct usbhid_device *usbhid; 
+
+	DBG_FW( "%s\n" , __FUNCTION__ );
+	//20110511, Yuger, kill current urb by method of usbhid_stop
+	if ( !hid_dev_backup )
+	{
+		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
+		return -1;
+	}
+
+	usbhid = hid_dev_backup->driver_data;
+
+	printk( KERN_INFO "sys_sis_HID_stop\n" );
+
+	//printk( KERN_INFO "hid_dev_backup->vendor, hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor, hid_dev_backup->product );
+
+	//20110602, Yuger, fix bug: not contact usb cause kernel panic
+	if( !usbhid )
+	{
+		printk( KERN_INFO "(stop)usbhid is not initialized yet" );
+		return -1;
+	}
+	else if ( !usbhid->urbin )
+	{
+		printk( KERN_INFO "(stop)usbhid->urbin is not initialized yet" );
+		return -1;
+	}
+	else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS2_TOUCH)
+	{
+		usb_fill_int_urb(backup_urb, usbhid->urbin->dev, usbhid->urbin->pipe,
+			usbhid->urbin->transfer_buffer, usbhid->urbin->transfer_buffer_length,
+			usbhid->urbin->complete, usbhid->urbin->context, usbhid->urbin->interval);
+
+                clear_bit( HID_STARTED, &usbhid->iofl );
+                set_bit( HID_DISCONNECTED, &usbhid->iofl );
+
+                usb_kill_urb( usbhid->urbin );
+                usb_free_urb( usbhid->urbin );
+                usbhid->urbin = NULL;
+		return 0;
+	}
+    else	
+	{
+		printk (KERN_INFO "This is not a SiS device");
+		return -801;
+	}
+}
+
+int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	//20110505, Yuger, rebuild the urb which is at the same urb address, then re-submit it
+
+	int ret;
+	struct usbhid_device *usbhid;
+	unsigned long flags;
+	
+	DBG_FW( "%s: " , __FUNCTION__ );
+	
+	if ( !hid_dev_backup )
+	{
+		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
+		return -1;
+	}
+
+	usbhid = hid_dev_backup->driver_data;
+
+	printk( KERN_INFO "sys_sis_HID_start" );
+
+	if( !usbhid )
+	{
+		printk( KERN_INFO "(start)usbhid is not initialized yet" );
+		return -1;
+	}
+
+	if( !backup_urb )
+	{
+		printk( KERN_INFO "(start)backup_urb is not initialized yet" );
+		return -1;
+	}
+
+	clear_bit( HID_DISCONNECTED, &usbhid->iofl );
+	usbhid->urbin = usb_alloc_urb( 0, GFP_KERNEL );
+
+	if( !backup_urb->interval )
+	{
+		printk( KERN_INFO "(start)backup_urb->interval does not exist" );
+		return -1;
+	}
+
+	usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe, 
+		backup_urb->transfer_buffer, backup_urb->transfer_buffer_length, 
+		backup_urb->complete, backup_urb->context, backup_urb->interval);
+	usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+	usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	set_bit( HID_STARTED, &usbhid->iofl );
+
+	//method at hid_start_in
+	spin_lock_irqsave( &usbhid->lock, flags );		
+	ret = usb_submit_urb( usbhid->urbin, GFP_ATOMIC );
+	spin_unlock_irqrestore( &usbhid->lock, flags );
+	//yy
+
+	DBG_FW( "ret = %d", ret );
+
+	return ret;
+}
+
+//SiS 817 only
+ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	int actual_length = 0, timeout = 0;
+	u8 *rep_data = NULL;
+	u16 size = 0;
+	long rep_ret;
+	struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent);
+	struct usb_device *dev = interface_to_usbdev(intf);
+
+	DBG_FW( "%s\n" , __FUNCTION__ );
+	
+	size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
+		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
+	timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
+		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
+
+	rep_data = kzalloc(size, GFP_KERNEL);
+	if (!rep_data)
+		return -12;
+
+	if ( copy_from_user( rep_data, (void*)buf, size) ) 
+	{
+		printk( KERN_INFO "copy_to_user fail\n" );
+		//free allocated data
+		kfree( rep_data );
+		rep_data = NULL;
+		return -19;
+	}
+
+	rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
+		rep_data, size, &actual_length, timeout);
+
+	DBG_FW( "%s: rep_data = ", __FUNCTION__);
+	sis_dbg_dump_array( rep_data, 8);
+		
+	if( rep_ret == 0 )
+	{
+		rep_ret = actual_length;
+		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
+		{
+			printk( KERN_INFO "copy_to_user fail\n" );
+			//free allocated data
+			kfree( rep_data );
+			rep_data = NULL;
+			return -19;
+		}
+	}
+
+	//free allocated data
+	kfree( rep_data );
+	rep_data = NULL;
+	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
+	return rep_ret;
+}
+
+ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
+{
+	int actual_length = 0;
+	u8 *rep_data = NULL;
+	long rep_ret;
+	struct usb_interface *intf = to_usb_interface( hid_dev_backup->dev.parent );
+	struct usb_device *dev = interface_to_usbdev( intf );
+	struct usbhid_device *usbhid = hid_dev_backup->driver_data;
+
+	u16 size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
+		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
+	int timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
+		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
+	
+	DBG_FW( "%s: 817 method, " , __FUNCTION__ );
+	DBG_FW("timeout = %d, size %d\n", timeout, size);
+
+	rep_data = kzalloc(size, GFP_KERNEL);
+	if (!rep_data)
+		return -12;
+
+	if ( copy_from_user( rep_data, (void*)buf, size) ) 
+	{
+		printk( KERN_INFO "copy_to_user fail\n" );
+		//free allocated data
+		kfree( rep_data );
+		rep_data = NULL;
+		return -19;
+	}
+
+	rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe,
+		rep_data, size, &actual_length, timeout );
+	
+	DBG_FW( "%s: rep_data = ", __FUNCTION__);
+	sis_dbg_dump_array( rep_data, size);
+	
+	if( rep_ret == 0 )
+	{
+		rep_ret = actual_length;
+		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
+		{
+			printk( KERN_INFO "copy_to_user fail\n" );
+			//free allocated data
+			kfree( rep_data );
+			rep_data = NULL;
+			return -19;
+		}
+	}
+	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
+	
+	//free allocated data
+	kfree( rep_data );
+	rep_data = NULL;
+
+	DBG_FW( "End of sys_sis_HID_IO\n" );
+	return rep_ret;
+}
+
+
+//for ioctl
+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,
+};
+
+//for ioctl
+int sis_setup_chardev(struct hid_device *hdev)
+{
+	
+	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");
+	hid_dev_backup = hdev;
+	
+	backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test
+	if (!backup_urb) {
+		dev_err(&hdev->dev, "cannot allocate backup_urb\n");
+		return -ENOMEM;
+	}
+/*	
+	if (nd == NULL) 
+	{
+          input_err = -ENOMEM;
+          goto error;
+	} 
+*/
+	// dynamic allocate driver handle
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SISF817_DEVICE_NAME);
+	else
+		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS817_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;
+
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		printk(KERN_INFO "%s driver(major %d) installed.\n", SISF817_DEVICE_NAME, sis_char_major);
+	else
+		printk(KERN_INFO "%s driver(major %d) installed.\n", SIS817_DEVICE_NAME, sis_char_major);
+
+	// register class
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		sis_char_class = class_create(THIS_MODULE, SISF817_DEVICE_NAME);
+	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
+		sis_char_class = class_create(THIS_MODULE, SIS817_DEVICE_NAME);
+
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SISF817_DEVICE_NAME);
+	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
+		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS817_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;
+}
+EXPORT_SYMBOL(sis_setup_chardev);
+
+void sis_deinit_chardev(void)
+{
+	//for ioctl
+	dev_t dev;
+	printk(KERN_INFO "sis_remove\n");
+
+	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);
+	usb_kill_urb( backup_urb );
+	usb_free_urb( backup_urb );
+	backup_urb = NULL;
+	hid_dev_backup = NULL;
+	
+}
+EXPORT_SYMBOL(sis_deinit_chardev);
+
+MODULE_DESCRIPTION("SiS 817 Touchscreen Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.h b/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
new file mode 100644
index 0000000..c7425c5
--- /dev/null
+++ b/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
@@ -0,0 +1,19 @@
+#ifndef __HID_SIS_CTRL_H__
+#define __HID_SIS_CTRL_H__
+
+#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
+#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
+
+#define CTRL 0
+#define ENDP_01 1
+#define ENDP_02 2
+#define DIR_IN 0x1
+
+int sis_cdev_open(struct inode *inode, struct file *filp);
+int sis_cdev_release(struct inode *inode, struct file *filp);
+ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
+ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos );
+int sis_setup_chardev(struct hid_device *hdev);
+void sis_deinit_chardev(void);
+
+#endif	// __HID_SIS_CTRL_H__
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] 13+ messages in thread

* RE: [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-12 10:55 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 13+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-12 10:55 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 hid multitouch driver is in hid.

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

diff --git a/linux-3.18.1/drivers/hid/Kconfig b/linux-3.18.1/drivers/hid/Kconfig
index f42df4d..2be7677 100644
--- a/linux-3.18.1/drivers/hid/Kconfig
+++ b/linux-3.18.1/drivers/hid/Kconfig
@@ -494,7 +494,35 @@ config HID_MULTITOUCH
 	  If unsure, say N.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called hid-multitouch.
+	  module will be called hid-multitouch.  
+	  
+config HID_MT_DBG_POINT
+	bool "HID Multitouch panels debug for touch point"
+	depends on HID_MULTITOUCH
+	default n
+	---help---
+	  Show debug message for touch point information.
+
+config HID_MT_DBG_MAP_INIT
+	bool "HID Multitouch panels debug mapping initial"
+	depends on HID_MULTITOUCH
+	default n
+	---help---
+	  Show debug message for mapping initial information.  
+
+config HID_SIS_CTRL
+	tristate "SiS Touch Device Controller"
+	depends on HID_MULTITOUCH
+	---help---
+	Support for SiS Touch devices update FW.
+
+config DEBUG_HID_SIS_UPDATE_FW
+	bool "SiS Touch device debug message(update firmware)"
+	depends on HID_SIS_CTRL
+	default n
+	---help---
+	  Say Y here if you want to enable debug message(update firmware) for SiS Touch 
+          devices. Must enable config HID_SIS_UPDATE_FW first.
 
 config HID_NTRIG
 	tristate "N-Trig touch screen"
diff --git a/linux-3.18.1/drivers/hid/Makefile b/linux-3.18.1/drivers/hid/Makefile
index e2850d8..02dc20d 100644
--- a/linux-3.18.1/drivers/hid/Makefile
+++ b/linux-3.18.1/drivers/hid/Makefile
@@ -33,6 +33,7 @@ ifdef CONFIG_DEBUG_FS
 	hid-wiimote-y	+= hid-wiimote-debug.o
 endif
 
+obj-$(CONFIG_HID_SIS_CTRL)	+= hid-sis_ctrl.o
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
 obj-$(CONFIG_HID_ACRUX)		+= hid-axff.o
 obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
diff --git a/linux-3.18.1/drivers/hid/hid-ids.h b/linux-3.18.1/drivers/hid/hid-ids.h
index 7c86373..c598e8d 100644
--- a/linux-3.18.1/drivers/hid/hid-ids.h
+++ b/linux-3.18.1/drivers/hid/hid-ids.h
@@ -807,6 +807,7 @@
 #define USB_VENDOR_ID_SIS_TOUCH		0x0457
 #define USB_DEVICE_ID_SIS9200_TOUCH	0x9200
 #define USB_DEVICE_ID_SIS817_TOUCH	0x0817
+#define USB_PRODUCT_ID_SISF817_TOUCH	0xF817
 #define USB_DEVICE_ID_SIS_TS		0x1013
 #define USB_DEVICE_ID_SIS1030_TOUCH	0x1030
 
diff --git a/linux-3.18.1/drivers/hid/hid-multitouch.c b/linux-3.18.1/drivers/hid/hid-multitouch.c
index 51e25b9..31e28dd 100644
--- a/linux-3.18.1/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.1/drivers/hid/hid-multitouch.c
@@ -45,7 +45,7 @@
 #include <linux/usb.h>
 #include <linux/input/mt.h>
 #include <linux/string.h>
-
+#include "hid-sis_ctrl.h"
 
 MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
@@ -1003,6 +1003,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (ret != 0)
 		return ret;
 
+	//SiS set noget for not init reports
+	hdev->quirks |= HID_QUIRK_NOGET;
+	printk(KERN_INFO "sis:sis-probe: quirk = %x\n", hdev->quirks);
+
+	//SiS FW update
+#ifdef CONFIG_HID_SIS_CTRL
+	ret = sis_setup_chardev(hdev);
+	if(ret)
+	{
+		printk( KERN_INFO "sis_setup_chardev fail\n");
+	}
+#endif	//CONFIG_HID_SIS_CTRL
+
 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 	if (ret)
 		return ret;
@@ -1041,6 +1054,10 @@ static int mt_resume(struct hid_device *hdev)
 
 static void mt_remove(struct hid_device *hdev)
 {
+	//SiS FW update
+#ifdef CONFIG_HID_SIS_CTRL
+	sis_deinit_chardev();
+#endif	//CONFIG_HID_SIS_CTRL
 	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
 	hid_hw_stop(hdev);
 }
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.c b/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
new file mode 100644
index 0000000..2794b65
--- /dev/null
+++ b/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
@@ -0,0 +1,397 @@
+/*
+ *  Character device driver for SIS multitouch panels control
+ *
+ *  Copyright (c) 2009 SIS, Ltd.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/init.h>
+
+//update FW
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <asm/uaccess.h>	//copy_from_user() & copy_to_user()
+
+#include "hid-ids.h"
+#include "hid-sis_ctrl.h"
+
+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;
+
+static struct hid_device *hid_dev_backup = NULL;  //backup address
+static struct urb *backup_urb = NULL;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+	#define DBG_FW(fmt, arg...)	printk( fmt, ##arg )
+	void sis_dbg_dump_array( u8 *ptr, u32 size)
+	{
+		u32 i;
+		for (i=0; i<size; i++)  
+		{
+			DBG_FW ("%02X ", ptr[i]);
+			if( ((i+1)&0xF) == 0)
+				DBG_FW ("\n");
+		}
+		if( size & 0xF)
+			DBG_FW ("\n");
+	}
+#else
+	#define DBG_FW(...)
+	#define sis_dbg_dump_array(...)
+#endif	// CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+
+int sis_cdev_open(struct inode *inode, struct file *filp)	//20120306 Yuger ioctl for tool
+{
+	struct usbhid_device *usbhid; 
+
+	DBG_FW( "%s\n" , __FUNCTION__ );
+	//20110511, Yuger, kill current urb by method of usbhid_stop
+	if ( !hid_dev_backup )
+	{
+		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
+		return -1;
+	}
+
+	usbhid = hid_dev_backup->driver_data;
+
+	printk( KERN_INFO "sys_sis_HID_stop\n" );
+
+	//printk( KERN_INFO "hid_dev_backup->vendor, hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor, hid_dev_backup->product );
+
+	//20110602, Yuger, fix bug: not contact usb cause kernel panic
+	if( !usbhid )
+	{
+		printk( KERN_INFO "(stop)usbhid is not initialized yet" );
+		return -1;
+	}
+	else if ( !usbhid->urbin )
+	{
+		printk( KERN_INFO "(stop)usbhid->urbin is not initialized yet" );
+		return -1;
+	}
+	else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS2_TOUCH)
+	{
+		usb_fill_int_urb(backup_urb, usbhid->urbin->dev, usbhid->urbin->pipe,
+			usbhid->urbin->transfer_buffer, usbhid->urbin->transfer_buffer_length,
+			usbhid->urbin->complete, usbhid->urbin->context, usbhid->urbin->interval);
+
+                clear_bit( HID_STARTED, &usbhid->iofl );
+                set_bit( HID_DISCONNECTED, &usbhid->iofl );
+
+                usb_kill_urb( usbhid->urbin );
+                usb_free_urb( usbhid->urbin );
+                usbhid->urbin = NULL;
+		return 0;
+	}
+    else	
+	{
+		printk (KERN_INFO "This is not a SiS device");
+		return -801;
+	}
+}
+
+int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+	//20110505, Yuger, rebuild the urb which is at the same urb address, then re-submit it
+
+	int ret;
+	struct usbhid_device *usbhid;
+	unsigned long flags;
+	
+	DBG_FW( "%s: " , __FUNCTION__ );
+	
+	if ( !hid_dev_backup )
+	{
+		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
+		return -1;
+	}
+
+	usbhid = hid_dev_backup->driver_data;
+
+	printk( KERN_INFO "sys_sis_HID_start" );
+
+	if( !usbhid )
+	{
+		printk( KERN_INFO "(start)usbhid is not initialized yet" );
+		return -1;
+	}
+
+	if( !backup_urb )
+	{
+		printk( KERN_INFO "(start)backup_urb is not initialized yet" );
+		return -1;
+	}
+
+	clear_bit( HID_DISCONNECTED, &usbhid->iofl );
+	usbhid->urbin = usb_alloc_urb( 0, GFP_KERNEL );
+
+	if( !backup_urb->interval )
+	{
+		printk( KERN_INFO "(start)backup_urb->interval does not exist" );
+		return -1;
+	}
+
+	usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe, 
+		backup_urb->transfer_buffer, backup_urb->transfer_buffer_length, 
+		backup_urb->complete, backup_urb->context, backup_urb->interval);
+	usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+	usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	set_bit( HID_STARTED, &usbhid->iofl );
+
+	//method at hid_start_in
+	spin_lock_irqsave( &usbhid->lock, flags );		
+	ret = usb_submit_urb( usbhid->urbin, GFP_ATOMIC );
+	spin_unlock_irqrestore( &usbhid->lock, flags );
+	//yy
+
+	DBG_FW( "ret = %d", ret );
+
+	return ret;
+}
+
+//SiS 817 only
+ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	int actual_length = 0, timeout = 0;
+	u8 *rep_data = NULL;
+	u16 size = 0;
+	long rep_ret;
+	struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent);
+	struct usb_device *dev = interface_to_usbdev(intf);
+
+	DBG_FW( "%s\n" , __FUNCTION__ );
+	
+	size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
+		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
+	timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
+		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
+
+	rep_data = kzalloc(size, GFP_KERNEL);
+	if (!rep_data)
+		return -12;
+
+	if ( copy_from_user( rep_data, (void*)buf, size) ) 
+	{
+		printk( KERN_INFO "copy_to_user fail\n" );
+		//free allocated data
+		kfree( rep_data );
+		rep_data = NULL;
+		return -19;
+	}
+
+	rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
+		rep_data, size, &actual_length, timeout);
+
+	DBG_FW( "%s: rep_data = ", __FUNCTION__);
+	sis_dbg_dump_array( rep_data, 8);
+		
+	if( rep_ret == 0 )
+	{
+		rep_ret = actual_length;
+		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
+		{
+			printk( KERN_INFO "copy_to_user fail\n" );
+			//free allocated data
+			kfree( rep_data );
+			rep_data = NULL;
+			return -19;
+		}
+	}
+
+	//free allocated data
+	kfree( rep_data );
+	rep_data = NULL;
+	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
+	return rep_ret;
+}
+
+ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
+{
+	int actual_length = 0;
+	u8 *rep_data = NULL;
+	long rep_ret;
+	struct usb_interface *intf = to_usb_interface( hid_dev_backup->dev.parent );
+	struct usb_device *dev = interface_to_usbdev( intf );
+	struct usbhid_device *usbhid = hid_dev_backup->driver_data;
+
+	u16 size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
+		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
+	int timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
+		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
+	
+	DBG_FW( "%s: 817 method, " , __FUNCTION__ );
+	DBG_FW("timeout = %d, size %d\n", timeout, size);
+
+	rep_data = kzalloc(size, GFP_KERNEL);
+	if (!rep_data)
+		return -12;
+
+	if ( copy_from_user( rep_data, (void*)buf, size) ) 
+	{
+		printk( KERN_INFO "copy_to_user fail\n" );
+		//free allocated data
+		kfree( rep_data );
+		rep_data = NULL;
+		return -19;
+	}
+
+	rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe,
+		rep_data, size, &actual_length, timeout );
+	
+	DBG_FW( "%s: rep_data = ", __FUNCTION__);
+	sis_dbg_dump_array( rep_data, size);
+	
+	if( rep_ret == 0 )
+	{
+		rep_ret = actual_length;
+		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
+		{
+			printk( KERN_INFO "copy_to_user fail\n" );
+			//free allocated data
+			kfree( rep_data );
+			rep_data = NULL;
+			return -19;
+		}
+	}
+	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
+	
+	//free allocated data
+	kfree( rep_data );
+	rep_data = NULL;
+
+	DBG_FW( "End of sys_sis_HID_IO\n" );
+	return rep_ret;
+}
+
+
+//for ioctl
+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,
+};
+
+//for ioctl
+int sis_setup_chardev(struct hid_device *hdev)
+{
+	
+	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");
+	hid_dev_backup = hdev;
+	
+	backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test
+	if (!backup_urb) {
+		dev_err(&hdev->dev, "cannot allocate backup_urb\n");
+		return -ENOMEM;
+	}
+/*	
+	if (nd == NULL) 
+	{
+          input_err = -ENOMEM;
+          goto error;
+	} 
+*/
+	// dynamic allocate driver handle
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SISF817_DEVICE_NAME);
+	else
+		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS817_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;
+
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		printk(KERN_INFO "%s driver(major %d) installed.\n", SISF817_DEVICE_NAME, sis_char_major);
+	else
+		printk(KERN_INFO "%s driver(major %d) installed.\n", SIS817_DEVICE_NAME, sis_char_major);
+
+	// register class
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		sis_char_class = class_create(THIS_MODULE, SISF817_DEVICE_NAME);
+	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
+		sis_char_class = class_create(THIS_MODULE, SIS817_DEVICE_NAME);
+
+	if(IS_ERR(ptr_err = sis_char_class)) 
+	{
+		goto err2;
+	}
+
+	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SISF817_DEVICE_NAME);
+	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
+		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS817_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;
+}
+EXPORT_SYMBOL(sis_setup_chardev);
+
+void sis_deinit_chardev(void)
+{
+	//for ioctl
+	dev_t dev;
+	printk(KERN_INFO "sis_remove\n");
+
+	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);
+	usb_kill_urb( backup_urb );
+	usb_free_urb( backup_urb );
+	backup_urb = NULL;
+	hid_dev_backup = NULL;
+	
+}
+EXPORT_SYMBOL(sis_deinit_chardev);
+
+MODULE_DESCRIPTION("SiS 817 Touchscreen Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.h b/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
new file mode 100644
index 0000000..c7425c5
--- /dev/null
+++ b/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
@@ -0,0 +1,19 @@
+#ifndef __HID_SIS_CTRL_H__
+#define __HID_SIS_CTRL_H__
+
+#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
+#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
+
+#define CTRL 0
+#define ENDP_01 1
+#define ENDP_02 2
+#define DIR_IN 0x1
+
+int sis_cdev_open(struct inode *inode, struct file *filp);
+int sis_cdev_release(struct inode *inode, struct file *filp);
+ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
+ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos );
+int sis_setup_chardev(struct hid_device *hdev);
+void sis_deinit_chardev(void);
+
+#endif	// __HID_SIS_CTRL_H__
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] 13+ messages in thread

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

On Mon, Feb 16, 2015 at 10:10 AM, Oliver Neukum <oneukum@suse.de> wrote:
> On Thu, 2015-02-12 at 15:24 +0800, 曾婷葳 (tammy_tseng) wrote:
>
>> Sorry. Re-send the code diff again.
>> Here is the hid touch driver for sis touch controller.
>> Thanks.
>
> This driver does very strange things. It looks like you are
> simulating a disconnect() to the usbhid driver currently driving
> the device. This is unacceptable. Please add the device to the
> generic blacklist and implement a clean open/close.
>

Indeed, this driver does very strange things.
At least you should explain in the commit messages why you need to
have a custom chardev in the hid tree and why using a plain HID
communication is not enough while discussing with the hardware.

Also, I am not especially happy with your way of quirking
hid-multitouch in such a specific way without external control (i.e.
not having put this in a MT_CLS).

Please split the 2 features (if I understand correctly enabling of the
multitouch mode and firmware update) in 2 separate patches.

How about not having a FW update capability in the kernel and just use
a plain hidraw user space application which would call the firmware
update?

Last, all HID drivers go through Jiri's tree, so you definitively
should add him in CC of your submissions.

Cheers,
Benjamin

>         Regards
>                 Oliver
>
>> Tammy
>> -----
>>
>> linux-3.18.5/drivers/hid/Kconfig             |  14 ++
>> linux-3.18.5/drivers/hid/hid-ids.h           |   1 +
>> linux-3.18.5/drivers/hid/hid-multitouch.c    |  16 ++
>> linux-3.18.5/drivers/hid/hid-sis_ctrl.c      | 360 +++++++++++++++++++++++++++
>> linux-3.18.5/drivers/hid/usbhid/hid-quirks.c |   1 +
>> 5 files changed, 392 insertions(+)
>>
>>
>> -----
>> diff --git a/linux-3.18.5/drivers/hid/Kconfig b/linux-3.18.5/drivers/hid/Kconfig
>> index f42df4d..2235cfe 100644
>> --- a/linux-3.18.5/drivers/hid/Kconfig
>> +++ b/linux-3.18.5/drivers/hid/Kconfig
>> @@ -496,6 +496,20 @@ config HID_MULTITOUCH
>>         To compile this driver as a module, choose M here: the
>>         module will be called hid-multitouch.
>>
>> +config HID_SIS_CTRL
>> +      bool "SiS Touch Device Controller"
>> +      depends on HID_MULTITOUCH
>> +      ---help---
>> +      Support for SiS Touch devices update FW.
>> +
>> +config DEBUG_HID_SIS_UPDATE_FW
>> +      bool "SiS Touch device debug message(update firmware)"
>> +      depends on HID_SIS_CTRL
>> +      default n
>> +      ---help---
>> +        Say Y here if you want to enable debug message(update firmware) for SiS Touch
>> +          devices. Must enable config HID_SIS_UPDATE_FW first.
>> +
>> config HID_NTRIG
>>       tristate "N-Trig touch screen"
>>       depends on USB_HID
>> diff --git a/linux-3.18.5/drivers/hid/hid-ids.h b/linux-3.18.5/drivers/hid/hid-ids.h
>> index 0e28190..b9ca441 100644
>> --- a/linux-3.18.5/drivers/hid/hid-ids.h
>> +++ b/linux-3.18.5/drivers/hid/hid-ids.h
>> @@ -809,6 +809,7 @@
>> #define USB_VENDOR_ID_SIS_TOUCH                0x0457
>> #define USB_DEVICE_ID_SIS9200_TOUCH  0x9200
>> #define USB_DEVICE_ID_SIS817_TOUCH    0x0817
>> +#define USB_DEVICE_ID_SISF817_TOUCH  0xF817
>> #define USB_DEVICE_ID_SIS_TS          0x1013
>> #define USB_DEVICE_ID_SIS1030_TOUCH  0x1030
>>
>> diff --git a/linux-3.18.5/drivers/hid/hid-multitouch.c b/linux-3.18.5/drivers/hid/hid-multitouch.c
>> index 51e25b9..11d67bc 100644
>> --- a/linux-3.18.5/drivers/hid/hid-multitouch.c
>> +++ b/linux-3.18.5/drivers/hid/hid-multitouch.c
>> @@ -54,6 +54,10 @@ MODULE_LICENSE("GPL");
>>
>>  #include "hid-ids.h"
>>
>> +#ifdef CONFIG_HID_SIS_CTRL
>> +#include "hid-sis_ctrl.c"
>> +#endif
>> +
>> /* quirks to control the device */
>> #define MT_QUIRK_NOT_SEEN_MEANS_UP      (1 << 0)
>> #define MT_QUIRK_SLOT_IS_CONTACTID   (1 << 1)
>> @@ -951,6 +955,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
>>               }
>>       }
>>
>> +#ifdef CONFIG_HID_SIS_CTRL
>> +      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
>> +              ret = sis_setup_chardev(hdev);
>> +              if (ret)
>> +                      dev_err(&hdev->dev, "sis_setup_chardev fail\n");
>> +      }
>> +#endif
>> +
>>       /* This allows the driver to correctly support devices
>>        * that emit events over several HID messages.
>>        */
>> @@ -1043,6 +1055,10 @@ static void mt_remove(struct hid_device *hdev) {
>>       sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
>>       hid_hw_stop(hdev);
>> +#ifdef CONFIG_HID_SIS_CTRL
>> +      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
>> +              sis_deinit_chardev();
>> +#endif
>> }
>>
>>  /*
>> diff --git a/linux-3.18.5/drivers/hid/hid-sis_ctrl.c b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
>> new file mode 100644
>> index 0000000..3a7b3df
>> --- /dev/null
>> +++ b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
>> @@ -0,0 +1,360 @@
>> +/*
>> + *  Character device driver for SIS multitouch panels control
>> + *
>> + *  Copyright (c) 2009 SIS, Ltd.
>> + *
>> + */
>> +
>> +/*
>> + * This program is free software; you can redistribute it and/or modify
>> +it
>> + * under the terms of the GNU General Public License as published by
>> +the Free
>> + * Software Foundation; either version 2 of the License, or (at your
>> +option)
>> + * any later version.
>> + */
>> +
>> +#include <linux/hid.h>
>> +#include <linux/module.h>
>> +#include <linux/usb.h>
>> +#include "usbhid/usbhid.h"
>> +#include <linux/init.h>
>> +
>> +/*update FW*/
>> +#include <linux/fs.h>
>> +#include <linux/cdev.h>
>> +/*#include <asm/uaccess.h>*/   /*copy_from_user() & copy_to_user()*/
>> +#include <linux/uaccess.h>
>> +
>> +#include "hid-ids.h"
>> +
>> +#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
>> +#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
>> +
>> +#define CTRL 0
>> +#define ENDP_01 1
>> +#define ENDP_02 2
>> +#define DIR_IN 0x1
>> +
>> +#define SIS_ERR_ALLOCATE_KERNEL_MEM        -12 /* Allocate memory fail */
>> +#define SIS_ERR_COPY_FROM_USER          -14 /* Copy data from user fail */
>> +#define SIS_ERR_COPY_FROM_KERNEL      -19 /* Copy data from kernel fail */
>
> You _must_ use the symbolic names. You cannot use numbers.
>
>> +
>> +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;
>> +
>> +static struct hid_device *hid_dev_backup;        /*backup address*/
>> +static struct urb *backup_urb;
>> +
>> +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
>> +      #define DBG_FW(fmt, arg...) printk(fmt, ##arg)
>> +      static void sis_dbg_dump_array(u8 *ptr, u32 size)
>> +      {
>> +              u32 i;
>> +
>> +              for (i = 0; i < size; i++) {
>> +                      DBG_FW("%02X ", ptr[i]);
>> +                      if (((i+1)&0xF) == 0)
>> +                              DBG_FW("\n");
>> +              }
>> +              if (size & 0xF)
>> +                      DBG_FW("\n");
>> +      }
>> +#else
>> +      #define DBG_FW(...)
>> +      #define sis_dbg_dump_array(...)
>> +#endif   /*CONFIG_DEBUG_HID_SIS_UPDATE_FW*/
>> +
>> +/*20120306 Yuger ioctl for tool*/
>> +static int sis_cdev_open(struct inode *inode, struct file *filp) {
>> +      struct usbhid_device *usbhid;
>> +
>> +      DBG_FW("%s\n" , __func__);
>> +      /*20110511, Yuger, kill current urb by method of usbhid_stop*/
>> +      if (!hid_dev_backup) {
>
> Why is this needed?
>
>> +              pr_info("(stop)hid_dev_backup is not initialized yet");
>> +              return -1;
>> +      }
>> +
>> +      usbhid = hid_dev_backup->driver_data;
>> +
>> +      pr_info("sys_sis_HID_stop\n");
>> +
>> +      /* printk( KERN_INFO "hid_dev_backup->vendor,
>> +      * hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor,
>> +      * hid_dev_backup->product );*/
>> +
>> +      /*20110602, Yuger, fix bug: not contact usb cause kernel panic*/
>> +      if (!usbhid) {
>> +              pr_info("(stop)usbhid is not initialized yet");
>> +              return -1;
>> +      } else if (!usbhid->urbin) {
>> +              pr_info("(stop)usbhid->urbin is not initialized yet");
>> +              return -1;
>> +      } else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH) {
>> +              usb_fill_int_urb(backup_urb,
>> +                      usbhid->urbin->dev,
>> +                      usbhid->urbin->pipe,
>> +                      usbhid->urbin->transfer_buffer,
>> +                      usbhid->urbin->transfer_buffer_length,
>> +                      usbhid->urbin->complete,
>> +                      usbhid->urbin->context,
>> +                      usbhid->urbin->interval);
>> +              clear_bit(HID_STARTED, &usbhid->iofl);
>> +              set_bit(HID_DISCONNECTED, &usbhid->iofl);
>> +
>> +              usb_kill_urb(usbhid->urbin);
>> +              usb_free_urb(usbhid->urbin);
>> +              usbhid->urbin = NULL;
>> +              return 0;
>> +      }
>> +
>> +      pr_info("This is not a SiS device");
>> +      return -801;
>> +}
>> +
>> +static int sis_cdev_release(struct inode *inode, struct file *filp) {
>> +      /*20110505, Yuger, rebuild the urb which is at the same urb address,
>> +      * then re-submit it*/
>> +
>> +      int ret;
>> +      struct usbhid_device *usbhid;
>> +      unsigned long flags;
>> +
>> +      DBG_FW("%s: ", __func__);
>> +
>> +      if (!hid_dev_backup) {
>> +              pr_info("(stop)hid_dev_backup is not initialized yet");
>> +              return -1;
>> +      }
>> +
>> +      usbhid = hid_dev_backup->driver_data;
>> +
>> +      pr_info("sys_sis_HID_start");
>> +
>> +      if (!usbhid) {
>> +              pr_info("(start)usbhid is not initialized yet");
>> +              return -1;
>> +      }
>> +
>> +      if (!backup_urb) {
>> +              pr_info("(start)backup_urb is not initialized yet");
>> +              return -1;
>> +      }
>> +
>> +      clear_bit(HID_DISCONNECTED, &usbhid->iofl);
>> +      usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL);
>> +
>> +      if (!backup_urb->interval) {
>> +              pr_info("(start)backup_urb->interval does not exist");
>> +              return -1;
>> +      }
>> +
>> +      usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
>> +      backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
>> +      backup_urb->complete, backup_urb->context, backup_urb->interval);
>> +      usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
>> +      usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
>> +
>> +      set_bit(HID_STARTED, &usbhid->iofl);
>> +
>> +      /*method at hid_start_in*/
>> +      spin_lock_irqsave(&usbhid->lock, flags);
>> +      ret = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
>> +      spin_unlock_irqrestore(&usbhid->lock, flags);
>> +      /*yy*/
>> +
>> +      DBG_FW("ret = %d", ret);
>> +
>> +      return ret;
>> +}
>> +
>> +/*SiS 817 only*/
>> +static ssize_t sis_cdev_read(struct file *file, char __user *buf,
>> +                              size_t count, loff_t *ppos) {
>> +      int actual_length = 0;
>> +      u8 *rep_data = NULL;
>> +      u32 size, timeout;
>> +      long rep_ret = 0;
>> +      struct usb_interface *intf =
>> +                      to_usb_interface(hid_dev_backup->dev.parent);
>> +      struct usb_device *dev = interface_to_usbdev(intf);
>> +
>> +      DBG_FW("%s\n", __func__);
>> +
>> +      rep_data = kzalloc(count, GFP_KERNEL);
>> +      if (!rep_data)
>> +              return SIS_ERR_ALLOCATE_KERNEL_MEM;
>> +
>> +      if (copy_from_user(rep_data, (void *)buf, count)) {
>> +              pr_err("copy_to_user fail\n");
>> +              rep_ret = SIS_ERR_COPY_FROM_USER;
>> +              goto end;
>> +      }
>> +      size = be32_to_cpup((u32 *)&rep_data[64]);
>> +      timeout = be32_to_cpup((u32 *)&rep_data[68]);
>> +
>> +      rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
>> +              rep_data, size, &actual_length, timeout);
>> +
>> +      DBG_FW("%s: rep_data = ", __func__);
>> +      sis_dbg_dump_array(rep_data, 8);
>> +
>> +      if (rep_ret == 0) {
>> +              rep_ret = actual_length;
>> +              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
>> +                      pr_err("copy_to_user fail\n");
>> +                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
>> +                      goto end;
>> +              }
>> +      }
>> +      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
>> +end:
>> +      /*free allocated data*/
>> +      kfree(rep_data);
>> +      return rep_ret;
>> +}
>> +
>> +static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
>> +                      size_t count, loff_t *f_pos) {
>> +      int actual_length = 0;
>> +      u8 *rep_data = NULL;
>> +      long rep_ret = 0;
>> +      struct usb_interface *intf =
>> +                      to_usb_interface(hid_dev_backup->dev.parent);
>> +      struct usb_device *dev = interface_to_usbdev(intf);
>> +      struct usbhid_device *usbhid = hid_dev_backup->driver_data;
>> +      u32 size, timeout;
>> +
>> +      rep_data = kzalloc(count, GFP_KERNEL);
>> +      if (!rep_data)
>> +              return SIS_ERR_ALLOCATE_KERNEL_MEM;
>> +
>> +      if (copy_from_user(rep_data, (void *)buf, count)) {
>> +              pr_err("copy_to_user fail\n");
>> +              rep_ret = SIS_ERR_COPY_FROM_USER;
>> +              goto end;
>> +      }
>> +
>> +      size = be32_to_cpup((u32 *)&rep_data[64]);
>> +      timeout = be32_to_cpup((u32 *)&rep_data[68]);
>> +
>> +      rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
>> +              rep_data, size, &actual_length, timeout);
>> +
>> +      DBG_FW("%s: rep_data = ", __func__);
>> +      sis_dbg_dump_array(rep_data, size);
>> +
>> +      if (rep_ret == 0) {
>> +              rep_ret = actual_length;
>> +              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
>> +                      pr_err("copy_to_user fail\n");
>> +                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
>> +                      goto end;
>> +              }
>> +      }
>> +      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
>> +      DBG_FW("End of sys_sis_HID_IO\n");
>> +end:
>> +      /*free allocated data*/
>> +      kfree(rep_data);
>> +      return rep_ret;
>> +}
>> +
>> +
>> +/*for ioctl*/
>> +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,
>> +};
>> +
>> +/*for ioctl*/
>> +static int sis_setup_chardev(struct hid_device *hdev) {
>> +      dev_t dev = MKDEV(sis_char_major, 0);
>> +      int ret = 0;
>> +      struct device *class_dev = NULL;
>> +      u8 *name = (hdev->product == USB_DEVICE_ID_SISF817_TOUCH) ?
>> +                      SISF817_DEVICE_NAME : SIS817_DEVICE_NAME;
>> +
>> +      dev_info(&hdev->dev, "sis_setup_chardev.\n");
>> +
>> +      backup_urb = usb_alloc_urb(0, GFP_KERNEL);    /*0721test*/
>> +      if (!backup_urb) {
>> +              dev_err(&hdev->dev, "cannot allocate backup_urb\n");
>> +              return -ENOMEM;
>> +      }
>> +      hid_dev_backup = hdev;
>> +      /*dynamic allocate driver handle*/
>> +      ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, name);
>> +      if (ret)
>> +              goto err1;
>> +
>> +      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 err2;
>> +
>> +      dev_info(&hdev->dev, "%s driver(major %d) installed.\n",
>> +                                      name, sis_char_major);
>> +
>> +      /*register class*/
>> +      sis_char_class = class_create(THIS_MODULE, name);
>> +      if (IS_ERR(sis_char_class)) {
>> +              ret = PTR_ERR(sis_char_class);
>> +              goto err3;
>> +      }
>> +
>> +      class_dev = device_create(sis_char_class, NULL, dev, NULL, name);
>> +      if (IS_ERR(class_dev)) {
>> +              ret = PTR_ERR(class_dev);
>> +              goto err4;
>> +      }
>> +
>> +      return 0;
>> +err4:
>> +      class_destroy(sis_char_class);
>> +      sis_char_class = NULL;
>> +err3:
>> +      cdev_del(&sis_char_cdev);
>> +      memset(&sis_char_cdev, 0, sizeof(struct cdev));
>> +err2:
>> +      sis_char_major = 0;
>> +      unregister_chrdev_region(dev, sis_char_devs_count);
>> +err1:
>> +      usb_kill_urb(backup_urb);
>> +      usb_free_urb(backup_urb);
>> +      backup_urb = NULL;
>> +      hid_dev_backup = NULL;
>> +      return ret;
>> +}
>> +
>> +/*for ioctl*/
>> +static void sis_deinit_chardev(void)
>> +{
>> +      dev_t dev = MKDEV(sis_char_major, 0);
>> +
>> +      if (hid_dev_backup) {
>> +              dev_info(&hid_dev_backup->dev, "sis_remove\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);
>> +              usb_kill_urb(backup_urb);
>> +              usb_free_urb(backup_urb);
>> +              backup_urb = NULL;
>> +              hid_dev_backup = NULL;
>> +      }
>> +}
>> diff --git a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
>> index 4477eb7..b534321 100644
>> --- a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
>> +++ b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
>> @@ -97,6 +97,7 @@ static const struct hid_blacklist {
>>       { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
>>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
>>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
>> +      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SISF817_TOUCH,
>> + HID_QUIRK_NOGET },
>>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
>>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
>>       { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
>
>
> --
> 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] 13+ messages in thread

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

On Thu, 2015-02-12 at 15:24 +0800, 曾婷葳 (tammy_tseng) wrote:

> Sorry. Re-send the code diff again.
> Here is the hid touch driver for sis touch controller.
> Thanks.

This driver does very strange things. It looks like you are
simulating a disconnect() to the usbhid driver currently driving
the device. This is unacceptable. Please add the device to the
generic blacklist and implement a clean open/close.

	Regards
		Oliver

> Tammy
> -----
> 
> linux-3.18.5/drivers/hid/Kconfig             |  14 ++
> linux-3.18.5/drivers/hid/hid-ids.h           |   1 +
> linux-3.18.5/drivers/hid/hid-multitouch.c    |  16 ++
> linux-3.18.5/drivers/hid/hid-sis_ctrl.c      | 360 +++++++++++++++++++++++++++
> linux-3.18.5/drivers/hid/usbhid/hid-quirks.c |   1 +
> 5 files changed, 392 insertions(+)
> 
> 
> -----
> diff --git a/linux-3.18.5/drivers/hid/Kconfig b/linux-3.18.5/drivers/hid/Kconfig
> index f42df4d..2235cfe 100644
> --- a/linux-3.18.5/drivers/hid/Kconfig
> +++ b/linux-3.18.5/drivers/hid/Kconfig
> @@ -496,6 +496,20 @@ config HID_MULTITOUCH
>         To compile this driver as a module, choose M here: the
>         module will be called hid-multitouch.
> 
> +config HID_SIS_CTRL
> +      bool "SiS Touch Device Controller"
> +      depends on HID_MULTITOUCH
> +      ---help---
> +      Support for SiS Touch devices update FW.
> +
> +config DEBUG_HID_SIS_UPDATE_FW
> +      bool "SiS Touch device debug message(update firmware)"
> +      depends on HID_SIS_CTRL
> +      default n
> +      ---help---
> +        Say Y here if you want to enable debug message(update firmware) for SiS Touch 
> +          devices. Must enable config HID_SIS_UPDATE_FW first.
> +
> config HID_NTRIG
>       tristate "N-Trig touch screen"
>       depends on USB_HID
> diff --git a/linux-3.18.5/drivers/hid/hid-ids.h b/linux-3.18.5/drivers/hid/hid-ids.h
> index 0e28190..b9ca441 100644
> --- a/linux-3.18.5/drivers/hid/hid-ids.h
> +++ b/linux-3.18.5/drivers/hid/hid-ids.h
> @@ -809,6 +809,7 @@
> #define USB_VENDOR_ID_SIS_TOUCH                0x0457
> #define USB_DEVICE_ID_SIS9200_TOUCH  0x9200
> #define USB_DEVICE_ID_SIS817_TOUCH    0x0817
> +#define USB_DEVICE_ID_SISF817_TOUCH  0xF817
> #define USB_DEVICE_ID_SIS_TS          0x1013
> #define USB_DEVICE_ID_SIS1030_TOUCH  0x1030
> 
> diff --git a/linux-3.18.5/drivers/hid/hid-multitouch.c b/linux-3.18.5/drivers/hid/hid-multitouch.c
> index 51e25b9..11d67bc 100644
> --- a/linux-3.18.5/drivers/hid/hid-multitouch.c
> +++ b/linux-3.18.5/drivers/hid/hid-multitouch.c
> @@ -54,6 +54,10 @@ MODULE_LICENSE("GPL");
> 
>  #include "hid-ids.h"
> 
> +#ifdef CONFIG_HID_SIS_CTRL
> +#include "hid-sis_ctrl.c"
> +#endif
> +
> /* quirks to control the device */
> #define MT_QUIRK_NOT_SEEN_MEANS_UP      (1 << 0)
> #define MT_QUIRK_SLOT_IS_CONTACTID   (1 << 1)
> @@ -951,6 +955,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
>               }
>       }
> 
> +#ifdef CONFIG_HID_SIS_CTRL
> +      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
> +              ret = sis_setup_chardev(hdev);
> +              if (ret)
> +                      dev_err(&hdev->dev, "sis_setup_chardev fail\n");
> +      }
> +#endif
> +
>       /* This allows the driver to correctly support devices
>        * that emit events over several HID messages.
>        */
> @@ -1043,6 +1055,10 @@ static void mt_remove(struct hid_device *hdev) {
>       sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
>       hid_hw_stop(hdev);
> +#ifdef CONFIG_HID_SIS_CTRL
> +      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
> +              sis_deinit_chardev();
> +#endif
> }
> 
>  /*
> diff --git a/linux-3.18.5/drivers/hid/hid-sis_ctrl.c b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
> new file mode 100644
> index 0000000..3a7b3df
> --- /dev/null
> +++ b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
> @@ -0,0 +1,360 @@
> +/*
> + *  Character device driver for SIS multitouch panels control
> + *
> + *  Copyright (c) 2009 SIS, Ltd.
> + *
> + */
> +
> +/*
> + * This program is free software; you can redistribute it and/or modify 
> +it
> + * under the terms of the GNU General Public License as published by 
> +the Free
> + * Software Foundation; either version 2 of the License, or (at your 
> +option)
> + * any later version.
> + */
> +
> +#include <linux/hid.h>
> +#include <linux/module.h>
> +#include <linux/usb.h>
> +#include "usbhid/usbhid.h"
> +#include <linux/init.h>
> +
> +/*update FW*/
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +/*#include <asm/uaccess.h>*/   /*copy_from_user() & copy_to_user()*/
> +#include <linux/uaccess.h>
> +
> +#include "hid-ids.h"
> +
> +#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
> +#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
> +
> +#define CTRL 0
> +#define ENDP_01 1
> +#define ENDP_02 2
> +#define DIR_IN 0x1
> +
> +#define SIS_ERR_ALLOCATE_KERNEL_MEM        -12 /* Allocate memory fail */
> +#define SIS_ERR_COPY_FROM_USER          -14 /* Copy data from user fail */
> +#define SIS_ERR_COPY_FROM_KERNEL      -19 /* Copy data from kernel fail */

You _must_ use the symbolic names. You cannot use numbers.

> +
> +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;
> +
> +static struct hid_device *hid_dev_backup;        /*backup address*/
> +static struct urb *backup_urb;
> +
> +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
> +      #define DBG_FW(fmt, arg...) printk(fmt, ##arg)
> +      static void sis_dbg_dump_array(u8 *ptr, u32 size)
> +      {
> +              u32 i;
> +
> +              for (i = 0; i < size; i++) {
> +                      DBG_FW("%02X ", ptr[i]);
> +                      if (((i+1)&0xF) == 0)
> +                              DBG_FW("\n");
> +              }
> +              if (size & 0xF)
> +                      DBG_FW("\n");
> +      }
> +#else
> +      #define DBG_FW(...)
> +      #define sis_dbg_dump_array(...)
> +#endif   /*CONFIG_DEBUG_HID_SIS_UPDATE_FW*/
> +
> +/*20120306 Yuger ioctl for tool*/
> +static int sis_cdev_open(struct inode *inode, struct file *filp) {
> +      struct usbhid_device *usbhid;
> +
> +      DBG_FW("%s\n" , __func__);
> +      /*20110511, Yuger, kill current urb by method of usbhid_stop*/
> +      if (!hid_dev_backup) {

Why is this needed?

> +              pr_info("(stop)hid_dev_backup is not initialized yet");
> +              return -1;
> +      }
> +
> +      usbhid = hid_dev_backup->driver_data;
> +
> +      pr_info("sys_sis_HID_stop\n");
> +
> +      /* printk( KERN_INFO "hid_dev_backup->vendor,
> +      * hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor,
> +      * hid_dev_backup->product );*/
> +
> +      /*20110602, Yuger, fix bug: not contact usb cause kernel panic*/
> +      if (!usbhid) {
> +              pr_info("(stop)usbhid is not initialized yet");
> +              return -1;
> +      } else if (!usbhid->urbin) {
> +              pr_info("(stop)usbhid->urbin is not initialized yet");
> +              return -1;
> +      } else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH) {
> +              usb_fill_int_urb(backup_urb,
> +                      usbhid->urbin->dev,
> +                      usbhid->urbin->pipe,
> +                      usbhid->urbin->transfer_buffer,
> +                      usbhid->urbin->transfer_buffer_length,
> +                      usbhid->urbin->complete,
> +                      usbhid->urbin->context,
> +                      usbhid->urbin->interval);
> +              clear_bit(HID_STARTED, &usbhid->iofl);
> +              set_bit(HID_DISCONNECTED, &usbhid->iofl);
> +
> +              usb_kill_urb(usbhid->urbin);
> +              usb_free_urb(usbhid->urbin);
> +              usbhid->urbin = NULL;
> +              return 0;
> +      }
> +
> +      pr_info("This is not a SiS device");
> +      return -801;
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp) {
> +      /*20110505, Yuger, rebuild the urb which is at the same urb address,
> +      * then re-submit it*/
> +
> +      int ret;
> +      struct usbhid_device *usbhid;
> +      unsigned long flags;
> +
> +      DBG_FW("%s: ", __func__);
> +
> +      if (!hid_dev_backup) {
> +              pr_info("(stop)hid_dev_backup is not initialized yet");
> +              return -1;
> +      }
> +
> +      usbhid = hid_dev_backup->driver_data;
> +
> +      pr_info("sys_sis_HID_start");
> +
> +      if (!usbhid) {
> +              pr_info("(start)usbhid is not initialized yet");
> +              return -1;
> +      }
> +
> +      if (!backup_urb) {
> +              pr_info("(start)backup_urb is not initialized yet");
> +              return -1;
> +      }
> +
> +      clear_bit(HID_DISCONNECTED, &usbhid->iofl);
> +      usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL);
> +
> +      if (!backup_urb->interval) {
> +              pr_info("(start)backup_urb->interval does not exist");
> +              return -1;
> +      }
> +
> +      usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
> +      backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
> +      backup_urb->complete, backup_urb->context, backup_urb->interval);
> +      usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
> +      usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> +
> +      set_bit(HID_STARTED, &usbhid->iofl);
> +
> +      /*method at hid_start_in*/
> +      spin_lock_irqsave(&usbhid->lock, flags);
> +      ret = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
> +      spin_unlock_irqrestore(&usbhid->lock, flags);
> +      /*yy*/
> +
> +      DBG_FW("ret = %d", ret);
> +
> +      return ret;
> +}
> +
> +/*SiS 817 only*/
> +static ssize_t sis_cdev_read(struct file *file, char __user *buf,
> +                              size_t count, loff_t *ppos) {
> +      int actual_length = 0;
> +      u8 *rep_data = NULL;
> +      u32 size, timeout;
> +      long rep_ret = 0;
> +      struct usb_interface *intf =
> +                      to_usb_interface(hid_dev_backup->dev.parent);
> +      struct usb_device *dev = interface_to_usbdev(intf);
> +
> +      DBG_FW("%s\n", __func__);
> +
> +      rep_data = kzalloc(count, GFP_KERNEL);
> +      if (!rep_data)
> +              return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +      if (copy_from_user(rep_data, (void *)buf, count)) {
> +              pr_err("copy_to_user fail\n");
> +              rep_ret = SIS_ERR_COPY_FROM_USER;
> +              goto end;
> +      }
> +      size = be32_to_cpup((u32 *)&rep_data[64]);
> +      timeout = be32_to_cpup((u32 *)&rep_data[68]);
> +
> +      rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
> +              rep_data, size, &actual_length, timeout);
> +
> +      DBG_FW("%s: rep_data = ", __func__);
> +      sis_dbg_dump_array(rep_data, 8);
> +
> +      if (rep_ret == 0) {
> +              rep_ret = actual_length;
> +              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
> +                      pr_err("copy_to_user fail\n");
> +                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
> +                      goto end;
> +              }
> +      }
> +      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
> +end:
> +      /*free allocated data*/
> +      kfree(rep_data);
> +      return rep_ret;
> +}
> +
> +static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
> +                      size_t count, loff_t *f_pos) {
> +      int actual_length = 0;
> +      u8 *rep_data = NULL;
> +      long rep_ret = 0;
> +      struct usb_interface *intf =
> +                      to_usb_interface(hid_dev_backup->dev.parent);
> +      struct usb_device *dev = interface_to_usbdev(intf);
> +      struct usbhid_device *usbhid = hid_dev_backup->driver_data;
> +      u32 size, timeout;
> +
> +      rep_data = kzalloc(count, GFP_KERNEL);
> +      if (!rep_data)
> +              return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +      if (copy_from_user(rep_data, (void *)buf, count)) {
> +              pr_err("copy_to_user fail\n");
> +              rep_ret = SIS_ERR_COPY_FROM_USER;
> +              goto end;
> +      }
> +
> +      size = be32_to_cpup((u32 *)&rep_data[64]);
> +      timeout = be32_to_cpup((u32 *)&rep_data[68]);
> +
> +      rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
> +              rep_data, size, &actual_length, timeout);
> +
> +      DBG_FW("%s: rep_data = ", __func__);
> +      sis_dbg_dump_array(rep_data, size);
> +
> +      if (rep_ret == 0) {
> +              rep_ret = actual_length;
> +              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
> +                      pr_err("copy_to_user fail\n");
> +                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
> +                      goto end;
> +              }
> +      }
> +      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
> +      DBG_FW("End of sys_sis_HID_IO\n");
> +end:
> +      /*free allocated data*/
> +      kfree(rep_data);
> +      return rep_ret;
> +}
> +
> +
> +/*for ioctl*/
> +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,
> +};
> +
> +/*for ioctl*/
> +static int sis_setup_chardev(struct hid_device *hdev) {
> +      dev_t dev = MKDEV(sis_char_major, 0);
> +      int ret = 0;
> +      struct device *class_dev = NULL;
> +      u8 *name = (hdev->product == USB_DEVICE_ID_SISF817_TOUCH) ?
> +                      SISF817_DEVICE_NAME : SIS817_DEVICE_NAME;
> +
> +      dev_info(&hdev->dev, "sis_setup_chardev.\n");
> +
> +      backup_urb = usb_alloc_urb(0, GFP_KERNEL);    /*0721test*/
> +      if (!backup_urb) {
> +              dev_err(&hdev->dev, "cannot allocate backup_urb\n");
> +              return -ENOMEM;
> +      }
> +      hid_dev_backup = hdev;
> +      /*dynamic allocate driver handle*/
> +      ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, name);
> +      if (ret)
> +              goto err1;
> +
> +      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 err2;
> +
> +      dev_info(&hdev->dev, "%s driver(major %d) installed.\n",
> +                                      name, sis_char_major);
> +
> +      /*register class*/
> +      sis_char_class = class_create(THIS_MODULE, name);
> +      if (IS_ERR(sis_char_class)) {
> +              ret = PTR_ERR(sis_char_class);
> +              goto err3;
> +      }
> +
> +      class_dev = device_create(sis_char_class, NULL, dev, NULL, name);
> +      if (IS_ERR(class_dev)) {
> +              ret = PTR_ERR(class_dev);
> +              goto err4;
> +      }
> +
> +      return 0;
> +err4:
> +      class_destroy(sis_char_class);
> +      sis_char_class = NULL;
> +err3:
> +      cdev_del(&sis_char_cdev);
> +      memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +err2:
> +      sis_char_major = 0;
> +      unregister_chrdev_region(dev, sis_char_devs_count);
> +err1:
> +      usb_kill_urb(backup_urb);
> +      usb_free_urb(backup_urb);
> +      backup_urb = NULL;
> +      hid_dev_backup = NULL;
> +      return ret;
> +}
> +
> +/*for ioctl*/
> +static void sis_deinit_chardev(void)
> +{
> +      dev_t dev = MKDEV(sis_char_major, 0);
> +
> +      if (hid_dev_backup) {
> +              dev_info(&hid_dev_backup->dev, "sis_remove\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);
> +              usb_kill_urb(backup_urb);
> +              usb_free_urb(backup_urb);
> +              backup_urb = NULL;
> +              hid_dev_backup = NULL;
> +      }
> +}
> diff --git a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
> index 4477eb7..b534321 100644
> --- a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
> +++ b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
> @@ -97,6 +97,7 @@ static const struct hid_blacklist {
>       { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
> +      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SISF817_TOUCH, 
> + HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },


-- 
Oliver Neukum <oneukum@suse.de>


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

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

On Thu, 2015-02-12 at 15:24 +0800, 曾婷葳 (tammy_tseng) wrote:

> Sorry. Re-send the code diff again.
> Here is the hid touch driver for sis touch controller.
> Thanks.

This driver does very strange things. It looks like you are
simulating a disconnect() to the usbhid driver currently driving
the device. This is unacceptable. Please add the device to the
generic blacklist and implement a clean open/close.

	Regards
		Oliver

> Tammy
> -----
> 
> linux-3.18.5/drivers/hid/Kconfig             |  14 ++
> linux-3.18.5/drivers/hid/hid-ids.h           |   1 +
> linux-3.18.5/drivers/hid/hid-multitouch.c    |  16 ++
> linux-3.18.5/drivers/hid/hid-sis_ctrl.c      | 360 +++++++++++++++++++++++++++
> linux-3.18.5/drivers/hid/usbhid/hid-quirks.c |   1 +
> 5 files changed, 392 insertions(+)
> 
> 
> -----
> diff --git a/linux-3.18.5/drivers/hid/Kconfig b/linux-3.18.5/drivers/hid/Kconfig
> index f42df4d..2235cfe 100644
> --- a/linux-3.18.5/drivers/hid/Kconfig
> +++ b/linux-3.18.5/drivers/hid/Kconfig
> @@ -496,6 +496,20 @@ config HID_MULTITOUCH
>         To compile this driver as a module, choose M here: the
>         module will be called hid-multitouch.
> 
> +config HID_SIS_CTRL
> +      bool "SiS Touch Device Controller"
> +      depends on HID_MULTITOUCH
> +      ---help---
> +      Support for SiS Touch devices update FW.
> +
> +config DEBUG_HID_SIS_UPDATE_FW
> +      bool "SiS Touch device debug message(update firmware)"
> +      depends on HID_SIS_CTRL
> +      default n
> +      ---help---
> +        Say Y here if you want to enable debug message(update firmware) for SiS Touch 
> +          devices. Must enable config HID_SIS_UPDATE_FW first.
> +
> config HID_NTRIG
>       tristate "N-Trig touch screen"
>       depends on USB_HID
> diff --git a/linux-3.18.5/drivers/hid/hid-ids.h b/linux-3.18.5/drivers/hid/hid-ids.h
> index 0e28190..b9ca441 100644
> --- a/linux-3.18.5/drivers/hid/hid-ids.h
> +++ b/linux-3.18.5/drivers/hid/hid-ids.h
> @@ -809,6 +809,7 @@
> #define USB_VENDOR_ID_SIS_TOUCH                0x0457
> #define USB_DEVICE_ID_SIS9200_TOUCH  0x9200
> #define USB_DEVICE_ID_SIS817_TOUCH    0x0817
> +#define USB_DEVICE_ID_SISF817_TOUCH  0xF817
> #define USB_DEVICE_ID_SIS_TS          0x1013
> #define USB_DEVICE_ID_SIS1030_TOUCH  0x1030
> 
> diff --git a/linux-3.18.5/drivers/hid/hid-multitouch.c b/linux-3.18.5/drivers/hid/hid-multitouch.c
> index 51e25b9..11d67bc 100644
> --- a/linux-3.18.5/drivers/hid/hid-multitouch.c
> +++ b/linux-3.18.5/drivers/hid/hid-multitouch.c
> @@ -54,6 +54,10 @@ MODULE_LICENSE("GPL");
> 
>  #include "hid-ids.h"
> 
> +#ifdef CONFIG_HID_SIS_CTRL
> +#include "hid-sis_ctrl.c"
> +#endif
> +
> /* quirks to control the device */
> #define MT_QUIRK_NOT_SEEN_MEANS_UP      (1 << 0)
> #define MT_QUIRK_SLOT_IS_CONTACTID   (1 << 1)
> @@ -951,6 +955,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
>               }
>       }
> 
> +#ifdef CONFIG_HID_SIS_CTRL
> +      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
> +              ret = sis_setup_chardev(hdev);
> +              if (ret)
> +                      dev_err(&hdev->dev, "sis_setup_chardev fail\n");
> +      }
> +#endif
> +
>       /* This allows the driver to correctly support devices
>        * that emit events over several HID messages.
>        */
> @@ -1043,6 +1055,10 @@ static void mt_remove(struct hid_device *hdev) {
>       sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
>       hid_hw_stop(hdev);
> +#ifdef CONFIG_HID_SIS_CTRL
> +      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
> +              sis_deinit_chardev();
> +#endif
> }
> 
>  /*
> diff --git a/linux-3.18.5/drivers/hid/hid-sis_ctrl.c b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
> new file mode 100644
> index 0000000..3a7b3df
> --- /dev/null
> +++ b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
> @@ -0,0 +1,360 @@
> +/*
> + *  Character device driver for SIS multitouch panels control
> + *
> + *  Copyright (c) 2009 SIS, Ltd.
> + *
> + */
> +
> +/*
> + * This program is free software; you can redistribute it and/or modify 
> +it
> + * under the terms of the GNU General Public License as published by 
> +the Free
> + * Software Foundation; either version 2 of the License, or (at your 
> +option)
> + * any later version.
> + */
> +
> +#include <linux/hid.h>
> +#include <linux/module.h>
> +#include <linux/usb.h>
> +#include "usbhid/usbhid.h"
> +#include <linux/init.h>
> +
> +/*update FW*/
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +/*#include <asm/uaccess.h>*/   /*copy_from_user() & copy_to_user()*/
> +#include <linux/uaccess.h>
> +
> +#include "hid-ids.h"
> +
> +#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
> +#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
> +
> +#define CTRL 0
> +#define ENDP_01 1
> +#define ENDP_02 2
> +#define DIR_IN 0x1
> +
> +#define SIS_ERR_ALLOCATE_KERNEL_MEM        -12 /* Allocate memory fail */
> +#define SIS_ERR_COPY_FROM_USER          -14 /* Copy data from user fail */
> +#define SIS_ERR_COPY_FROM_KERNEL      -19 /* Copy data from kernel fail */

You _must_ use the symbolic names. You cannot use numbers.

> +
> +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;
> +
> +static struct hid_device *hid_dev_backup;        /*backup address*/
> +static struct urb *backup_urb;
> +
> +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
> +      #define DBG_FW(fmt, arg...) printk(fmt, ##arg)
> +      static void sis_dbg_dump_array(u8 *ptr, u32 size)
> +      {
> +              u32 i;
> +
> +              for (i = 0; i < size; i++) {
> +                      DBG_FW("%02X ", ptr[i]);
> +                      if (((i+1)&0xF) == 0)
> +                              DBG_FW("\n");
> +              }
> +              if (size & 0xF)
> +                      DBG_FW("\n");
> +      }
> +#else
> +      #define DBG_FW(...)
> +      #define sis_dbg_dump_array(...)
> +#endif   /*CONFIG_DEBUG_HID_SIS_UPDATE_FW*/
> +
> +/*20120306 Yuger ioctl for tool*/
> +static int sis_cdev_open(struct inode *inode, struct file *filp) {
> +      struct usbhid_device *usbhid;
> +
> +      DBG_FW("%s\n" , __func__);
> +      /*20110511, Yuger, kill current urb by method of usbhid_stop*/
> +      if (!hid_dev_backup) {

Why is this needed?

> +              pr_info("(stop)hid_dev_backup is not initialized yet");
> +              return -1;
> +      }
> +
> +      usbhid = hid_dev_backup->driver_data;
> +
> +      pr_info("sys_sis_HID_stop\n");
> +
> +      /* printk( KERN_INFO "hid_dev_backup->vendor,
> +      * hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor,
> +      * hid_dev_backup->product );*/
> +
> +      /*20110602, Yuger, fix bug: not contact usb cause kernel panic*/
> +      if (!usbhid) {
> +              pr_info("(stop)usbhid is not initialized yet");
> +              return -1;
> +      } else if (!usbhid->urbin) {
> +              pr_info("(stop)usbhid->urbin is not initialized yet");
> +              return -1;
> +      } else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH) {
> +              usb_fill_int_urb(backup_urb,
> +                      usbhid->urbin->dev,
> +                      usbhid->urbin->pipe,
> +                      usbhid->urbin->transfer_buffer,
> +                      usbhid->urbin->transfer_buffer_length,
> +                      usbhid->urbin->complete,
> +                      usbhid->urbin->context,
> +                      usbhid->urbin->interval);
> +              clear_bit(HID_STARTED, &usbhid->iofl);
> +              set_bit(HID_DISCONNECTED, &usbhid->iofl);
> +
> +              usb_kill_urb(usbhid->urbin);
> +              usb_free_urb(usbhid->urbin);
> +              usbhid->urbin = NULL;
> +              return 0;
> +      }
> +
> +      pr_info("This is not a SiS device");
> +      return -801;
> +}
> +
> +static int sis_cdev_release(struct inode *inode, struct file *filp) {
> +      /*20110505, Yuger, rebuild the urb which is at the same urb address,
> +      * then re-submit it*/
> +
> +      int ret;
> +      struct usbhid_device *usbhid;
> +      unsigned long flags;
> +
> +      DBG_FW("%s: ", __func__);
> +
> +      if (!hid_dev_backup) {
> +              pr_info("(stop)hid_dev_backup is not initialized yet");
> +              return -1;
> +      }
> +
> +      usbhid = hid_dev_backup->driver_data;
> +
> +      pr_info("sys_sis_HID_start");
> +
> +      if (!usbhid) {
> +              pr_info("(start)usbhid is not initialized yet");
> +              return -1;
> +      }
> +
> +      if (!backup_urb) {
> +              pr_info("(start)backup_urb is not initialized yet");
> +              return -1;
> +      }
> +
> +      clear_bit(HID_DISCONNECTED, &usbhid->iofl);
> +      usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL);
> +
> +      if (!backup_urb->interval) {
> +              pr_info("(start)backup_urb->interval does not exist");
> +              return -1;
> +      }
> +
> +      usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
> +      backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
> +      backup_urb->complete, backup_urb->context, backup_urb->interval);
> +      usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
> +      usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> +
> +      set_bit(HID_STARTED, &usbhid->iofl);
> +
> +      /*method at hid_start_in*/
> +      spin_lock_irqsave(&usbhid->lock, flags);
> +      ret = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
> +      spin_unlock_irqrestore(&usbhid->lock, flags);
> +      /*yy*/
> +
> +      DBG_FW("ret = %d", ret);
> +
> +      return ret;
> +}
> +
> +/*SiS 817 only*/
> +static ssize_t sis_cdev_read(struct file *file, char __user *buf,
> +                              size_t count, loff_t *ppos) {
> +      int actual_length = 0;
> +      u8 *rep_data = NULL;
> +      u32 size, timeout;
> +      long rep_ret = 0;
> +      struct usb_interface *intf =
> +                      to_usb_interface(hid_dev_backup->dev.parent);
> +      struct usb_device *dev = interface_to_usbdev(intf);
> +
> +      DBG_FW("%s\n", __func__);
> +
> +      rep_data = kzalloc(count, GFP_KERNEL);
> +      if (!rep_data)
> +              return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +      if (copy_from_user(rep_data, (void *)buf, count)) {
> +              pr_err("copy_to_user fail\n");
> +              rep_ret = SIS_ERR_COPY_FROM_USER;
> +              goto end;
> +      }
> +      size = be32_to_cpup((u32 *)&rep_data[64]);
> +      timeout = be32_to_cpup((u32 *)&rep_data[68]);
> +
> +      rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
> +              rep_data, size, &actual_length, timeout);
> +
> +      DBG_FW("%s: rep_data = ", __func__);
> +      sis_dbg_dump_array(rep_data, 8);
> +
> +      if (rep_ret == 0) {
> +              rep_ret = actual_length;
> +              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
> +                      pr_err("copy_to_user fail\n");
> +                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
> +                      goto end;
> +              }
> +      }
> +      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
> +end:
> +      /*free allocated data*/
> +      kfree(rep_data);
> +      return rep_ret;
> +}
> +
> +static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
> +                      size_t count, loff_t *f_pos) {
> +      int actual_length = 0;
> +      u8 *rep_data = NULL;
> +      long rep_ret = 0;
> +      struct usb_interface *intf =
> +                      to_usb_interface(hid_dev_backup->dev.parent);
> +      struct usb_device *dev = interface_to_usbdev(intf);
> +      struct usbhid_device *usbhid = hid_dev_backup->driver_data;
> +      u32 size, timeout;
> +
> +      rep_data = kzalloc(count, GFP_KERNEL);
> +      if (!rep_data)
> +              return SIS_ERR_ALLOCATE_KERNEL_MEM;
> +
> +      if (copy_from_user(rep_data, (void *)buf, count)) {
> +              pr_err("copy_to_user fail\n");
> +              rep_ret = SIS_ERR_COPY_FROM_USER;
> +              goto end;
> +      }
> +
> +      size = be32_to_cpup((u32 *)&rep_data[64]);
> +      timeout = be32_to_cpup((u32 *)&rep_data[68]);
> +
> +      rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
> +              rep_data, size, &actual_length, timeout);
> +
> +      DBG_FW("%s: rep_data = ", __func__);
> +      sis_dbg_dump_array(rep_data, size);
> +
> +      if (rep_ret == 0) {
> +              rep_ret = actual_length;
> +              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
> +                      pr_err("copy_to_user fail\n");
> +                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
> +                      goto end;
> +              }
> +      }
> +      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
> +      DBG_FW("End of sys_sis_HID_IO\n");
> +end:
> +      /*free allocated data*/
> +      kfree(rep_data);
> +      return rep_ret;
> +}
> +
> +
> +/*for ioctl*/
> +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,
> +};
> +
> +/*for ioctl*/
> +static int sis_setup_chardev(struct hid_device *hdev) {
> +      dev_t dev = MKDEV(sis_char_major, 0);
> +      int ret = 0;
> +      struct device *class_dev = NULL;
> +      u8 *name = (hdev->product == USB_DEVICE_ID_SISF817_TOUCH) ?
> +                      SISF817_DEVICE_NAME : SIS817_DEVICE_NAME;
> +
> +      dev_info(&hdev->dev, "sis_setup_chardev.\n");
> +
> +      backup_urb = usb_alloc_urb(0, GFP_KERNEL);    /*0721test*/
> +      if (!backup_urb) {
> +              dev_err(&hdev->dev, "cannot allocate backup_urb\n");
> +              return -ENOMEM;
> +      }
> +      hid_dev_backup = hdev;
> +      /*dynamic allocate driver handle*/
> +      ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, name);
> +      if (ret)
> +              goto err1;
> +
> +      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 err2;
> +
> +      dev_info(&hdev->dev, "%s driver(major %d) installed.\n",
> +                                      name, sis_char_major);
> +
> +      /*register class*/
> +      sis_char_class = class_create(THIS_MODULE, name);
> +      if (IS_ERR(sis_char_class)) {
> +              ret = PTR_ERR(sis_char_class);
> +              goto err3;
> +      }
> +
> +      class_dev = device_create(sis_char_class, NULL, dev, NULL, name);
> +      if (IS_ERR(class_dev)) {
> +              ret = PTR_ERR(class_dev);
> +              goto err4;
> +      }
> +
> +      return 0;
> +err4:
> +      class_destroy(sis_char_class);
> +      sis_char_class = NULL;
> +err3:
> +      cdev_del(&sis_char_cdev);
> +      memset(&sis_char_cdev, 0, sizeof(struct cdev));
> +err2:
> +      sis_char_major = 0;
> +      unregister_chrdev_region(dev, sis_char_devs_count);
> +err1:
> +      usb_kill_urb(backup_urb);
> +      usb_free_urb(backup_urb);
> +      backup_urb = NULL;
> +      hid_dev_backup = NULL;
> +      return ret;
> +}
> +
> +/*for ioctl*/
> +static void sis_deinit_chardev(void)
> +{
> +      dev_t dev = MKDEV(sis_char_major, 0);
> +
> +      if (hid_dev_backup) {
> +              dev_info(&hid_dev_backup->dev, "sis_remove\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);
> +              usb_kill_urb(backup_urb);
> +              usb_free_urb(backup_urb);
> +              backup_urb = NULL;
> +              hid_dev_backup = NULL;
> +      }
> +}
> diff --git a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
> index 4477eb7..b534321 100644
> --- a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
> +++ b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
> @@ -97,6 +97,7 @@ static const struct hid_blacklist {
>       { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
> +      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SISF817_TOUCH, 
> + HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
>       { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
>       { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },


-- 
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] 13+ messages in thread

* Re: [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-02-12  7:24 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 13+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-02-12  7:24 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: 16484 bytes --]

Hi, Dmitry

> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Thursday, February 12, 2015 3:04 PM
> To: 曾婷葳 (tammy_tseng)
> Cc: Oliver Neukum; lkml; linux-input@vger.kernel.org; 
> tammy0524@gmail.com
> Subject: Re: [PATCH 2/2] INPUT/HID: add touch support for SiS touch 
> driver
> 
> Hi Tammy,
> 
> On Thu, Feb 12, 2015 at 02:07:26PM +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 sent as HTML so mailing lists dropped it.
> 
> Thanks.
> 
> --
> Dmitry


Sorry. Re-send the code diff again.
Here is the hid touch driver for sis touch controller.
Thanks.

Tammy
-----

linux-3.18.5/drivers/hid/Kconfig             |  14 ++
linux-3.18.5/drivers/hid/hid-ids.h           |   1 +
linux-3.18.5/drivers/hid/hid-multitouch.c    |  16 ++
linux-3.18.5/drivers/hid/hid-sis_ctrl.c      | 360 +++++++++++++++++++++++++++
linux-3.18.5/drivers/hid/usbhid/hid-quirks.c |   1 +
5 files changed, 392 insertions(+)


-----
diff --git a/linux-3.18.5/drivers/hid/Kconfig b/linux-3.18.5/drivers/hid/Kconfig
index f42df4d..2235cfe 100644
--- a/linux-3.18.5/drivers/hid/Kconfig
+++ b/linux-3.18.5/drivers/hid/Kconfig
@@ -496,6 +496,20 @@ config HID_MULTITOUCH
        To compile this driver as a module, choose M here: the
        module will be called hid-multitouch.

+config HID_SIS_CTRL
+      bool "SiS Touch Device Controller"
+      depends on HID_MULTITOUCH
+      ---help---
+      Support for SiS Touch devices update FW.
+
+config DEBUG_HID_SIS_UPDATE_FW
+      bool "SiS Touch device debug message(update firmware)"
+      depends on HID_SIS_CTRL
+      default n
+      ---help---
+        Say Y here if you want to enable debug message(update firmware) for SiS Touch 
+          devices. Must enable config HID_SIS_UPDATE_FW first.
+
config HID_NTRIG
      tristate "N-Trig touch screen"
      depends on USB_HID
diff --git a/linux-3.18.5/drivers/hid/hid-ids.h b/linux-3.18.5/drivers/hid/hid-ids.h
index 0e28190..b9ca441 100644
--- a/linux-3.18.5/drivers/hid/hid-ids.h
+++ b/linux-3.18.5/drivers/hid/hid-ids.h
@@ -809,6 +809,7 @@
#define USB_VENDOR_ID_SIS_TOUCH                0x0457
#define USB_DEVICE_ID_SIS9200_TOUCH  0x9200
#define USB_DEVICE_ID_SIS817_TOUCH    0x0817
+#define USB_DEVICE_ID_SISF817_TOUCH  0xF817
#define USB_DEVICE_ID_SIS_TS          0x1013
#define USB_DEVICE_ID_SIS1030_TOUCH  0x1030

diff --git a/linux-3.18.5/drivers/hid/hid-multitouch.c b/linux-3.18.5/drivers/hid/hid-multitouch.c
index 51e25b9..11d67bc 100644
--- a/linux-3.18.5/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.5/drivers/hid/hid-multitouch.c
@@ -54,6 +54,10 @@ MODULE_LICENSE("GPL");

 #include "hid-ids.h"

+#ifdef CONFIG_HID_SIS_CTRL
+#include "hid-sis_ctrl.c"
+#endif
+
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP      (1 << 0)
#define MT_QUIRK_SLOT_IS_CONTACTID   (1 << 1)
@@ -951,6 +955,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
              }
      }

+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              ret = sis_setup_chardev(hdev);
+              if (ret)
+                      dev_err(&hdev->dev, "sis_setup_chardev fail\n");
+      }
+#endif
+
      /* This allows the driver to correctly support devices
       * that emit events over several HID messages.
       */
@@ -1043,6 +1055,10 @@ static void mt_remove(struct hid_device *hdev) {
      sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
      hid_hw_stop(hdev);
+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
+              sis_deinit_chardev();
+#endif
}

 /*
diff --git a/linux-3.18.5/drivers/hid/hid-sis_ctrl.c b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
new file mode 100644
index 0000000..3a7b3df
--- /dev/null
+++ b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
@@ -0,0 +1,360 @@
+/*
+ *  Character device driver for SIS multitouch panels control
+ *
+ *  Copyright (c) 2009 SIS, Ltd.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify 
+it
+ * under the terms of the GNU General Public License as published by 
+the Free
+ * Software Foundation; either version 2 of the License, or (at your 
+option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/init.h>
+
+/*update FW*/
+#include <linux/fs.h>
+#include <linux/cdev.h>
+/*#include <asm/uaccess.h>*/   /*copy_from_user() & copy_to_user()*/
+#include <linux/uaccess.h>
+
+#include "hid-ids.h"
+
+#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
+#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
+
+#define CTRL 0
+#define ENDP_01 1
+#define ENDP_02 2
+#define DIR_IN 0x1
+
+#define SIS_ERR_ALLOCATE_KERNEL_MEM        -12 /* Allocate memory fail */
+#define SIS_ERR_COPY_FROM_USER          -14 /* Copy data from user fail */
+#define SIS_ERR_COPY_FROM_KERNEL      -19 /* Copy data from kernel fail */
+
+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;
+
+static struct hid_device *hid_dev_backup;        /*backup address*/
+static struct urb *backup_urb;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+      #define DBG_FW(fmt, arg...) printk(fmt, ##arg)
+      static void sis_dbg_dump_array(u8 *ptr, u32 size)
+      {
+              u32 i;
+
+              for (i = 0; i < size; i++) {
+                      DBG_FW("%02X ", ptr[i]);
+                      if (((i+1)&0xF) == 0)
+                              DBG_FW("\n");
+              }
+              if (size & 0xF)
+                      DBG_FW("\n");
+      }
+#else
+      #define DBG_FW(...)
+      #define sis_dbg_dump_array(...)
+#endif   /*CONFIG_DEBUG_HID_SIS_UPDATE_FW*/
+
+/*20120306 Yuger ioctl for tool*/
+static int sis_cdev_open(struct inode *inode, struct file *filp) {
+      struct usbhid_device *usbhid;
+
+      DBG_FW("%s\n" , __func__);
+      /*20110511, Yuger, kill current urb by method of usbhid_stop*/
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_stop\n");
+
+      /* printk( KERN_INFO "hid_dev_backup->vendor,
+      * hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor,
+      * hid_dev_backup->product );*/
+
+      /*20110602, Yuger, fix bug: not contact usb cause kernel panic*/
+      if (!usbhid) {
+              pr_info("(stop)usbhid is not initialized yet");
+              return -1;
+      } else if (!usbhid->urbin) {
+              pr_info("(stop)usbhid->urbin is not initialized yet");
+              return -1;
+      } else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              usb_fill_int_urb(backup_urb,
+                      usbhid->urbin->dev,
+                      usbhid->urbin->pipe,
+                      usbhid->urbin->transfer_buffer,
+                      usbhid->urbin->transfer_buffer_length,
+                      usbhid->urbin->complete,
+                      usbhid->urbin->context,
+                      usbhid->urbin->interval);
+              clear_bit(HID_STARTED, &usbhid->iofl);
+              set_bit(HID_DISCONNECTED, &usbhid->iofl);
+
+              usb_kill_urb(usbhid->urbin);
+              usb_free_urb(usbhid->urbin);
+              usbhid->urbin = NULL;
+              return 0;
+      }
+
+      pr_info("This is not a SiS device");
+      return -801;
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp) {
+      /*20110505, Yuger, rebuild the urb which is at the same urb address,
+      * then re-submit it*/
+
+      int ret;
+      struct usbhid_device *usbhid;
+      unsigned long flags;
+
+      DBG_FW("%s: ", __func__);
+
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_start");
+
+      if (!usbhid) {
+              pr_info("(start)usbhid is not initialized yet");
+              return -1;
+      }
+
+      if (!backup_urb) {
+              pr_info("(start)backup_urb is not initialized yet");
+              return -1;
+      }
+
+      clear_bit(HID_DISCONNECTED, &usbhid->iofl);
+      usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL);
+
+      if (!backup_urb->interval) {
+              pr_info("(start)backup_urb->interval does not exist");
+              return -1;
+      }
+
+      usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
+      backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
+      backup_urb->complete, backup_urb->context, backup_urb->interval);
+      usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+      usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+      set_bit(HID_STARTED, &usbhid->iofl);
+
+      /*method at hid_start_in*/
+      spin_lock_irqsave(&usbhid->lock, flags);
+      ret = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
+      spin_unlock_irqrestore(&usbhid->lock, flags);
+      /*yy*/
+
+      DBG_FW("ret = %d", ret);
+
+      return ret;
+}
+
+/*SiS 817 only*/
+static ssize_t sis_cdev_read(struct file *file, char __user *buf,
+                              size_t count, loff_t *ppos) {
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      u32 size, timeout;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+
+      DBG_FW("%s\n", __func__);
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, 8);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
+                      size_t count, loff_t *f_pos) {
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+      struct usbhid_device *usbhid = hid_dev_backup->driver_data;
+      u32 size, timeout;
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, size);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+      DBG_FW("End of sys_sis_HID_IO\n");
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+
+/*for ioctl*/
+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,
+};
+
+/*for ioctl*/
+static int sis_setup_chardev(struct hid_device *hdev) {
+      dev_t dev = MKDEV(sis_char_major, 0);
+      int ret = 0;
+      struct device *class_dev = NULL;
+      u8 *name = (hdev->product == USB_DEVICE_ID_SISF817_TOUCH) ?
+                      SISF817_DEVICE_NAME : SIS817_DEVICE_NAME;
+
+      dev_info(&hdev->dev, "sis_setup_chardev.\n");
+
+      backup_urb = usb_alloc_urb(0, GFP_KERNEL);    /*0721test*/
+      if (!backup_urb) {
+              dev_err(&hdev->dev, "cannot allocate backup_urb\n");
+              return -ENOMEM;
+      }
+      hid_dev_backup = hdev;
+      /*dynamic allocate driver handle*/
+      ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, name);
+      if (ret)
+              goto err1;
+
+      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 err2;
+
+      dev_info(&hdev->dev, "%s driver(major %d) installed.\n",
+                                      name, sis_char_major);
+
+      /*register class*/
+      sis_char_class = class_create(THIS_MODULE, name);
+      if (IS_ERR(sis_char_class)) {
+              ret = PTR_ERR(sis_char_class);
+              goto err3;
+      }
+
+      class_dev = device_create(sis_char_class, NULL, dev, NULL, name);
+      if (IS_ERR(class_dev)) {
+              ret = PTR_ERR(class_dev);
+              goto err4;
+      }
+
+      return 0;
+err4:
+      class_destroy(sis_char_class);
+      sis_char_class = NULL;
+err3:
+      cdev_del(&sis_char_cdev);
+      memset(&sis_char_cdev, 0, sizeof(struct cdev));
+err2:
+      sis_char_major = 0;
+      unregister_chrdev_region(dev, sis_char_devs_count);
+err1:
+      usb_kill_urb(backup_urb);
+      usb_free_urb(backup_urb);
+      backup_urb = NULL;
+      hid_dev_backup = NULL;
+      return ret;
+}
+
+/*for ioctl*/
+static void sis_deinit_chardev(void)
+{
+      dev_t dev = MKDEV(sis_char_major, 0);
+
+      if (hid_dev_backup) {
+              dev_info(&hid_dev_backup->dev, "sis_remove\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);
+              usb_kill_urb(backup_urb);
+              usb_free_urb(backup_urb);
+              backup_urb = NULL;
+              hid_dev_backup = NULL;
+      }
+}
diff --git a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
index 4477eb7..b534321 100644
--- a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
+++ b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
@@ -97,6 +97,7 @@ static const struct hid_blacklist {
      { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
+      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SISF817_TOUCH, 
+ HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
ÿôèº{.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] 13+ messages in thread

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

Hi, Dmitry

> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Thursday, February 12, 2015 3:04 PM
> To: 曾婷葳 (tammy_tseng)
> Cc: Oliver Neukum; lkml; linux-input@vger.kernel.org; 
> tammy0524@gmail.com
> Subject: Re: [PATCH 2/2] INPUT/HID: add touch support for SiS touch 
> driver
> 
> Hi Tammy,
> 
> On Thu, Feb 12, 2015 at 02:07:26PM +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 sent as HTML so mailing lists dropped it.
> 
> Thanks.
> 
> --
> Dmitry


Sorry. Re-send the code diff again.
Here is the hid touch driver for sis touch controller.
Thanks.

Tammy
-----

linux-3.18.5/drivers/hid/Kconfig             |  14 ++
linux-3.18.5/drivers/hid/hid-ids.h           |   1 +
linux-3.18.5/drivers/hid/hid-multitouch.c    |  16 ++
linux-3.18.5/drivers/hid/hid-sis_ctrl.c      | 360 +++++++++++++++++++++++++++
linux-3.18.5/drivers/hid/usbhid/hid-quirks.c |   1 +
5 files changed, 392 insertions(+)


-----
diff --git a/linux-3.18.5/drivers/hid/Kconfig b/linux-3.18.5/drivers/hid/Kconfig
index f42df4d..2235cfe 100644
--- a/linux-3.18.5/drivers/hid/Kconfig
+++ b/linux-3.18.5/drivers/hid/Kconfig
@@ -496,6 +496,20 @@ config HID_MULTITOUCH
        To compile this driver as a module, choose M here: the
        module will be called hid-multitouch.

+config HID_SIS_CTRL
+      bool "SiS Touch Device Controller"
+      depends on HID_MULTITOUCH
+      ---help---
+      Support for SiS Touch devices update FW.
+
+config DEBUG_HID_SIS_UPDATE_FW
+      bool "SiS Touch device debug message(update firmware)"
+      depends on HID_SIS_CTRL
+      default n
+      ---help---
+        Say Y here if you want to enable debug message(update firmware) for SiS Touch 
+          devices. Must enable config HID_SIS_UPDATE_FW first.
+
config HID_NTRIG
      tristate "N-Trig touch screen"
      depends on USB_HID
diff --git a/linux-3.18.5/drivers/hid/hid-ids.h b/linux-3.18.5/drivers/hid/hid-ids.h
index 0e28190..b9ca441 100644
--- a/linux-3.18.5/drivers/hid/hid-ids.h
+++ b/linux-3.18.5/drivers/hid/hid-ids.h
@@ -809,6 +809,7 @@
#define USB_VENDOR_ID_SIS_TOUCH                0x0457
#define USB_DEVICE_ID_SIS9200_TOUCH  0x9200
#define USB_DEVICE_ID_SIS817_TOUCH    0x0817
+#define USB_DEVICE_ID_SISF817_TOUCH  0xF817
#define USB_DEVICE_ID_SIS_TS          0x1013
#define USB_DEVICE_ID_SIS1030_TOUCH  0x1030

diff --git a/linux-3.18.5/drivers/hid/hid-multitouch.c b/linux-3.18.5/drivers/hid/hid-multitouch.c
index 51e25b9..11d67bc 100644
--- a/linux-3.18.5/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.5/drivers/hid/hid-multitouch.c
@@ -54,6 +54,10 @@ MODULE_LICENSE("GPL");

 #include "hid-ids.h"

+#ifdef CONFIG_HID_SIS_CTRL
+#include "hid-sis_ctrl.c"
+#endif
+
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP      (1 << 0)
#define MT_QUIRK_SLOT_IS_CONTACTID   (1 << 1)
@@ -951,6 +955,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
              }
      }

+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              ret = sis_setup_chardev(hdev);
+              if (ret)
+                      dev_err(&hdev->dev, "sis_setup_chardev fail\n");
+      }
+#endif
+
      /* This allows the driver to correctly support devices
       * that emit events over several HID messages.
       */
@@ -1043,6 +1055,10 @@ static void mt_remove(struct hid_device *hdev) {
      sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
      hid_hw_stop(hdev);
+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
+              sis_deinit_chardev();
+#endif
}

 /*
diff --git a/linux-3.18.5/drivers/hid/hid-sis_ctrl.c b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
new file mode 100644
index 0000000..3a7b3df
--- /dev/null
+++ b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
@@ -0,0 +1,360 @@
+/*
+ *  Character device driver for SIS multitouch panels control
+ *
+ *  Copyright (c) 2009 SIS, Ltd.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify 
+it
+ * under the terms of the GNU General Public License as published by 
+the Free
+ * Software Foundation; either version 2 of the License, or (at your 
+option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/init.h>
+
+/*update FW*/
+#include <linux/fs.h>
+#include <linux/cdev.h>
+/*#include <asm/uaccess.h>*/   /*copy_from_user() & copy_to_user()*/
+#include <linux/uaccess.h>
+
+#include "hid-ids.h"
+
+#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
+#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
+
+#define CTRL 0
+#define ENDP_01 1
+#define ENDP_02 2
+#define DIR_IN 0x1
+
+#define SIS_ERR_ALLOCATE_KERNEL_MEM        -12 /* Allocate memory fail */
+#define SIS_ERR_COPY_FROM_USER          -14 /* Copy data from user fail */
+#define SIS_ERR_COPY_FROM_KERNEL      -19 /* Copy data from kernel fail */
+
+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;
+
+static struct hid_device *hid_dev_backup;        /*backup address*/
+static struct urb *backup_urb;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+      #define DBG_FW(fmt, arg...) printk(fmt, ##arg)
+      static void sis_dbg_dump_array(u8 *ptr, u32 size)
+      {
+              u32 i;
+
+              for (i = 0; i < size; i++) {
+                      DBG_FW("%02X ", ptr[i]);
+                      if (((i+1)&0xF) == 0)
+                              DBG_FW("\n");
+              }
+              if (size & 0xF)
+                      DBG_FW("\n");
+      }
+#else
+      #define DBG_FW(...)
+      #define sis_dbg_dump_array(...)
+#endif   /*CONFIG_DEBUG_HID_SIS_UPDATE_FW*/
+
+/*20120306 Yuger ioctl for tool*/
+static int sis_cdev_open(struct inode *inode, struct file *filp) {
+      struct usbhid_device *usbhid;
+
+      DBG_FW("%s\n" , __func__);
+      /*20110511, Yuger, kill current urb by method of usbhid_stop*/
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_stop\n");
+
+      /* printk( KERN_INFO "hid_dev_backup->vendor,
+      * hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor,
+      * hid_dev_backup->product );*/
+
+      /*20110602, Yuger, fix bug: not contact usb cause kernel panic*/
+      if (!usbhid) {
+              pr_info("(stop)usbhid is not initialized yet");
+              return -1;
+      } else if (!usbhid->urbin) {
+              pr_info("(stop)usbhid->urbin is not initialized yet");
+              return -1;
+      } else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              usb_fill_int_urb(backup_urb,
+                      usbhid->urbin->dev,
+                      usbhid->urbin->pipe,
+                      usbhid->urbin->transfer_buffer,
+                      usbhid->urbin->transfer_buffer_length,
+                      usbhid->urbin->complete,
+                      usbhid->urbin->context,
+                      usbhid->urbin->interval);
+              clear_bit(HID_STARTED, &usbhid->iofl);
+              set_bit(HID_DISCONNECTED, &usbhid->iofl);
+
+              usb_kill_urb(usbhid->urbin);
+              usb_free_urb(usbhid->urbin);
+              usbhid->urbin = NULL;
+              return 0;
+      }
+
+      pr_info("This is not a SiS device");
+      return -801;
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp) {
+      /*20110505, Yuger, rebuild the urb which is at the same urb address,
+      * then re-submit it*/
+
+      int ret;
+      struct usbhid_device *usbhid;
+      unsigned long flags;
+
+      DBG_FW("%s: ", __func__);
+
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_start");
+
+      if (!usbhid) {
+              pr_info("(start)usbhid is not initialized yet");
+              return -1;
+      }
+
+      if (!backup_urb) {
+              pr_info("(start)backup_urb is not initialized yet");
+              return -1;
+      }
+
+      clear_bit(HID_DISCONNECTED, &usbhid->iofl);
+      usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL);
+
+      if (!backup_urb->interval) {
+              pr_info("(start)backup_urb->interval does not exist");
+              return -1;
+      }
+
+      usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
+      backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
+      backup_urb->complete, backup_urb->context, backup_urb->interval);
+      usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+      usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+      set_bit(HID_STARTED, &usbhid->iofl);
+
+      /*method at hid_start_in*/
+      spin_lock_irqsave(&usbhid->lock, flags);
+      ret = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
+      spin_unlock_irqrestore(&usbhid->lock, flags);
+      /*yy*/
+
+      DBG_FW("ret = %d", ret);
+
+      return ret;
+}
+
+/*SiS 817 only*/
+static ssize_t sis_cdev_read(struct file *file, char __user *buf,
+                              size_t count, loff_t *ppos) {
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      u32 size, timeout;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+
+      DBG_FW("%s\n", __func__);
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, 8);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
+                      size_t count, loff_t *f_pos) {
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+      struct usbhid_device *usbhid = hid_dev_backup->driver_data;
+      u32 size, timeout;
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, size);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+      DBG_FW("End of sys_sis_HID_IO\n");
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+
+/*for ioctl*/
+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,
+};
+
+/*for ioctl*/
+static int sis_setup_chardev(struct hid_device *hdev) {
+      dev_t dev = MKDEV(sis_char_major, 0);
+      int ret = 0;
+      struct device *class_dev = NULL;
+      u8 *name = (hdev->product == USB_DEVICE_ID_SISF817_TOUCH) ?
+                      SISF817_DEVICE_NAME : SIS817_DEVICE_NAME;
+
+      dev_info(&hdev->dev, "sis_setup_chardev.\n");
+
+      backup_urb = usb_alloc_urb(0, GFP_KERNEL);    /*0721test*/
+      if (!backup_urb) {
+              dev_err(&hdev->dev, "cannot allocate backup_urb\n");
+              return -ENOMEM;
+      }
+      hid_dev_backup = hdev;
+      /*dynamic allocate driver handle*/
+      ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, name);
+      if (ret)
+              goto err1;
+
+      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 err2;
+
+      dev_info(&hdev->dev, "%s driver(major %d) installed.\n",
+                                      name, sis_char_major);
+
+      /*register class*/
+      sis_char_class = class_create(THIS_MODULE, name);
+      if (IS_ERR(sis_char_class)) {
+              ret = PTR_ERR(sis_char_class);
+              goto err3;
+      }
+
+      class_dev = device_create(sis_char_class, NULL, dev, NULL, name);
+      if (IS_ERR(class_dev)) {
+              ret = PTR_ERR(class_dev);
+              goto err4;
+      }
+
+      return 0;
+err4:
+      class_destroy(sis_char_class);
+      sis_char_class = NULL;
+err3:
+      cdev_del(&sis_char_cdev);
+      memset(&sis_char_cdev, 0, sizeof(struct cdev));
+err2:
+      sis_char_major = 0;
+      unregister_chrdev_region(dev, sis_char_devs_count);
+err1:
+      usb_kill_urb(backup_urb);
+      usb_free_urb(backup_urb);
+      backup_urb = NULL;
+      hid_dev_backup = NULL;
+      return ret;
+}
+
+/*for ioctl*/
+static void sis_deinit_chardev(void)
+{
+      dev_t dev = MKDEV(sis_char_major, 0);
+
+      if (hid_dev_backup) {
+              dev_info(&hid_dev_backup->dev, "sis_remove\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);
+              usb_kill_urb(backup_urb);
+              usb_free_urb(backup_urb);
+              backup_urb = NULL;
+              hid_dev_backup = NULL;
+      }
+}
diff --git a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
index 4477eb7..b534321 100644
--- a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
+++ b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
@@ -97,6 +97,7 @@ static const struct hid_blacklist {
      { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
+      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SISF817_TOUCH, 
+ HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },

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

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

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

Hi, Dmitry

> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Thursday, February 12, 2015 3:04 PM
> To: 曾婷葳 (tammy_tseng)
> Cc: Oliver Neukum; lkml; linux-input@vger.kernel.org; tammy0524@gmail.com
> Subject: Re: [PATCH 2/2] INPUT/HID: add touch support for SiS touch
> driver
> 
> Hi Tammy,
> 
> On Thu, Feb 12, 2015 at 02:07:26PM +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 sent as HTML so mailing lists dropped it.
> 
> Thanks.
> 
> --
> Dmitry


Sorry. Re-send the code diff again.
Here is the hid touch driver for sis touch controller.
Thanks.

Tammy
-----

linux-3.18.5/drivers/hid/Kconfig             |  14 ++
linux-3.18.5/drivers/hid/hid-ids.h           |   1 +
linux-3.18.5/drivers/hid/hid-multitouch.c    |  16 ++
linux-3.18.5/drivers/hid/hid-sis_ctrl.c      | 360 +++++++++++++++++++++++++++
linux-3.18.5/drivers/hid/usbhid/hid-quirks.c |   1 +
5 files changed, 392 insertions(+)


-----
diff --git a/linux-3.18.5/drivers/hid/Kconfig b/linux-3.18.5/drivers/hid/Kconfig
index f42df4d..2235cfe 100644
--- a/linux-3.18.5/drivers/hid/Kconfig
+++ b/linux-3.18.5/drivers/hid/Kconfig
@@ -496,6 +496,20 @@ config HID_MULTITOUCH
        To compile this driver as a module, choose M here: the
        module will be called hid-multitouch.

+config HID_SIS_CTRL
+      bool "SiS Touch Device Controller"
+      depends on HID_MULTITOUCH
+      ---help---
+      Support for SiS Touch devices update FW.
+
+config DEBUG_HID_SIS_UPDATE_FW
+      bool "SiS Touch device debug message(update firmware)"
+      depends on HID_SIS_CTRL
+      default n
+      ---help---
+        Say Y here if you want to enable debug message(update firmware) for SiS Touch 
+          devices. Must enable config HID_SIS_UPDATE_FW first.
+
config HID_NTRIG
      tristate "N-Trig touch screen"
      depends on USB_HID
diff --git a/linux-3.18.5/drivers/hid/hid-ids.h b/linux-3.18.5/drivers/hid/hid-ids.h
index 0e28190..b9ca441 100644
--- a/linux-3.18.5/drivers/hid/hid-ids.h
+++ b/linux-3.18.5/drivers/hid/hid-ids.h
@@ -809,6 +809,7 @@
#define USB_VENDOR_ID_SIS_TOUCH                0x0457
#define USB_DEVICE_ID_SIS9200_TOUCH  0x9200
#define USB_DEVICE_ID_SIS817_TOUCH    0x0817
+#define USB_DEVICE_ID_SISF817_TOUCH  0xF817
#define USB_DEVICE_ID_SIS_TS          0x1013
#define USB_DEVICE_ID_SIS1030_TOUCH  0x1030

diff --git a/linux-3.18.5/drivers/hid/hid-multitouch.c b/linux-3.18.5/drivers/hid/hid-multitouch.c
index 51e25b9..11d67bc 100644
--- a/linux-3.18.5/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.5/drivers/hid/hid-multitouch.c
@@ -54,6 +54,10 @@ MODULE_LICENSE("GPL");

 #include "hid-ids.h"

+#ifdef CONFIG_HID_SIS_CTRL
+#include "hid-sis_ctrl.c"
+#endif
+
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP      (1 << 0)
#define MT_QUIRK_SLOT_IS_CONTACTID   (1 << 1)
@@ -951,6 +955,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
              }
      }

+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              ret = sis_setup_chardev(hdev);
+              if (ret)
+                      dev_err(&hdev->dev, "sis_setup_chardev fail\n");
+      }
+#endif
+
      /* This allows the driver to correctly support devices
       * that emit events over several HID messages.
       */
@@ -1043,6 +1055,10 @@ static void mt_remove(struct hid_device *hdev)
{
      sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
      hid_hw_stop(hdev);
+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
+              sis_deinit_chardev();
+#endif
}

 /*
diff --git a/linux-3.18.5/drivers/hid/hid-sis_ctrl.c b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
new file mode 100644
index 0000000..3a7b3df
--- /dev/null
+++ b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
@@ -0,0 +1,360 @@
+/*
+ *  Character device driver for SIS multitouch panels control
+ *
+ *  Copyright (c) 2009 SIS, Ltd.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/init.h>
+
+/*update FW*/
+#include <linux/fs.h>
+#include <linux/cdev.h>
+/*#include <asm/uaccess.h>*/   /*copy_from_user() & copy_to_user()*/
+#include <linux/uaccess.h>
+
+#include "hid-ids.h"
+
+#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
+#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
+
+#define CTRL 0
+#define ENDP_01 1
+#define ENDP_02 2
+#define DIR_IN 0x1
+
+#define SIS_ERR_ALLOCATE_KERNEL_MEM        -12 /* Allocate memory fail */
+#define SIS_ERR_COPY_FROM_USER          -14 /* Copy data from user fail */
+#define SIS_ERR_COPY_FROM_KERNEL      -19 /* Copy data from kernel fail */
+
+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;
+
+static struct hid_device *hid_dev_backup;        /*backup address*/
+static struct urb *backup_urb;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+      #define DBG_FW(fmt, arg...) printk(fmt, ##arg)
+      static void sis_dbg_dump_array(u8 *ptr, u32 size)
+      {
+              u32 i;
+
+              for (i = 0; i < size; i++) {
+                      DBG_FW("%02X ", ptr[i]);
+                      if (((i+1)&0xF) == 0)
+                              DBG_FW("\n");
+              }
+              if (size & 0xF)
+                      DBG_FW("\n");
+      }
+#else
+      #define DBG_FW(...)
+      #define sis_dbg_dump_array(...)
+#endif   /*CONFIG_DEBUG_HID_SIS_UPDATE_FW*/
+
+/*20120306 Yuger ioctl for tool*/
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+      struct usbhid_device *usbhid;
+
+      DBG_FW("%s\n" , __func__);
+      /*20110511, Yuger, kill current urb by method of usbhid_stop*/
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_stop\n");
+
+      /* printk( KERN_INFO "hid_dev_backup->vendor,
+      * hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor,
+      * hid_dev_backup->product );*/
+
+      /*20110602, Yuger, fix bug: not contact usb cause kernel panic*/
+      if (!usbhid) {
+              pr_info("(stop)usbhid is not initialized yet");
+              return -1;
+      } else if (!usbhid->urbin) {
+              pr_info("(stop)usbhid->urbin is not initialized yet");
+              return -1;
+      } else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              usb_fill_int_urb(backup_urb,
+                      usbhid->urbin->dev,
+                      usbhid->urbin->pipe,
+                      usbhid->urbin->transfer_buffer,
+                      usbhid->urbin->transfer_buffer_length,
+                      usbhid->urbin->complete,
+                      usbhid->urbin->context,
+                      usbhid->urbin->interval);
+              clear_bit(HID_STARTED, &usbhid->iofl);
+              set_bit(HID_DISCONNECTED, &usbhid->iofl);
+
+              usb_kill_urb(usbhid->urbin);
+              usb_free_urb(usbhid->urbin);
+              usbhid->urbin = NULL;
+              return 0;
+      }
+
+      pr_info("This is not a SiS device");
+      return -801;
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+      /*20110505, Yuger, rebuild the urb which is at the same urb address,
+      * then re-submit it*/
+
+      int ret;
+      struct usbhid_device *usbhid;
+      unsigned long flags;
+
+      DBG_FW("%s: ", __func__);
+
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_start");
+
+      if (!usbhid) {
+              pr_info("(start)usbhid is not initialized yet");
+              return -1;
+      }
+
+      if (!backup_urb) {
+              pr_info("(start)backup_urb is not initialized yet");
+              return -1;
+      }
+
+      clear_bit(HID_DISCONNECTED, &usbhid->iofl);
+      usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL);
+
+      if (!backup_urb->interval) {
+              pr_info("(start)backup_urb->interval does not exist");
+              return -1;
+      }
+
+      usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
+      backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
+      backup_urb->complete, backup_urb->context, backup_urb->interval);
+      usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+      usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+      set_bit(HID_STARTED, &usbhid->iofl);
+
+      /*method at hid_start_in*/
+      spin_lock_irqsave(&usbhid->lock, flags);
+      ret = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
+      spin_unlock_irqrestore(&usbhid->lock, flags);
+      /*yy*/
+
+      DBG_FW("ret = %d", ret);
+
+      return ret;
+}
+
+/*SiS 817 only*/
+static ssize_t sis_cdev_read(struct file *file, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      u32 size, timeout;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+
+      DBG_FW("%s\n", __func__);
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, 8);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
+                      size_t count, loff_t *f_pos)
+{
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+      struct usbhid_device *usbhid = hid_dev_backup->driver_data;
+      u32 size, timeout;
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, size);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+      DBG_FW("End of sys_sis_HID_IO\n");
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+
+/*for ioctl*/
+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,
+};
+
+/*for ioctl*/
+static int sis_setup_chardev(struct hid_device *hdev)
+{
+      dev_t dev = MKDEV(sis_char_major, 0);
+      int ret = 0;
+      struct device *class_dev = NULL;
+      u8 *name = (hdev->product == USB_DEVICE_ID_SISF817_TOUCH) ?
+                      SISF817_DEVICE_NAME : SIS817_DEVICE_NAME;
+
+      dev_info(&hdev->dev, "sis_setup_chardev.\n");
+
+      backup_urb = usb_alloc_urb(0, GFP_KERNEL);    /*0721test*/
+      if (!backup_urb) {
+              dev_err(&hdev->dev, "cannot allocate backup_urb\n");
+              return -ENOMEM;
+      }
+      hid_dev_backup = hdev;
+      /*dynamic allocate driver handle*/
+      ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, name);
+      if (ret)
+              goto err1;
+
+      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 err2;
+
+      dev_info(&hdev->dev, "%s driver(major %d) installed.\n",
+                                      name, sis_char_major);
+
+      /*register class*/
+      sis_char_class = class_create(THIS_MODULE, name);
+      if (IS_ERR(sis_char_class)) {
+              ret = PTR_ERR(sis_char_class);
+              goto err3;
+      }
+
+      class_dev = device_create(sis_char_class, NULL, dev, NULL, name);
+      if (IS_ERR(class_dev)) {
+              ret = PTR_ERR(class_dev);
+              goto err4;
+      }
+
+      return 0;
+err4:
+      class_destroy(sis_char_class);
+      sis_char_class = NULL;
+err3:
+      cdev_del(&sis_char_cdev);
+      memset(&sis_char_cdev, 0, sizeof(struct cdev));
+err2:
+      sis_char_major = 0;
+      unregister_chrdev_region(dev, sis_char_devs_count);
+err1:
+      usb_kill_urb(backup_urb);
+      usb_free_urb(backup_urb);
+      backup_urb = NULL;
+      hid_dev_backup = NULL;
+      return ret;
+}
+
+/*for ioctl*/
+static void sis_deinit_chardev(void)
+{
+      dev_t dev = MKDEV(sis_char_major, 0);
+
+      if (hid_dev_backup) {
+              dev_info(&hid_dev_backup->dev, "sis_remove\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);
+              usb_kill_urb(backup_urb);
+              usb_free_urb(backup_urb);
+              backup_urb = NULL;
+              hid_dev_backup = NULL;
+      }
+}
diff --git a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
index 4477eb7..b534321 100644
--- a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
+++ b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
@@ -97,6 +97,7 @@ static const struct hid_blacklist {
      { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
+      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SISF817_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
ÿôèº{.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] 13+ messages in thread

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

Hi, Dmitry

> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Thursday, February 12, 2015 3:04 PM
> To: 曾婷葳 (tammy_tseng)
> Cc: Oliver Neukum; lkml; linux-input@vger.kernel.org; tammy0524@gmail.com
> Subject: Re: [PATCH 2/2] INPUT/HID: add touch support for SiS touch
> driver
> 
> Hi Tammy,
> 
> On Thu, Feb 12, 2015 at 02:07:26PM +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 sent as HTML so mailing lists dropped it.
> 
> Thanks.
> 
> --
> Dmitry


Sorry. Re-send the code diff again.
Here is the hid touch driver for sis touch controller.
Thanks.

Tammy
-----

linux-3.18.5/drivers/hid/Kconfig             |  14 ++
linux-3.18.5/drivers/hid/hid-ids.h           |   1 +
linux-3.18.5/drivers/hid/hid-multitouch.c    |  16 ++
linux-3.18.5/drivers/hid/hid-sis_ctrl.c      | 360 +++++++++++++++++++++++++++
linux-3.18.5/drivers/hid/usbhid/hid-quirks.c |   1 +
5 files changed, 392 insertions(+)


-----
diff --git a/linux-3.18.5/drivers/hid/Kconfig b/linux-3.18.5/drivers/hid/Kconfig
index f42df4d..2235cfe 100644
--- a/linux-3.18.5/drivers/hid/Kconfig
+++ b/linux-3.18.5/drivers/hid/Kconfig
@@ -496,6 +496,20 @@ config HID_MULTITOUCH
        To compile this driver as a module, choose M here: the
        module will be called hid-multitouch.

+config HID_SIS_CTRL
+      bool "SiS Touch Device Controller"
+      depends on HID_MULTITOUCH
+      ---help---
+      Support for SiS Touch devices update FW.
+
+config DEBUG_HID_SIS_UPDATE_FW
+      bool "SiS Touch device debug message(update firmware)"
+      depends on HID_SIS_CTRL
+      default n
+      ---help---
+        Say Y here if you want to enable debug message(update firmware) for SiS Touch 
+          devices. Must enable config HID_SIS_UPDATE_FW first.
+
config HID_NTRIG
      tristate "N-Trig touch screen"
      depends on USB_HID
diff --git a/linux-3.18.5/drivers/hid/hid-ids.h b/linux-3.18.5/drivers/hid/hid-ids.h
index 0e28190..b9ca441 100644
--- a/linux-3.18.5/drivers/hid/hid-ids.h
+++ b/linux-3.18.5/drivers/hid/hid-ids.h
@@ -809,6 +809,7 @@
#define USB_VENDOR_ID_SIS_TOUCH                0x0457
#define USB_DEVICE_ID_SIS9200_TOUCH  0x9200
#define USB_DEVICE_ID_SIS817_TOUCH    0x0817
+#define USB_DEVICE_ID_SISF817_TOUCH  0xF817
#define USB_DEVICE_ID_SIS_TS          0x1013
#define USB_DEVICE_ID_SIS1030_TOUCH  0x1030

diff --git a/linux-3.18.5/drivers/hid/hid-multitouch.c b/linux-3.18.5/drivers/hid/hid-multitouch.c
index 51e25b9..11d67bc 100644
--- a/linux-3.18.5/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.5/drivers/hid/hid-multitouch.c
@@ -54,6 +54,10 @@ MODULE_LICENSE("GPL");

 #include "hid-ids.h"

+#ifdef CONFIG_HID_SIS_CTRL
+#include "hid-sis_ctrl.c"
+#endif
+
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP      (1 << 0)
#define MT_QUIRK_SLOT_IS_CONTACTID   (1 << 1)
@@ -951,6 +955,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
              }
      }

+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              ret = sis_setup_chardev(hdev);
+              if (ret)
+                      dev_err(&hdev->dev, "sis_setup_chardev fail\n");
+      }
+#endif
+
      /* This allows the driver to correctly support devices
       * that emit events over several HID messages.
       */
@@ -1043,6 +1055,10 @@ static void mt_remove(struct hid_device *hdev)
{
      sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
      hid_hw_stop(hdev);
+#ifdef CONFIG_HID_SIS_CTRL
+      if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH)
+              sis_deinit_chardev();
+#endif
}

 /*
diff --git a/linux-3.18.5/drivers/hid/hid-sis_ctrl.c b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
new file mode 100644
index 0000000..3a7b3df
--- /dev/null
+++ b/linux-3.18.5/drivers/hid/hid-sis_ctrl.c
@@ -0,0 +1,360 @@
+/*
+ *  Character device driver for SIS multitouch panels control
+ *
+ *  Copyright (c) 2009 SIS, Ltd.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/init.h>
+
+/*update FW*/
+#include <linux/fs.h>
+#include <linux/cdev.h>
+/*#include <asm/uaccess.h>*/   /*copy_from_user() & copy_to_user()*/
+#include <linux/uaccess.h>
+
+#include "hid-ids.h"
+
+#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
+#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
+
+#define CTRL 0
+#define ENDP_01 1
+#define ENDP_02 2
+#define DIR_IN 0x1
+
+#define SIS_ERR_ALLOCATE_KERNEL_MEM        -12 /* Allocate memory fail */
+#define SIS_ERR_COPY_FROM_USER          -14 /* Copy data from user fail */
+#define SIS_ERR_COPY_FROM_KERNEL      -19 /* Copy data from kernel fail */
+
+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;
+
+static struct hid_device *hid_dev_backup;        /*backup address*/
+static struct urb *backup_urb;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+      #define DBG_FW(fmt, arg...) printk(fmt, ##arg)
+      static void sis_dbg_dump_array(u8 *ptr, u32 size)
+      {
+              u32 i;
+
+              for (i = 0; i < size; i++) {
+                      DBG_FW("%02X ", ptr[i]);
+                      if (((i+1)&0xF) == 0)
+                              DBG_FW("\n");
+              }
+              if (size & 0xF)
+                      DBG_FW("\n");
+      }
+#else
+      #define DBG_FW(...)
+      #define sis_dbg_dump_array(...)
+#endif   /*CONFIG_DEBUG_HID_SIS_UPDATE_FW*/
+
+/*20120306 Yuger ioctl for tool*/
+static int sis_cdev_open(struct inode *inode, struct file *filp)
+{
+      struct usbhid_device *usbhid;
+
+      DBG_FW("%s\n" , __func__);
+      /*20110511, Yuger, kill current urb by method of usbhid_stop*/
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_stop\n");
+
+      /* printk( KERN_INFO "hid_dev_backup->vendor,
+      * hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor,
+      * hid_dev_backup->product );*/
+
+      /*20110602, Yuger, fix bug: not contact usb cause kernel panic*/
+      if (!usbhid) {
+              pr_info("(stop)usbhid is not initialized yet");
+              return -1;
+      } else if (!usbhid->urbin) {
+              pr_info("(stop)usbhid->urbin is not initialized yet");
+              return -1;
+      } else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+              usb_fill_int_urb(backup_urb,
+                      usbhid->urbin->dev,
+                      usbhid->urbin->pipe,
+                      usbhid->urbin->transfer_buffer,
+                      usbhid->urbin->transfer_buffer_length,
+                      usbhid->urbin->complete,
+                      usbhid->urbin->context,
+                      usbhid->urbin->interval);
+              clear_bit(HID_STARTED, &usbhid->iofl);
+              set_bit(HID_DISCONNECTED, &usbhid->iofl);
+
+              usb_kill_urb(usbhid->urbin);
+              usb_free_urb(usbhid->urbin);
+              usbhid->urbin = NULL;
+              return 0;
+      }
+
+      pr_info("This is not a SiS device");
+      return -801;
+}
+
+static int sis_cdev_release(struct inode *inode, struct file *filp)
+{
+      /*20110505, Yuger, rebuild the urb which is at the same urb address,
+      * then re-submit it*/
+
+      int ret;
+      struct usbhid_device *usbhid;
+      unsigned long flags;
+
+      DBG_FW("%s: ", __func__);
+
+      if (!hid_dev_backup) {
+              pr_info("(stop)hid_dev_backup is not initialized yet");
+              return -1;
+      }
+
+      usbhid = hid_dev_backup->driver_data;
+
+      pr_info("sys_sis_HID_start");
+
+      if (!usbhid) {
+              pr_info("(start)usbhid is not initialized yet");
+              return -1;
+      }
+
+      if (!backup_urb) {
+              pr_info("(start)backup_urb is not initialized yet");
+              return -1;
+      }
+
+      clear_bit(HID_DISCONNECTED, &usbhid->iofl);
+      usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL);
+
+      if (!backup_urb->interval) {
+              pr_info("(start)backup_urb->interval does not exist");
+              return -1;
+      }
+
+      usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
+      backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
+      backup_urb->complete, backup_urb->context, backup_urb->interval);
+      usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+      usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+      set_bit(HID_STARTED, &usbhid->iofl);
+
+      /*method at hid_start_in*/
+      spin_lock_irqsave(&usbhid->lock, flags);
+      ret = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
+      spin_unlock_irqrestore(&usbhid->lock, flags);
+      /*yy*/
+
+      DBG_FW("ret = %d", ret);
+
+      return ret;
+}
+
+/*SiS 817 only*/
+static ssize_t sis_cdev_read(struct file *file, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      u32 size, timeout;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+
+      DBG_FW("%s\n", __func__);
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, 8);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+static ssize_t sis_cdev_write(struct file *file, const char __user *buf,
+                      size_t count, loff_t *f_pos)
+{
+      int actual_length = 0;
+      u8 *rep_data = NULL;
+      long rep_ret = 0;
+      struct usb_interface *intf =
+                      to_usb_interface(hid_dev_backup->dev.parent);
+      struct usb_device *dev = interface_to_usbdev(intf);
+      struct usbhid_device *usbhid = hid_dev_backup->driver_data;
+      u32 size, timeout;
+
+      rep_data = kzalloc(count, GFP_KERNEL);
+      if (!rep_data)
+              return SIS_ERR_ALLOCATE_KERNEL_MEM;
+
+      if (copy_from_user(rep_data, (void *)buf, count)) {
+              pr_err("copy_to_user fail\n");
+              rep_ret = SIS_ERR_COPY_FROM_USER;
+              goto end;
+      }
+
+      size = be32_to_cpup((u32 *)&rep_data[64]);
+      timeout = be32_to_cpup((u32 *)&rep_data[68]);
+
+      rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
+              rep_data, size, &actual_length, timeout);
+
+      DBG_FW("%s: rep_data = ", __func__);
+      sis_dbg_dump_array(rep_data, size);
+
+      if (rep_ret == 0) {
+              rep_ret = actual_length;
+              if (copy_to_user((void *)buf, rep_data, rep_ret)) {
+                      pr_err("copy_to_user fail\n");
+                      rep_ret = SIS_ERR_COPY_FROM_KERNEL;
+                      goto end;
+              }
+      }
+      DBG_FW("%s: rep_ret = %ld\n", __func__, rep_ret);
+      DBG_FW("End of sys_sis_HID_IO\n");
+end:
+      /*free allocated data*/
+      kfree(rep_data);
+      return rep_ret;
+}
+
+
+/*for ioctl*/
+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,
+};
+
+/*for ioctl*/
+static int sis_setup_chardev(struct hid_device *hdev)
+{
+      dev_t dev = MKDEV(sis_char_major, 0);
+      int ret = 0;
+      struct device *class_dev = NULL;
+      u8 *name = (hdev->product == USB_DEVICE_ID_SISF817_TOUCH) ?
+                      SISF817_DEVICE_NAME : SIS817_DEVICE_NAME;
+
+      dev_info(&hdev->dev, "sis_setup_chardev.\n");
+
+      backup_urb = usb_alloc_urb(0, GFP_KERNEL);    /*0721test*/
+      if (!backup_urb) {
+              dev_err(&hdev->dev, "cannot allocate backup_urb\n");
+              return -ENOMEM;
+      }
+      hid_dev_backup = hdev;
+      /*dynamic allocate driver handle*/
+      ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, name);
+      if (ret)
+              goto err1;
+
+      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 err2;
+
+      dev_info(&hdev->dev, "%s driver(major %d) installed.\n",
+                                      name, sis_char_major);
+
+      /*register class*/
+      sis_char_class = class_create(THIS_MODULE, name);
+      if (IS_ERR(sis_char_class)) {
+              ret = PTR_ERR(sis_char_class);
+              goto err3;
+      }
+
+      class_dev = device_create(sis_char_class, NULL, dev, NULL, name);
+      if (IS_ERR(class_dev)) {
+              ret = PTR_ERR(class_dev);
+              goto err4;
+      }
+
+      return 0;
+err4:
+      class_destroy(sis_char_class);
+      sis_char_class = NULL;
+err3:
+      cdev_del(&sis_char_cdev);
+      memset(&sis_char_cdev, 0, sizeof(struct cdev));
+err2:
+      sis_char_major = 0;
+      unregister_chrdev_region(dev, sis_char_devs_count);
+err1:
+      usb_kill_urb(backup_urb);
+      usb_free_urb(backup_urb);
+      backup_urb = NULL;
+      hid_dev_backup = NULL;
+      return ret;
+}
+
+/*for ioctl*/
+static void sis_deinit_chardev(void)
+{
+      dev_t dev = MKDEV(sis_char_major, 0);
+
+      if (hid_dev_backup) {
+              dev_info(&hid_dev_backup->dev, "sis_remove\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);
+              usb_kill_urb(backup_urb);
+              usb_free_urb(backup_urb);
+              backup_urb = NULL;
+              hid_dev_backup = NULL;
+      }
+}
diff --git a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
index 4477eb7..b534321 100644
--- a/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
+++ b/linux-3.18.5/drivers/hid/usbhid/hid-quirks.c
@@ -97,6 +97,7 @@ static const struct hid_blacklist {
      { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
+      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SISF817_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
      { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
      { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },

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

* Re: [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver
       [not found] <8322374EB97AA24A95D0DDBFC8F1CA1DCB07FA@SISMBEV01.sis.com.tw>
@ 2015-02-12  7:03   ` Dmitry Torokhov
  0 siblings, 0 replies; 13+ messages in thread
From: Dmitry Torokhov @ 2015-02-12  7:03 UTC (permalink / raw)
  To: 曾婷葳 (tammy_tseng)
  Cc: Oliver Neukum, lkml, linux-input, tammy0524

Hi Tammy,

On Thu, Feb 12, 2015 at 02:07:26PM +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 sent as HTML so mailing lists dropped it.

Thanks.

-- 
Dmitry

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

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

Hi Tammy,

On Thu, Feb 12, 2015 at 02:07:26PM +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 sent as HTML so mailing lists dropped it.

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] 13+ messages in thread

* [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-09 10:38 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 13+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-09 10:38 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 hid multitouch driver is in hid.

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

diff --git a/linux-3.18.1/drivers/hid/Kconfig b/linux-3.18.1/drivers/hid/Kconfig
index 2be7677..f42df4d 100644
--- a/linux-3.18.1/drivers/hid/Kconfig
+++ b/linux-3.18.1/drivers/hid/Kconfig
@@ -494,35 +494,7 @@ config HID_MULTITOUCH
 	  If unsure, say N.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called hid-multitouch.  
-	  
-config HID_MT_DBG_POINT
-	bool "HID Multitouch panels debug for touch point"
-	depends on HID_MULTITOUCH
-	default n
-	---help---
-	  Show debug message for touch point information.
-
-config HID_MT_DBG_MAP_INIT
-	bool "HID Multitouch panels debug mapping initial"
-	depends on HID_MULTITOUCH
-	default n
-	---help---
-	  Show debug message for mapping initial information.  
-
-config HID_SIS_CTRL
-	tristate "SiS Touch Device Controller"
-	depends on HID_MULTITOUCH
-	---help---
-	Support for SiS Touch devices update FW.
-
-config DEBUG_HID_SIS_UPDATE_FW
-	bool "SiS Touch device debug message(update firmware)"
-	depends on HID_SIS_CTRL
-	default n
-	---help---
-	  Say Y here if you want to enable debug message(update firmware) for SiS Touch 
-          devices. Must enable config HID_SIS_UPDATE_FW first.
+	  module will be called hid-multitouch.
 
 config HID_NTRIG
 	tristate "N-Trig touch screen"
diff --git a/linux-3.18.1/drivers/hid/Makefile b/linux-3.18.1/drivers/hid/Makefile
index 02dc20d..e2850d8 100644
--- a/linux-3.18.1/drivers/hid/Makefile
+++ b/linux-3.18.1/drivers/hid/Makefile
@@ -33,7 +33,6 @@ ifdef CONFIG_DEBUG_FS
 	hid-wiimote-y	+= hid-wiimote-debug.o
 endif
 
-obj-$(CONFIG_HID_SIS_CTRL)	+= hid-sis_ctrl.o
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
 obj-$(CONFIG_HID_ACRUX)		+= hid-axff.o
 obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
diff --git a/linux-3.18.1/drivers/hid/hid-ids.h b/linux-3.18.1/drivers/hid/hid-ids.h
index c598e8d..7c86373 100644
--- a/linux-3.18.1/drivers/hid/hid-ids.h
+++ b/linux-3.18.1/drivers/hid/hid-ids.h
@@ -807,7 +807,6 @@
 #define USB_VENDOR_ID_SIS_TOUCH		0x0457
 #define USB_DEVICE_ID_SIS9200_TOUCH	0x9200
 #define USB_DEVICE_ID_SIS817_TOUCH	0x0817
-#define USB_PRODUCT_ID_SISF817_TOUCH	0xF817
 #define USB_DEVICE_ID_SIS_TS		0x1013
 #define USB_DEVICE_ID_SIS1030_TOUCH	0x1030
 
diff --git a/linux-3.18.1/drivers/hid/hid-multitouch.c b/linux-3.18.1/drivers/hid/hid-multitouch.c
index 31e28dd..51e25b9 100644
--- a/linux-3.18.1/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.1/drivers/hid/hid-multitouch.c
@@ -45,7 +45,7 @@
 #include <linux/usb.h>
 #include <linux/input/mt.h>
 #include <linux/string.h>
-#include "hid-sis_ctrl.h"
+
 
 MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
@@ -1003,19 +1003,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (ret != 0)
 		return ret;
 
-	//SiS set noget for not init reports
-	hdev->quirks |= HID_QUIRK_NOGET;
-	printk(KERN_INFO "sis:sis-probe: quirk = %x\n", hdev->quirks);
-
-	//SiS FW update
-#ifdef CONFIG_HID_SIS_CTRL
-	ret = sis_setup_chardev(hdev);
-	if(ret)
-	{
-		printk( KERN_INFO "sis_setup_chardev fail\n");
-	}
-#endif	//CONFIG_HID_SIS_CTRL
-
 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 	if (ret)
 		return ret;
@@ -1054,10 +1041,6 @@ static int mt_resume(struct hid_device *hdev)
 
 static void mt_remove(struct hid_device *hdev)
 {
-	//SiS FW update
-#ifdef CONFIG_HID_SIS_CTRL
-	sis_deinit_chardev();
-#endif	//CONFIG_HID_SIS_CTRL
 	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
 	hid_hw_stop(hdev);
 }
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.c b/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
deleted file mode 100644
index 2794b65..0000000
--- a/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- *  Character device driver for SIS multitouch panels control
- *
- *  Copyright (c) 2009 SIS, Ltd.
- *
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include "usbhid/usbhid.h"
-#include <linux/init.h>
-
-//update FW
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <asm/uaccess.h>	//copy_from_user() & copy_to_user()
-
-#include "hid-ids.h"
-#include "hid-sis_ctrl.h"
-
-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;
-
-static struct hid_device *hid_dev_backup = NULL;  //backup address
-static struct urb *backup_urb = NULL;
-
-#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
-	#define DBG_FW(fmt, arg...)	printk( fmt, ##arg )
-	void sis_dbg_dump_array( u8 *ptr, u32 size)
-	{
-		u32 i;
-		for (i=0; i<size; i++)  
-		{
-			DBG_FW ("%02X ", ptr[i]);
-			if( ((i+1)&0xF) == 0)
-				DBG_FW ("\n");
-		}
-		if( size & 0xF)
-			DBG_FW ("\n");
-	}
-#else
-	#define DBG_FW(...)
-	#define sis_dbg_dump_array(...)
-#endif	// CONFIG_DEBUG_HID_SIS_UPDATE_FW
-
-
-int sis_cdev_open(struct inode *inode, struct file *filp)	//20120306 Yuger ioctl for tool
-{
-	struct usbhid_device *usbhid; 
-
-	DBG_FW( "%s\n" , __FUNCTION__ );
-	//20110511, Yuger, kill current urb by method of usbhid_stop
-	if ( !hid_dev_backup )
-	{
-		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
-		return -1;
-	}
-
-	usbhid = hid_dev_backup->driver_data;
-
-	printk( KERN_INFO "sys_sis_HID_stop\n" );
-
-	//printk( KERN_INFO "hid_dev_backup->vendor, hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor, hid_dev_backup->product );
-
-	//20110602, Yuger, fix bug: not contact usb cause kernel panic
-	if( !usbhid )
-	{
-		printk( KERN_INFO "(stop)usbhid is not initialized yet" );
-		return -1;
-	}
-	else if ( !usbhid->urbin )
-	{
-		printk( KERN_INFO "(stop)usbhid->urbin is not initialized yet" );
-		return -1;
-	}
-	else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS2_TOUCH)
-	{
-		usb_fill_int_urb(backup_urb, usbhid->urbin->dev, usbhid->urbin->pipe,
-			usbhid->urbin->transfer_buffer, usbhid->urbin->transfer_buffer_length,
-			usbhid->urbin->complete, usbhid->urbin->context, usbhid->urbin->interval);
-
-                clear_bit( HID_STARTED, &usbhid->iofl );
-                set_bit( HID_DISCONNECTED, &usbhid->iofl );
-
-                usb_kill_urb( usbhid->urbin );
-                usb_free_urb( usbhid->urbin );
-                usbhid->urbin = NULL;
-		return 0;
-	}
-    else	
-	{
-		printk (KERN_INFO "This is not a SiS device");
-		return -801;
-	}
-}
-
-int sis_cdev_release(struct inode *inode, struct file *filp)
-{
-	//20110505, Yuger, rebuild the urb which is at the same urb address, then re-submit it
-
-	int ret;
-	struct usbhid_device *usbhid;
-	unsigned long flags;
-	
-	DBG_FW( "%s: " , __FUNCTION__ );
-	
-	if ( !hid_dev_backup )
-	{
-		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
-		return -1;
-	}
-
-	usbhid = hid_dev_backup->driver_data;
-
-	printk( KERN_INFO "sys_sis_HID_start" );
-
-	if( !usbhid )
-	{
-		printk( KERN_INFO "(start)usbhid is not initialized yet" );
-		return -1;
-	}
-
-	if( !backup_urb )
-	{
-		printk( KERN_INFO "(start)backup_urb is not initialized yet" );
-		return -1;
-	}
-
-	clear_bit( HID_DISCONNECTED, &usbhid->iofl );
-	usbhid->urbin = usb_alloc_urb( 0, GFP_KERNEL );
-
-	if( !backup_urb->interval )
-	{
-		printk( KERN_INFO "(start)backup_urb->interval does not exist" );
-		return -1;
-	}
-
-	usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe, 
-		backup_urb->transfer_buffer, backup_urb->transfer_buffer_length, 
-		backup_urb->complete, backup_urb->context, backup_urb->interval);
-	usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
-	usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	set_bit( HID_STARTED, &usbhid->iofl );
-
-	//method at hid_start_in
-	spin_lock_irqsave( &usbhid->lock, flags );		
-	ret = usb_submit_urb( usbhid->urbin, GFP_ATOMIC );
-	spin_unlock_irqrestore( &usbhid->lock, flags );
-	//yy
-
-	DBG_FW( "ret = %d", ret );
-
-	return ret;
-}
-
-//SiS 817 only
-ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-	int actual_length = 0, timeout = 0;
-	u8 *rep_data = NULL;
-	u16 size = 0;
-	long rep_ret;
-	struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent);
-	struct usb_device *dev = interface_to_usbdev(intf);
-
-	DBG_FW( "%s\n" , __FUNCTION__ );
-	
-	size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
-		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
-	timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
-		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
-
-	rep_data = kzalloc(size, GFP_KERNEL);
-	if (!rep_data)
-		return -12;
-
-	if ( copy_from_user( rep_data, (void*)buf, size) ) 
-	{
-		printk( KERN_INFO "copy_to_user fail\n" );
-		//free allocated data
-		kfree( rep_data );
-		rep_data = NULL;
-		return -19;
-	}
-
-	rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
-		rep_data, size, &actual_length, timeout);
-
-	DBG_FW( "%s: rep_data = ", __FUNCTION__);
-	sis_dbg_dump_array( rep_data, 8);
-		
-	if( rep_ret == 0 )
-	{
-		rep_ret = actual_length;
-		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
-		{
-			printk( KERN_INFO "copy_to_user fail\n" );
-			//free allocated data
-			kfree( rep_data );
-			rep_data = NULL;
-			return -19;
-		}
-	}
-
-	//free allocated data
-	kfree( rep_data );
-	rep_data = NULL;
-	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
-	return rep_ret;
-}
-
-ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
-{
-	int actual_length = 0;
-	u8 *rep_data = NULL;
-	long rep_ret;
-	struct usb_interface *intf = to_usb_interface( hid_dev_backup->dev.parent );
-	struct usb_device *dev = interface_to_usbdev( intf );
-	struct usbhid_device *usbhid = hid_dev_backup->driver_data;
-
-	u16 size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
-		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
-	int timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
-		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
-	
-	DBG_FW( "%s: 817 method, " , __FUNCTION__ );
-	DBG_FW("timeout = %d, size %d\n", timeout, size);
-
-	rep_data = kzalloc(size, GFP_KERNEL);
-	if (!rep_data)
-		return -12;
-
-	if ( copy_from_user( rep_data, (void*)buf, size) ) 
-	{
-		printk( KERN_INFO "copy_to_user fail\n" );
-		//free allocated data
-		kfree( rep_data );
-		rep_data = NULL;
-		return -19;
-	}
-
-	rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe,
-		rep_data, size, &actual_length, timeout );
-	
-	DBG_FW( "%s: rep_data = ", __FUNCTION__);
-	sis_dbg_dump_array( rep_data, size);
-	
-	if( rep_ret == 0 )
-	{
-		rep_ret = actual_length;
-		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
-		{
-			printk( KERN_INFO "copy_to_user fail\n" );
-			//free allocated data
-			kfree( rep_data );
-			rep_data = NULL;
-			return -19;
-		}
-	}
-	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
-	
-	//free allocated data
-	kfree( rep_data );
-	rep_data = NULL;
-
-	DBG_FW( "End of sys_sis_HID_IO\n" );
-	return rep_ret;
-}
-
-
-//for ioctl
-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,
-};
-
-//for ioctl
-int sis_setup_chardev(struct hid_device *hdev)
-{
-	
-	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");
-	hid_dev_backup = hdev;
-	
-	backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test
-	if (!backup_urb) {
-		dev_err(&hdev->dev, "cannot allocate backup_urb\n");
-		return -ENOMEM;
-	}
-/*	
-	if (nd == NULL) 
-	{
-          input_err = -ENOMEM;
-          goto error;
-	} 
-*/
-	// dynamic allocate driver handle
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SISF817_DEVICE_NAME);
-	else
-		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS817_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;
-
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		printk(KERN_INFO "%s driver(major %d) installed.\n", SISF817_DEVICE_NAME, sis_char_major);
-	else
-		printk(KERN_INFO "%s driver(major %d) installed.\n", SIS817_DEVICE_NAME, sis_char_major);
-
-	// register class
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		sis_char_class = class_create(THIS_MODULE, SISF817_DEVICE_NAME);
-	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
-		sis_char_class = class_create(THIS_MODULE, SIS817_DEVICE_NAME);
-
-	if(IS_ERR(ptr_err = sis_char_class)) 
-	{
-		goto err2;
-	}
-
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SISF817_DEVICE_NAME);
-	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
-		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS817_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;
-}
-EXPORT_SYMBOL(sis_setup_chardev);
-
-void sis_deinit_chardev(void)
-{
-	//for ioctl
-	dev_t dev;
-	printk(KERN_INFO "sis_remove\n");
-
-	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);
-	usb_kill_urb( backup_urb );
-	usb_free_urb( backup_urb );
-	backup_urb = NULL;
-	hid_dev_backup = NULL;
-	
-}
-EXPORT_SYMBOL(sis_deinit_chardev);
-
-MODULE_DESCRIPTION("SiS 817 Touchscreen Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.h b/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
deleted file mode 100644
index c7425c5..0000000
--- a/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __HID_SIS_CTRL_H__
-#define __HID_SIS_CTRL_H__
-
-#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
-#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
-
-#define CTRL 0
-#define ENDP_01 1
-#define ENDP_02 2
-#define DIR_IN 0x1
-
-int sis_cdev_open(struct inode *inode, struct file *filp);
-int sis_cdev_release(struct inode *inode, struct file *filp);
-ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
-ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos );
-int sis_setup_chardev(struct hid_device *hdev);
-void sis_deinit_chardev(void);
-
-#endif	// __HID_SIS_CTRL_H__

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

* [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver
@ 2015-01-09 10:38 ` 曾婷葳 (tammy_tseng)
  0 siblings, 0 replies; 13+ messages in thread
From: 曾婷葳 (tammy_tseng) @ 2015-01-09 10:38 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 hid multitouch driver is in hid.

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

diff --git a/linux-3.18.1/drivers/hid/Kconfig b/linux-3.18.1/drivers/hid/Kconfig
index 2be7677..f42df4d 100644
--- a/linux-3.18.1/drivers/hid/Kconfig
+++ b/linux-3.18.1/drivers/hid/Kconfig
@@ -494,35 +494,7 @@ config HID_MULTITOUCH
 	  If unsure, say N.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called hid-multitouch.  
-	  
-config HID_MT_DBG_POINT
-	bool "HID Multitouch panels debug for touch point"
-	depends on HID_MULTITOUCH
-	default n
-	---help---
-	  Show debug message for touch point information.
-
-config HID_MT_DBG_MAP_INIT
-	bool "HID Multitouch panels debug mapping initial"
-	depends on HID_MULTITOUCH
-	default n
-	---help---
-	  Show debug message for mapping initial information.  
-
-config HID_SIS_CTRL
-	tristate "SiS Touch Device Controller"
-	depends on HID_MULTITOUCH
-	---help---
-	Support for SiS Touch devices update FW.
-
-config DEBUG_HID_SIS_UPDATE_FW
-	bool "SiS Touch device debug message(update firmware)"
-	depends on HID_SIS_CTRL
-	default n
-	---help---
-	  Say Y here if you want to enable debug message(update firmware) for SiS Touch 
-          devices. Must enable config HID_SIS_UPDATE_FW first.
+	  module will be called hid-multitouch.
 
 config HID_NTRIG
 	tristate "N-Trig touch screen"
diff --git a/linux-3.18.1/drivers/hid/Makefile b/linux-3.18.1/drivers/hid/Makefile
index 02dc20d..e2850d8 100644
--- a/linux-3.18.1/drivers/hid/Makefile
+++ b/linux-3.18.1/drivers/hid/Makefile
@@ -33,7 +33,6 @@ ifdef CONFIG_DEBUG_FS
 	hid-wiimote-y	+= hid-wiimote-debug.o
 endif
 
-obj-$(CONFIG_HID_SIS_CTRL)	+= hid-sis_ctrl.o
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
 obj-$(CONFIG_HID_ACRUX)		+= hid-axff.o
 obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
diff --git a/linux-3.18.1/drivers/hid/hid-ids.h b/linux-3.18.1/drivers/hid/hid-ids.h
index c598e8d..7c86373 100644
--- a/linux-3.18.1/drivers/hid/hid-ids.h
+++ b/linux-3.18.1/drivers/hid/hid-ids.h
@@ -807,7 +807,6 @@
 #define USB_VENDOR_ID_SIS_TOUCH		0x0457
 #define USB_DEVICE_ID_SIS9200_TOUCH	0x9200
 #define USB_DEVICE_ID_SIS817_TOUCH	0x0817
-#define USB_PRODUCT_ID_SISF817_TOUCH	0xF817
 #define USB_DEVICE_ID_SIS_TS		0x1013
 #define USB_DEVICE_ID_SIS1030_TOUCH	0x1030
 
diff --git a/linux-3.18.1/drivers/hid/hid-multitouch.c b/linux-3.18.1/drivers/hid/hid-multitouch.c
index 31e28dd..51e25b9 100644
--- a/linux-3.18.1/drivers/hid/hid-multitouch.c
+++ b/linux-3.18.1/drivers/hid/hid-multitouch.c
@@ -45,7 +45,7 @@
 #include <linux/usb.h>
 #include <linux/input/mt.h>
 #include <linux/string.h>
-#include "hid-sis_ctrl.h"
+
 
 MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
@@ -1003,19 +1003,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (ret != 0)
 		return ret;
 
-	//SiS set noget for not init reports
-	hdev->quirks |= HID_QUIRK_NOGET;
-	printk(KERN_INFO "sis:sis-probe: quirk = %x\n", hdev->quirks);
-
-	//SiS FW update
-#ifdef CONFIG_HID_SIS_CTRL
-	ret = sis_setup_chardev(hdev);
-	if(ret)
-	{
-		printk( KERN_INFO "sis_setup_chardev fail\n");
-	}
-#endif	//CONFIG_HID_SIS_CTRL
-
 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 	if (ret)
 		return ret;
@@ -1054,10 +1041,6 @@ static int mt_resume(struct hid_device *hdev)
 
 static void mt_remove(struct hid_device *hdev)
 {
-	//SiS FW update
-#ifdef CONFIG_HID_SIS_CTRL
-	sis_deinit_chardev();
-#endif	//CONFIG_HID_SIS_CTRL
 	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
 	hid_hw_stop(hdev);
 }
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.c b/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
deleted file mode 100644
index 2794b65..0000000
--- a/linux-3.18.1/drivers/hid/hid-sis_ctrl.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- *  Character device driver for SIS multitouch panels control
- *
- *  Copyright (c) 2009 SIS, Ltd.
- *
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include "usbhid/usbhid.h"
-#include <linux/init.h>
-
-//update FW
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <asm/uaccess.h>	//copy_from_user() & copy_to_user()
-
-#include "hid-ids.h"
-#include "hid-sis_ctrl.h"
-
-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;
-
-static struct hid_device *hid_dev_backup = NULL;  //backup address
-static struct urb *backup_urb = NULL;
-
-#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
-	#define DBG_FW(fmt, arg...)	printk( fmt, ##arg )
-	void sis_dbg_dump_array( u8 *ptr, u32 size)
-	{
-		u32 i;
-		for (i=0; i<size; i++)  
-		{
-			DBG_FW ("%02X ", ptr[i]);
-			if( ((i+1)&0xF) == 0)
-				DBG_FW ("\n");
-		}
-		if( size & 0xF)
-			DBG_FW ("\n");
-	}
-#else
-	#define DBG_FW(...)
-	#define sis_dbg_dump_array(...)
-#endif	// CONFIG_DEBUG_HID_SIS_UPDATE_FW
-
-
-int sis_cdev_open(struct inode *inode, struct file *filp)	//20120306 Yuger ioctl for tool
-{
-	struct usbhid_device *usbhid; 
-
-	DBG_FW( "%s\n" , __FUNCTION__ );
-	//20110511, Yuger, kill current urb by method of usbhid_stop
-	if ( !hid_dev_backup )
-	{
-		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
-		return -1;
-	}
-
-	usbhid = hid_dev_backup->driver_data;
-
-	printk( KERN_INFO "sys_sis_HID_stop\n" );
-
-	//printk( KERN_INFO "hid_dev_backup->vendor, hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor, hid_dev_backup->product );
-
-	//20110602, Yuger, fix bug: not contact usb cause kernel panic
-	if( !usbhid )
-	{
-		printk( KERN_INFO "(stop)usbhid is not initialized yet" );
-		return -1;
-	}
-	else if ( !usbhid->urbin )
-	{
-		printk( KERN_INFO "(stop)usbhid->urbin is not initialized yet" );
-		return -1;
-	}
-	else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS2_TOUCH)
-	{
-		usb_fill_int_urb(backup_urb, usbhid->urbin->dev, usbhid->urbin->pipe,
-			usbhid->urbin->transfer_buffer, usbhid->urbin->transfer_buffer_length,
-			usbhid->urbin->complete, usbhid->urbin->context, usbhid->urbin->interval);
-
-                clear_bit( HID_STARTED, &usbhid->iofl );
-                set_bit( HID_DISCONNECTED, &usbhid->iofl );
-
-                usb_kill_urb( usbhid->urbin );
-                usb_free_urb( usbhid->urbin );
-                usbhid->urbin = NULL;
-		return 0;
-	}
-    else	
-	{
-		printk (KERN_INFO "This is not a SiS device");
-		return -801;
-	}
-}
-
-int sis_cdev_release(struct inode *inode, struct file *filp)
-{
-	//20110505, Yuger, rebuild the urb which is at the same urb address, then re-submit it
-
-	int ret;
-	struct usbhid_device *usbhid;
-	unsigned long flags;
-	
-	DBG_FW( "%s: " , __FUNCTION__ );
-	
-	if ( !hid_dev_backup )
-	{
-		printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
-		return -1;
-	}
-
-	usbhid = hid_dev_backup->driver_data;
-
-	printk( KERN_INFO "sys_sis_HID_start" );
-
-	if( !usbhid )
-	{
-		printk( KERN_INFO "(start)usbhid is not initialized yet" );
-		return -1;
-	}
-
-	if( !backup_urb )
-	{
-		printk( KERN_INFO "(start)backup_urb is not initialized yet" );
-		return -1;
-	}
-
-	clear_bit( HID_DISCONNECTED, &usbhid->iofl );
-	usbhid->urbin = usb_alloc_urb( 0, GFP_KERNEL );
-
-	if( !backup_urb->interval )
-	{
-		printk( KERN_INFO "(start)backup_urb->interval does not exist" );
-		return -1;
-	}
-
-	usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe, 
-		backup_urb->transfer_buffer, backup_urb->transfer_buffer_length, 
-		backup_urb->complete, backup_urb->context, backup_urb->interval);
-	usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
-	usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	set_bit( HID_STARTED, &usbhid->iofl );
-
-	//method at hid_start_in
-	spin_lock_irqsave( &usbhid->lock, flags );		
-	ret = usb_submit_urb( usbhid->urbin, GFP_ATOMIC );
-	spin_unlock_irqrestore( &usbhid->lock, flags );
-	//yy
-
-	DBG_FW( "ret = %d", ret );
-
-	return ret;
-}
-
-//SiS 817 only
-ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-	int actual_length = 0, timeout = 0;
-	u8 *rep_data = NULL;
-	u16 size = 0;
-	long rep_ret;
-	struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent);
-	struct usb_device *dev = interface_to_usbdev(intf);
-
-	DBG_FW( "%s\n" , __FUNCTION__ );
-	
-	size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
-		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
-	timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
-		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
-
-	rep_data = kzalloc(size, GFP_KERNEL);
-	if (!rep_data)
-		return -12;
-
-	if ( copy_from_user( rep_data, (void*)buf, size) ) 
-	{
-		printk( KERN_INFO "copy_to_user fail\n" );
-		//free allocated data
-		kfree( rep_data );
-		rep_data = NULL;
-		return -19;
-	}
-
-	rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
-		rep_data, size, &actual_length, timeout);
-
-	DBG_FW( "%s: rep_data = ", __FUNCTION__);
-	sis_dbg_dump_array( rep_data, 8);
-		
-	if( rep_ret == 0 )
-	{
-		rep_ret = actual_length;
-		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
-		{
-			printk( KERN_INFO "copy_to_user fail\n" );
-			//free allocated data
-			kfree( rep_data );
-			rep_data = NULL;
-			return -19;
-		}
-	}
-
-	//free allocated data
-	kfree( rep_data );
-	rep_data = NULL;
-	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
-	return rep_ret;
-}
-
-ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
-{
-	int actual_length = 0;
-	u8 *rep_data = NULL;
-	long rep_ret;
-	struct usb_interface *intf = to_usb_interface( hid_dev_backup->dev.parent );
-	struct usb_device *dev = interface_to_usbdev( intf );
-	struct usbhid_device *usbhid = hid_dev_backup->driver_data;
-
-	u16 size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + 
-		(((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff);
-	int timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + 
-		(((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff);
-	
-	DBG_FW( "%s: 817 method, " , __FUNCTION__ );
-	DBG_FW("timeout = %d, size %d\n", timeout, size);
-
-	rep_data = kzalloc(size, GFP_KERNEL);
-	if (!rep_data)
-		return -12;
-
-	if ( copy_from_user( rep_data, (void*)buf, size) ) 
-	{
-		printk( KERN_INFO "copy_to_user fail\n" );
-		//free allocated data
-		kfree( rep_data );
-		rep_data = NULL;
-		return -19;
-	}
-
-	rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe,
-		rep_data, size, &actual_length, timeout );
-	
-	DBG_FW( "%s: rep_data = ", __FUNCTION__);
-	sis_dbg_dump_array( rep_data, size);
-	
-	if( rep_ret == 0 )
-	{
-		rep_ret = actual_length;
-		if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) 
-		{
-			printk( KERN_INFO "copy_to_user fail\n" );
-			//free allocated data
-			kfree( rep_data );
-			rep_data = NULL;
-			return -19;
-		}
-	}
-	DBG_FW( "%s: rep_ret = %ld\n", __FUNCTION__,rep_ret );
-	
-	//free allocated data
-	kfree( rep_data );
-	rep_data = NULL;
-
-	DBG_FW( "End of sys_sis_HID_IO\n" );
-	return rep_ret;
-}
-
-
-//for ioctl
-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,
-};
-
-//for ioctl
-int sis_setup_chardev(struct hid_device *hdev)
-{
-	
-	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");
-	hid_dev_backup = hdev;
-	
-	backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test
-	if (!backup_urb) {
-		dev_err(&hdev->dev, "cannot allocate backup_urb\n");
-		return -ENOMEM;
-	}
-/*	
-	if (nd == NULL) 
-	{
-          input_err = -ENOMEM;
-          goto error;
-	} 
-*/
-	// dynamic allocate driver handle
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SISF817_DEVICE_NAME);
-	else
-		alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS817_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;
-
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		printk(KERN_INFO "%s driver(major %d) installed.\n", SISF817_DEVICE_NAME, sis_char_major);
-	else
-		printk(KERN_INFO "%s driver(major %d) installed.\n", SIS817_DEVICE_NAME, sis_char_major);
-
-	// register class
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		sis_char_class = class_create(THIS_MODULE, SISF817_DEVICE_NAME);
-	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
-		sis_char_class = class_create(THIS_MODULE, SIS817_DEVICE_NAME);
-
-	if(IS_ERR(ptr_err = sis_char_class)) 
-	{
-		goto err2;
-	}
-
-	if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
-		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SISF817_DEVICE_NAME);
-	else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
-		class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS817_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;
-}
-EXPORT_SYMBOL(sis_setup_chardev);
-
-void sis_deinit_chardev(void)
-{
-	//for ioctl
-	dev_t dev;
-	printk(KERN_INFO "sis_remove\n");
-
-	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);
-	usb_kill_urb( backup_urb );
-	usb_free_urb( backup_urb );
-	backup_urb = NULL;
-	hid_dev_backup = NULL;
-	
-}
-EXPORT_SYMBOL(sis_deinit_chardev);
-
-MODULE_DESCRIPTION("SiS 817 Touchscreen Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/linux-3.18.1/drivers/hid/hid-sis_ctrl.h b/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
deleted file mode 100644
index c7425c5..0000000
--- a/linux-3.18.1/drivers/hid/hid-sis_ctrl.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __HID_SIS_CTRL_H__
-#define __HID_SIS_CTRL_H__
-
-#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
-#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
-
-#define CTRL 0
-#define ENDP_01 1
-#define ENDP_02 2
-#define DIR_IN 0x1
-
-int sis_cdev_open(struct inode *inode, struct file *filp);
-int sis_cdev_release(struct inode *inode, struct file *filp);
-ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
-ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos );
-int sis_setup_chardev(struct hid_device *hdev);
-void sis_deinit_chardev(void);
-
-#endif	// __HID_SIS_CTRL_H__

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

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

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-12 10:55 [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver 曾婷葳 (tammy_tseng)
2015-01-12 10:55 ` 曾婷葳 (tammy_tseng)
  -- strict thread matches above, loose matches on Subject: below --
2015-02-12  7:24 曾婷葳 (tammy_tseng)
2015-02-12  7:24 ` 曾婷葳 (tammy_tseng)
2015-02-16 15:10 ` Oliver Neukum
2015-02-16 15:10   ` Oliver Neukum
2015-02-16 15:36   ` Benjamin Tissoires
     [not found] <8322374EB97AA24A95D0DDBFC8F1CA1DCB07FA@SISMBEV01.sis.com.tw>
2015-02-12  7:03 ` Dmitry Torokhov
2015-02-12  7:03   ` Dmitry Torokhov
2015-02-12  7:16   ` 曾婷葳 (tammy_tseng)
2015-02-12  7:16     ` 曾婷葳 (tammy_tseng)
2015-01-09 10:38 曾婷葳 (tammy_tseng)
2015-01-09 10:38 ` 曾婷葳 (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.