summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c')
-rwxr-xr-xdrivers/input/touchscreen/sis_usbhid_ts/hid-sis.c1104
1 files changed, 1104 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c b/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c
new file mode 100755
index 00000000..0b9cee3d
--- /dev/null
+++ b/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c
@@ -0,0 +1,1104 @@
+/*
+ * HID driver for sis 9237/9257 test touchscreens
+ *
+ * Copyright (c) 2008 Rafi Rubin
+ * Copyright (c) 2009 Stephane Chatty
+ *
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/hid-debug.h>
+//for i2c-bridge
+#include <linux/usb.h>
+#include "../../../hid/usbhid/usbhid.h"
+#include <asm/uaccess.h>
+#include <linux/types.h>
+
+#ifdef CONFIG_HID_SIS_UPDATE_FW
+//for ioctl
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+
+#define INTERNAL_DEVICE_NAME "sis_zeus_hid_touch_device"
+#define BRIDGE_DEVICE_NAME "sis_zeus_hid_bridge_touch_device"
+#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device"
+#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_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;
+//20110111 Tammy system call for tool
+static struct hid_device *hid_dev_backup = NULL; //backup address
+static struct urb *backup_urb = NULL;
+#endif //CONFIG_HID_SIS_UPDATE_FW
+
+///////////////// SIS START /////////////////
+#define USB_VENDOR_ID_SIS_TOUCH 0x1039
+#define USB_VENDOR_ID_SIS2_TOUCH 0x0457
+#define USB_PRODUCT_ID_SIS_TOUCH 0x0810
+#define USB_PRODUCT_ID_SIS2_TOUCH 0x0151
+#define USB_PRODUCT_ID_NEW_SIS2_TOUCH 0x0816
+#define USB_PRODUCT_ID_SIS9200_TOUCH 0x9200
+#define USB_PRODUCT_ID_SIS817_TOUCH 0x0817
+#define USB_PRODUCT_ID_SISF817_TOUCH 0xF817
+
+//waltop id-table
+#define USB_VENUS_ID_WALTOP 0x0503
+#define USB_VENUS_ID_WALTOP2 0x1040
+///////////////// SIS END /////////////////
+//#define CONFIG_HID_SIS_UPDATE_FW
+//#define CONFIG_DEBUG_HID_SIS_INIT
+//#define CONFIG_DEBUG_HID_SIS_SENDPOINT
+
+#define MAX_X 4095
+#define MAX_Y 4095
+//#define MAX_PRESSURE 2047
+#define MAX_SCANTIME 65535
+#define MAX_CONTACTID 31
+
+#define MAX_POINT 10
+#define HID_DG_SCANTIME 0x000d0056 //new usage not defined in hid.h
+#define REPORTID_10 0x10
+#define REPORTID_TYPE1 0x30
+
+#define CTRL 0
+#define DIR_IN 0x1
+
+struct Point {
+ u16 x, y, id, pressure, width, height;
+};
+
+struct sis_data {
+ int id, total, ReportID, scantime;
+ struct Point pt[MAX_POINT];
+};
+
+
+static int pkg_num=0;
+static int idx=-1;
+
+/*
+ * this driver is aimed at two firmware versions in circulation:
+ * - dual pen/fingedrivers/hid/hid-sis.c:83:r single touch
+ * - finger multitouch, pen not working
+ */
+
+static int sis_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ // No special mappings needed for the pen and single touch
+ if (field->physical == HID_GD_POINTER)
+ return -1;
+
+ else if (field->physical && (field->physical != HID_GD_POINTER))
+ return 0;
+
+#ifdef CONFIG_DEBUG_HID_SIS_INIT
+ printk (KERN_INFO "sis_input_mapping : usage->hid = %x\n", usage->hid);
+#endif //CONFIG_DEBUG_HID_SIS_INIT
+
+ switch (usage->hid & HID_USAGE_PAGE) {
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X);
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum, field->logical_maximum, 0, 0);
+ return 1;
+
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y);
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum, field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ /* we do not want to map these for now */
+ case HID_DG_CONFIDENCE:
+ case HID_DG_INPUTMODE:
+ case HID_DG_DEVICEINDEX:
+ case HID_DG_CONTACTCOUNT:
+ case HID_DG_CONTACTMAX:
+ case HID_DG_INRANGE:
+
+ //new usage for SiS817 Device(for later use)
+ case HID_DG_WIDTH:
+ //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR);
+ //input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
+ //return 1;
+ case HID_DG_HEIGHT:
+ //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR);
+ //input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ //return 1;
+ case HID_DG_TIPPRESSURE:
+ //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE);
+ //input_set_abs_params(hi->input, ABS_MT_PRESSURE, 0, 2047, 0, 0);
+ //return 1;
+ case HID_DG_SCANTIME:
+ return -1;
+
+ case HID_DG_TIPSWITCH:
+ hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE);
+ input_set_abs_params(hi->input, ABS_MT_PRESSURE, 0, 1, 0, 0);
+ return 1;
+
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TRACKING_ID);
+ input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, 0, 127, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ /*case HID_UP_BUTTON:
+ return 0;*/
+
+ case 0xff000000:
+ /* ignore HID features */
+ return -1;
+
+ }
+ /* ignore buttons */
+ return 0;
+}
+
+//sis_input_mapped : unmapped usage that no use in sis_event
+static int sis_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+#ifdef CONFIG_DEBUG_HID_SIS_INIT
+ printk (KERN_INFO "sis_input_mapping : usage->hid = %x\n", usage->hid);
+#endif //CONFIG_DEBUG_HID_SIS_INIT
+
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+static void sis_event_emission(struct sis_data *nd, struct input_dev *input)
+{
+ int i;
+ bool all_touch_up = true;
+ for(i=0; i< nd->total; i++)
+ {
+
+#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT
+ printk(KERN_INFO "MT_event: finger(s)=%d, id=%d, x=%d, y=%d\n", nd->total, nd->pt[i].id, nd->pt[i].x, nd->pt[i].y);
+ printk(KERN_INFO "MT_event: pressure=%d, width=%d, height=%d, scantime=%d\n", nd->pt[i].pressure, nd->pt[i].width, nd->pt[i].height, nd->scantime);
+#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT
+
+ //checking correction of data
+ if(nd->pt[i].x > MAX_X || nd->pt[i].y > MAX_Y || nd->pt[i].id > MAX_CONTACTID /*|| nd->scantime > MAX_SCANTIME*/)
+ {
+ printk(KERN_INFO "point data error : abort sending point this time");
+ break;
+ }
+
+ if(nd->pt[i].pressure)
+ {
+ //input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(nd->pt[i].height,nd->pt[i].width));
+ //input_report_abs(input, ABS_MT_TOUCH_MINOR, min(nd->pt[i].height,nd->pt[i].width));
+
+ input_report_abs(input, ABS_MT_PRESSURE, nd->pt[i].pressure);
+ input_report_abs(input, ABS_MT_POSITION_X, MAX_Y - nd->pt[i].y);
+ input_report_abs(input, ABS_MT_POSITION_Y, nd->pt[i].x);
+ input_report_abs(input, ABS_MT_TRACKING_ID, nd->pt[i].id);
+ input_mt_sync(input);
+ all_touch_up = false;
+ }
+
+ if(i == (nd->total - 1) && all_touch_up == true)
+ input_mt_sync(input);
+ }
+ //input_sync(input);
+ //input_sync will be send by hid default flow
+}
+
+static void sis_event_clear(struct sis_data *nd, int max)
+{
+ int i;
+ for(i=0; i<max; i++)
+ {
+ nd->pt[i].id = 0;
+ nd->pt[i].x = 0;
+ nd->pt[i].y = 0;
+ nd->pt[i].pressure = 0;
+ nd->pt[i].width = 0;
+ nd->pt[i].height = 0;
+ }
+ nd->scantime = 0;
+ idx = -1;
+ pkg_num = 0;
+}
+
+static int sis_raw_event (struct hid_device *hid, struct hid_report *report,
+ u8 *raw_data, int size)
+{
+ struct sis_data *nd = hid_get_drvdata(hid);
+ nd->ReportID = raw_data[0];
+
+#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT
+ printk(KERN_INFO "raw_event : ReportID = %d\n", nd->ReportID);
+#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT
+
+ hid_set_drvdata(hid, nd);
+ return 0;
+}
+
+static void sis_event_lastdata(struct hid_device *hid, struct sis_data *nd, struct input_dev *input)
+{
+ int pkg_n=0;
+
+//817 method : original format
+ if ( (hid->product == USB_PRODUCT_ID_SIS817_TOUCH || hid->product == USB_PRODUCT_ID_SISF817_TOUCH) && nd->ReportID == REPORTID_10)
+ {
+#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT
+ printk (KERN_INFO "sis_event_lastdata : 817 original format\n");
+#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT
+
+ sis_event_emission(nd, input);
+ sis_event_clear(nd, MAX_POINT);
+ }
+ //817 method : Extend Class Format
+ else if ( (hid->product == USB_PRODUCT_ID_SIS817_TOUCH || hid->product == USB_PRODUCT_ID_SISF817_TOUCH) && nd->ReportID != REPORTID_10)
+ {
+#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT
+ printk (KERN_INFO "sis_event_lastdata : 817 extend format\n");
+#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT
+
+ if(nd->total >= 6)
+ {
+ idx = 4;
+ pkg_num = nd->total;
+ }
+ else if(nd->total >= 1)
+ {
+ sis_event_emission(nd, input);
+ sis_event_clear(nd, MAX_POINT);
+ }
+ else
+ {
+ if(pkg_num >0)
+ {
+ nd->total = pkg_num;
+ sis_event_emission(nd, input);
+ pkg_n = 0;
+ sis_event_clear(nd, MAX_POINT);
+ }
+ else
+ {
+ sis_event_clear(nd, MAX_POINT);
+ }
+ }
+ }
+ else //816 method
+ {
+#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT
+ printk (KERN_INFO "sis_event_lastdata : 816 format\n");
+#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT
+
+ if(nd->total >= 3)
+ {
+ idx = 1;
+ pkg_num = nd->total;
+ }
+ else if(nd->total >= 1)
+ {
+ sis_event_emission(nd, input);
+ sis_event_clear(nd, MAX_POINT);
+ }
+ else
+ {
+ if(pkg_num >0)
+ {
+ if((pkg_num%2)>0)
+ pkg_n = pkg_num+1;
+ else
+ pkg_n = pkg_num;
+
+ if(pkg_n == (idx + 1) )
+ {
+ nd->total = pkg_num;
+ sis_event_emission(nd, input);
+ pkg_n = 0;
+ sis_event_clear(nd, MAX_POINT);
+ }
+ }
+ else
+ {
+ sis_event_clear(nd, MAX_POINT);
+ }
+ }
+ }
+}
+/*
+ * this function is called upon all reports
+ * so that we can filter contact point information,
+ * decide whether we are in multi or single touch mode
+ * and call input_mt_sync after each point if necessary
+ */
+static int sis_event (struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct sis_data *nd = hid_get_drvdata(hid);
+ //printk (KERN_INFO "sis_event");
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT
+ printk (KERN_INFO "sis_event : usage->hid = %x, value = %d\n", usage->hid, value);
+#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ break;
+
+ case HID_DG_TIPSWITCH:
+ idx++;
+ nd->pt[idx].pressure = !!value;
+ break;
+
+ case HID_DG_CONTACTID:
+ nd->pt[idx].id = value;
+ break;
+
+ case HID_GD_X:
+ nd->pt[idx].x = value;
+ break;
+
+ case HID_GD_Y:
+ nd->pt[idx].y = value;
+ break;
+
+ //new usage for SiS817 Extend Class Device
+ case HID_DG_SCANTIME:
+ nd->scantime = value;
+ if ( (nd->ReportID & 0xf0) > REPORTID_TYPE1 )
+ sis_event_lastdata(hid, nd, input);
+ break;
+
+ case HID_DG_WIDTH:
+ nd->pt[idx].width = value;
+ break;
+
+ case HID_DG_HEIGHT:
+ nd->pt[idx].height = value;
+ break;
+
+ case HID_DG_TIPPRESSURE:
+ nd->pt[idx].pressure = value;
+ break;
+ //end of new usage for SiS817 Extend Class Device
+
+ case HID_DG_CONTACTCOUNT:
+ nd->total = value;
+ if ( (nd->ReportID & 0xf0) <= REPORTID_TYPE1 )
+ sis_event_lastdata(hid, nd, input);
+ break;
+ default:
+ //fallback to the generic hidinput handling
+ return 0;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+#ifdef CONFIG_HID_SIS_UPDATE_FW
+int sis_cdev_open(struct inode *inode, struct file *filp) //20120306 Yuger ioctl for tool
+{
+ //20110511, Yuger, kill current urb by method of usbhid_stop
+ struct usbhid_device *usbhid;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_open\n" );
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ if ( !hid_dev_backup )
+ {
+ printk( KERN_INFO "sis_cdev_open : hid_dev_backup is not initialized yet" );
+ return -1;
+ }
+
+ usbhid = hid_dev_backup->driver_data;
+
+ //20110602, Yuger, fix bug: not contact usb cause kernel panic
+ if( !usbhid )
+ {
+ printk( KERN_INFO "sis_cdev_open : usbhid is not initialized yet" );
+ return -1;
+ }
+ else if ( !usbhid->urbin )
+ {
+ printk( KERN_INFO "sis_cdev_open : 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;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_release" );
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ if ( !hid_dev_backup )
+ {
+ printk( KERN_INFO "sis_cdev_release : 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 "sis_cdev_release : usbhid is not initialized yet" );
+ return -1;
+ }
+
+ if( !backup_urb )
+ {
+ printk( KERN_INFO "sis_cdev_release : urb_backup 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 "sis_cdev_release : urb_backup->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
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_release : ret = %d", ret );
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ 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);
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_read\n");
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ 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);
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk(KERN_INFO "sis_cdev_read : rep_data = ");
+ for (i=0; i<8; i++)
+ {
+ printk ("%02X ", rep_data[i]);
+ }
+ printk ("\n");
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ 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;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_read : rep_ret = %ld\n", rep_ret );
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ return rep_ret;
+}
+
+ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos )
+{
+ int i, actual_length = 0;
+ u8 *tmp_data = NULL; //include report id
+ 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;
+
+ if ( hid_dev_backup->product == USB_PRODUCT_ID_SIS817_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_SISF817_TOUCH ) //817 method
+ {
+ 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);
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_write : 817 method\n");
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ 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 );
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk(KERN_INFO "sis_cdev_write : rep_data = ");
+ for (i=0; i<size-1; i++)
+ {
+ printk ("%02X ", rep_data[i]);
+ }
+ if (i == size-1)
+ printk ("%02X\n", rep_data[i]);
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ 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;
+ }
+ }
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_write : rep_ret = %ld\n", rep_ret );
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ }
+ else //816 method
+ {
+
+ u8 request = buf[0];
+ u8 dir = buf[1];
+ u16 value = (((u16)(buf[2] & 0xff)) << 24) + (((u16)(buf[3] & 0xff)) << 16) + (((u16)(buf[4] & 0xff)) << 8) + (u16)(buf[5] & 0xff);
+ u16 index = (((u16)(buf[6] & 0xff)) << 24) + (((u16)(buf[7] & 0xff)) << 16) + (((u16)(buf[8] & 0xff)) << 8) + (u16)(buf[9] & 0xff);
+
+
+ u16 size = (((u16)(buf[29] & 0xff)) << 24) + (((u16)(buf[30] & 0xff)) << 16) + (((u16)(buf[31] & 0xff)) << 8) + (u16)(buf[32] & 0xff);
+ int timeout = (((int)(buf[33] & 0xff)) << 24) + (((int)(buf[34] & 0xff)) << 16) + (((int)(buf[35] & 0xff)) << 8) + (int)(buf[36] & 0xff);
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "sis_cdev_write : 816 method\n");
+ printk (KERN_INFO "dir = %d, value = %d, index = %d, timeout = %d\n", dir, value, index, timeout);
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ rep_data = kzalloc( size , GFP_KERNEL );
+ if ( rep_data == 0 )
+ {
+ return -12;
+ }
+
+ for( i = 0; i < size; i++)
+ {
+ rep_data[i] = buf[10+i];
+ }
+
+ tmp_data = kzalloc( size + 1, GFP_KERNEL ); //include report id, so size +1
+
+ for( i = 0; i < size; i++ )
+ {
+ tmp_data[i+1] = rep_data[i];
+ }
+
+ buf += 10;
+
+ if( dir & DIR_IN )
+ {
+ if ( hid_dev_backup->product == USB_PRODUCT_ID_SIS2_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_NEW_SIS2_TOUCH )
+ {
+ //20110510, Yuger, for correcting intr data send into interrupt msg(receive, in, endp=2)
+ tmp_data[0] = 0x0A;//in
+
+ rep_ret = usb_interrupt_msg( dev, backup_urb->pipe, tmp_data, size+1, &actual_length, timeout );
+ //yy
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk(KERN_INFO "(INT_IN)rep_ret = %ld, actual_length = %d", rep_ret, actual_length);
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ if( rep_ret == 0 )
+ {
+ rep_ret = actual_length;
+ }
+
+ //20110510, Yuger, for recovering rep_data
+ for( i = 0; i < size; i++ )
+ {
+ rep_data[i] = tmp_data[i+1];
+ }
+ //yy
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk(KERN_INFO "(INT_IN)size = %u, dir = %u, rep_ret = %ld, rep_data = %X %X %X", size, dir, rep_ret, rep_data[0], rep_data[1], rep_data[2]);
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ if ( copy_to_user( (void*)buf, rep_data, rep_ret ) )
+ {
+ printk( KERN_INFO "copy_to_user fail\n" );
+ //free allocated data
+ kfree( rep_data );
+ kfree( tmp_data );
+ rep_data = NULL;
+ tmp_data = NULL;
+ return -19;
+ }
+ }
+ else
+ {
+ //control message
+ rep_ret = usb_control_msg( dev, usb_rcvctrlpipe( dev, CTRL ),
+ request, (USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE),
+ value, index, rep_data, size, timeout );
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk ("(CTRL) size = %d, dir = %d, rep_ret = %ld, rep_data = ", size, dir, rep_ret);
+ for (i=0; i<size-1; i++)
+ {
+ printk ("%02X ", rep_data[i]);
+ }
+ if (i == size-1)
+ printk ("%02X\n", rep_data[i]);
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ 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;
+ }
+ }
+ }
+ else
+ {
+ if ( hid_dev_backup->product == USB_PRODUCT_ID_SIS2_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_NEW_SIS2_TOUCH )
+ {
+ //20110510, Yuger, for correcting intr data send into interrupt msg(send, out, endp=1)
+ tmp_data[0] = 0x09;//out
+
+ rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe, tmp_data, size + 1, &actual_length, timeout );
+
+ //just return success or not(no need to return actual_length if succeed)
+
+ //20110510, Yuger, for recovering rep_data
+ for( i = 0; i < size; i++ )
+ {
+ rep_data[i] = tmp_data[i+1];
+ }
+ //yy
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk(KERN_INFO "(INT_OUT)size = %u, actual_length = %d, rep_ret = %ld, rep_data = %x %x %x", size, actual_length, rep_ret, rep_data[0], rep_data[1], rep_data[2]);
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ if ( copy_to_user( (void*)buf, rep_data, actual_length-1 ) )
+ {
+ printk( KERN_INFO "copy_to_user fail\n" );
+ //free allocated data
+ kfree( rep_data );
+ kfree( tmp_data );
+ rep_data = NULL;
+ tmp_data = NULL;
+ return -19;
+ }
+ }
+ else
+ {
+ //control message
+ rep_ret = usb_control_msg( dev, usb_sndctrlpipe( dev, CTRL ),
+ request, (USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE),
+ value, index, rep_data, 16, timeout );
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk ("(CTRL) size = %d, dir = %d, rep_ret = %ld, rep_data = ", size, dir, rep_ret);
+ for (i=0; i<size-1; i++)
+ {
+ printk ("%02X ", rep_data[i]);
+ }
+ if (i == size-1)
+ printk ("%02X\n", rep_data[i]);
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ 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( tmp_data );
+ tmp_data = NULL;
+ }
+ //free allocated data
+ kfree( rep_data );
+ rep_data = NULL;
+
+#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
+ printk( KERN_INFO "End of sis_cdev_write\n" );
+#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW
+
+ return rep_ret;
+}
+
+//~TT
+
+//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, struct sis_data *nd)
+{
+
+ 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 (nd == NULL)
+ {
+ input_err = -ENOMEM;
+ goto error;
+ }
+
+ // dynamic allocate driver handle
+ if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH)
+ alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, BRIDGE_DEVICE_NAME);
+ else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
+ alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS817_DEVICE_NAME);
+ else 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, INTERNAL_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_SIS9200_TOUCH)
+ printk(KERN_INFO "%s driver(major %d) installed.\n", BRIDGE_DEVICE_NAME, sis_char_major);
+ else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
+ printk(KERN_INFO "%s driver(major %d) installed.\n", SIS817_DEVICE_NAME, sis_char_major);
+ else 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", INTERNAL_DEVICE_NAME, sis_char_major);
+
+ // register class
+ if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH)
+ sis_char_class = class_create(THIS_MODULE, BRIDGE_DEVICE_NAME);
+ else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH)
+ sis_char_class = class_create(THIS_MODULE, SIS817_DEVICE_NAME);
+ else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH)
+ sis_char_class = class_create(THIS_MODULE, SISF817_DEVICE_NAME);
+ else
+ sis_char_class = class_create(THIS_MODULE, INTERNAL_DEVICE_NAME);
+
+ if(IS_ERR(ptr_err = sis_char_class))
+ {
+ goto err2;
+ }
+
+ if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH)
+ class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, BRIDGE_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);
+ else 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
+ class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, INTERNAL_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 //CONFIG_HID_SIS_UPDATE_FW
+
+static int sis_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct sis_data *nd;
+ u8 *rep_data = NULL;
+
+#ifdef CONFIG_HID_SIS_UPDATE_FW
+ hid_dev_backup = hdev;
+#endif //CONFIG_HID_SIS_UPDATE_FW
+
+ printk(KERN_INFO "sis_probe\n");
+
+#ifdef CONFIG_HID_SIS_UPDATE_FW
+ backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test
+ if (!backup_urb) {
+ dev_err(&hdev->dev, "cannot allocate backup_urb\n");
+ return -ENOMEM;
+ }
+#endif //CONFIG_HID_SIS_UPDATE_FW
+
+// command Set_Feature for changing device from mouse to touch device
+ rep_data = kmalloc(3,GFP_KERNEL); //return value will be 0xabcd
+ if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH)
+ {
+ if(!rep_data)
+ return -ENOMEM;
+ rep_data[0] = 0x07;
+ rep_data[1] = 0x02;
+ rep_data[2] = 0xA9;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, (USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE), 0x0307, 0, rep_data, 3, 1000);
+ }
+
+// allocate memory for sis_data struct
+ nd = kzalloc(sizeof(struct sis_data), GFP_KERNEL);
+ if (!nd) {
+ dev_err(&hdev->dev, "cannot allocate SiS 9200 data\n");
+ kfree(rep_data);
+ rep_data = NULL;
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, nd);
+
+#ifdef CONFIG_HID_SIS_UPDATE_FW
+ //for ioctl
+ ret = sis_setup_chardev(hdev, nd);
+ if(ret)
+ {
+ printk( KERN_INFO "sis_setup_chardev fail\n");
+ }
+#endif //CONFIG_HID_SIS_UPDATE_FW
+
+ //set noget for not init reports (speed improvement)
+ hdev->quirks |= HID_QUIRK_NOGET;
+ hdev->quirks &= ~HID_QUIRK_MULTITOUCH; //only hid-multitouch cat use this flag!
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+err_free:
+ kfree(rep_data);
+ rep_data = NULL;
+ return ret;
+}
+
+static void sis_remove(struct hid_device *hdev)
+{
+#ifdef CONFIG_HID_SIS_UPDATE_FW
+ //for ioctl
+ dev_t dev = MKDEV(sis_char_major, 0);
+
+ printk(KERN_INFO "sis_remove\n");
+
+ 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);
+#else //CONFIG_HID_SIS_UPDATE_FW
+
+ printk(KERN_INFO "sis_remove\n");
+
+#endif //CONFIG_HID_SIS_UPDATE_FW
+
+#ifdef CONFIG_HID_SIS_UPDATE_FW
+ usb_kill_urb( backup_urb );
+ usb_free_urb( backup_urb );
+ backup_urb = NULL;
+#endif
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id sis_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS2_TOUCH) }, //0x0457, 0x0151
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS_TOUCH) }, //0x0457, 0x0810
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_NEW_SIS2_TOUCH) }, //0x0457, 0x0816
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS9200_TOUCH) }, //0x0457, 0x9200
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS817_TOUCH) }, //0x0457, 0x0817
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SISF817_TOUCH) }, //0x0457, 0xF817
+ { }
+};
+MODULE_DEVICE_TABLE(hid, sis_devices);
+
+
+
+static struct hid_driver sis_driver = {
+ .name = "sis",
+ .id_table = sis_devices,
+ .probe = sis_probe,
+ .remove = sis_remove,
+ .raw_event = sis_raw_event,
+ .input_mapped = sis_input_mapped,
+ .input_mapping = sis_input_mapping,
+ .event = sis_event,
+};
+
+static int __init sis_init(void)
+{
+ printk(KERN_INFO "sis_init\n");
+ return hid_register_driver(&sis_driver);
+}
+
+static void __exit sis_exit(void)
+{
+ printk(KERN_INFO "sis_exit\n");
+ hid_unregister_driver(&sis_driver);
+}
+
+module_init(sis_init);
+module_exit(sis_exit);
+MODULE_DESCRIPTION("SiS 817 Touchscreen Driver");
+MODULE_LICENSE("GPL");