Re: [PATCH 2/2] INPUT/HID: add touch support for SiS touch driver
From: æåè (tammy_tseng)
Date: Thu Feb 12 2015 - 02:24:36 EST
Hi, Dmitry
> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@xxxxxxxxx]
> Sent: Thursday, February 12, 2015 3:04 PM
> To: æåè (tammy_tseng)
> Cc: Oliver Neukum; lkml; linux-input@xxxxxxxxxxxxxxx;
> tammy0524@xxxxxxxxx
> 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 },