399 lines
9.9 KiB
Diff
399 lines
9.9 KiB
Diff
From 6317c631cb1fd32f34da98a945747781d5a8906d Mon Sep 17 00:00:00 2001
|
|
From: Priya Vijayan <priya.vijayan@intel.com>
|
|
Date: Tue, 4 May 2010 14:21:37 -0700
|
|
Subject: [PATCH] Add mtdev driver and configs
|
|
|
|
Add multi-touch driver and configs for event devices.
|
|
This module is from He Min <min.he@intel.com>
|
|
Code modifications and configs from Priya Vijayan <priya.vijayan@intel.com>
|
|
|
|
Patch-mainline: 2.6.34
|
|
|
|
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
|
|
---
|
|
drivers/input/Kconfig | 9 ++
|
|
drivers/input/Makefile | 1 +
|
|
drivers/input/input.c | 1 +
|
|
drivers/input/mtdev.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++
|
|
include/linux/input.h | 1 +
|
|
5 files changed, 319 insertions(+), 0 deletions(-)
|
|
create mode 100644 drivers/input/mtdev.c
|
|
|
|
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
|
|
index 07c2cd4..0264508 100644
|
|
--- a/drivers/input/Kconfig
|
|
+++ b/drivers/input/Kconfig
|
|
@@ -135,6 +135,15 @@ config INPUT_EVDEV
|
|
To compile this driver as a module, choose M here: the
|
|
module will be called evdev.
|
|
|
|
+config INPUT_MTDEV
|
|
+ tristate "Multitouch interface"
|
|
+ help
|
|
+ Say Y here if you want to enable Multi-touch input driver for event devices
|
|
+ If unsure, say N.
|
|
+
|
|
+ To compile this driver as a module, choose M here:the
|
|
+ module will be called mtdev.
|
|
+
|
|
config INPUT_EVBUG
|
|
tristate "Event debugging"
|
|
help
|
|
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
|
|
index 7ad212d..96a4d94 100644
|
|
--- a/drivers/input/Makefile
|
|
+++ b/drivers/input/Makefile
|
|
@@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
|
|
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
|
|
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
|
|
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
|
|
+obj-$(CONFIG_INPUT_MTDEV) += mtdev.o
|
|
|
|
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
|
|
obj-$(CONFIG_INPUT_MOUSE) += mouse/
|
|
diff --git a/drivers/input/input.c b/drivers/input/input.c
|
|
index 86cb2d2..b589dec 100644
|
|
--- a/drivers/input/input.c
|
|
+++ b/drivers/input/input.c
|
|
@@ -47,6 +47,7 @@ static unsigned int input_abs_bypass_init_data[] __initdata = {
|
|
ABS_MT_BLOB_ID,
|
|
ABS_MT_TRACKING_ID,
|
|
ABS_MT_PRESSURE,
|
|
+ ABS_MT_CONTACT_COUNT,
|
|
0
|
|
};
|
|
static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
|
|
diff --git a/drivers/input/mtdev.c b/drivers/input/mtdev.c
|
|
new file mode 100644
|
|
index 0000000..8b01220
|
|
--- /dev/null
|
|
+++ b/drivers/input/mtdev.c
|
|
@@ -0,0 +1,312 @@
|
|
+#include <linux/module.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/hid.h>
|
|
+#include <linux/wait.h>
|
|
+#include <linux/kthread.h>
|
|
+
|
|
+#define MTDEV_MAX_POINTERS 5
|
|
+
|
|
+#ifndef ABS_MT_PRESSURE
|
|
+#define ABS_MT_PRESSURE 0x3a
|
|
+#endif
|
|
+#ifndef ABS_MT_CONTACT_COUNT
|
|
+#define ABS_MT_CONTACT_COUNT 0x3b
|
|
+#endif
|
|
+
|
|
+struct mtdev_input_dev
|
|
+{
|
|
+ struct input_dev* input_dev;
|
|
+ int id;
|
|
+ bool ready;
|
|
+ int x;
|
|
+ int y;
|
|
+ int z;
|
|
+ int touch;
|
|
+};
|
|
+
|
|
+struct mtdev_dev
|
|
+{
|
|
+ int count;
|
|
+ int last_count;
|
|
+ wait_queue_head_t wq;
|
|
+ struct input_handle handle;
|
|
+ struct mtdev_input_dev devs[MTDEV_MAX_POINTERS];
|
|
+};
|
|
+
|
|
+//id==-1 means to find an empty slot
|
|
+static int find_match_id(struct mtdev_dev * mtdev,int id)
|
|
+{
|
|
+ int i=0;
|
|
+
|
|
+ for (i=0;i<MTDEV_MAX_POINTERS;i++)
|
|
+ {
|
|
+ if(mtdev->devs[i].id==id)
|
|
+ {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+
|
|
+static int mtdev_kt(void *data)
|
|
+{
|
|
+ struct mtdev_dev *mtdev=(struct mtdev_dev*)data;
|
|
+ int i=0;
|
|
+ int err=0;
|
|
+ printk("mtdev_kt entered\n");
|
|
+ if(!mtdev)
|
|
+ return -1;
|
|
+ //wait_event_interruptible(mtdev->wq,kthread_should_stop());
|
|
+ for(;i<MTDEV_MAX_POINTERS;i++)
|
|
+ {
|
|
+ struct input_dev *pdev=NULL;
|
|
+ pdev=mtdev->devs[i].input_dev;
|
|
+
|
|
+ err=input_register_device(pdev);
|
|
+ if(err)
|
|
+ {
|
|
+ printk("error in register mtdev %d\n",err);
|
|
+ return err;
|
|
+ }
|
|
+ else
|
|
+ printk("successfully registered input %d\n",i);
|
|
+ mtdev->devs[i].ready=true;
|
|
+
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mtdev_event(struct input_handle * handle,
|
|
+ unsigned int type, unsigned int code, int value)
|
|
+{
|
|
+ static int i=0;
|
|
+ //int err=0;
|
|
+ int j=0;
|
|
+ struct mtdev_dev *mtdev=handle->private;
|
|
+ //printk("mtdev_event %x %x %x\n",type,code,value);
|
|
+ if(!mtdev->devs[1].ready||!mtdev->devs[0].ready)
|
|
+ return;
|
|
+ if(type==EV_ABS)
|
|
+ {
|
|
+ switch(code)
|
|
+ {
|
|
+ case ABS_MT_CONTACT_COUNT:
|
|
+ if(value!=0)
|
|
+ {
|
|
+ //we start from the first point
|
|
+ i=0;
|
|
+ //printk("mtdev:contact count is %d\n",value);
|
|
+ }
|
|
+ else if(value>MTDEV_MAX_POINTERS)
|
|
+ {
|
|
+ value=MTDEV_MAX_POINTERS;
|
|
+ }
|
|
+
|
|
+ //found last release fingers and send release event
|
|
+ for(j=0;j<MTDEV_MAX_POINTERS;j++)
|
|
+ {
|
|
+ if(mtdev->devs[j].touch==0
|
|
+ &&mtdev->devs[j].id!=-1)
|
|
+ {
|
|
+ input_report_key(mtdev->devs[j].input_dev,BTN_TOUCH,0);
|
|
+ input_sync(mtdev->devs[j].input_dev);
|
|
+ printk("%d id %d released\n",j,mtdev->devs[j].id);
|
|
+ mtdev->devs[j].id=-1;
|
|
+ }
|
|
+ mtdev->devs[j].touch=0;
|
|
+ }
|
|
+ mtdev->count=value;
|
|
+
|
|
+ mtdev->last_count=value;
|
|
+
|
|
+ break;
|
|
+ case ABS_MT_TRACKING_ID:
|
|
+ {
|
|
+ i=find_match_id(mtdev,value);
|
|
+ if(i==-1||i>=MTDEV_MAX_POINTERS)
|
|
+ {
|
|
+ i=find_match_id(mtdev,-1);
|
|
+ if(i==-1||i>=MTDEV_MAX_POINTERS)
|
|
+ {
|
|
+ printk("no empty slot for id %d\n",value);
|
|
+ break;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ //newly pressed
|
|
+ mtdev->devs[i].touch=2;
|
|
+ mtdev->devs[i].id=value;
|
|
+ printk("found slot %d for id %d\n",i,value);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ //printk("found slot %d for id%d\n",i,value);
|
|
+ //keep the point
|
|
+ mtdev->devs[i].touch=1;
|
|
+
|
|
+ }
|
|
+ break;
|
|
+ case ABS_MT_POSITION_X:
|
|
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
|
|
+ mtdev->devs[i].x=value;
|
|
+ //printk("mt x :%d\n",value);
|
|
+ break;
|
|
+ case ABS_MT_POSITION_Y:
|
|
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
|
|
+ mtdev->devs[i].y=value;
|
|
+ //printk("mt y :%d\n",value);
|
|
+ break;
|
|
+ case ABS_MT_PRESSURE:
|
|
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
|
|
+ mtdev->devs[i].z=value;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ else if(type == EV_SYN && code == SYN_MT_REPORT)
|
|
+ {
|
|
+ if(i<MTDEV_MAX_POINTERS&&i!=-1)
|
|
+ {
|
|
+ if(mtdev->devs[i].touch==2)
|
|
+ {
|
|
+ input_report_key(mtdev->devs[i].input_dev,BTN_TOUCH,1);
|
|
+
|
|
+ }
|
|
+ input_report_abs(mtdev->devs[i].input_dev,ABS_X,mtdev->devs[i].x);
|
|
+ input_report_abs(mtdev->devs[i].input_dev,ABS_Y,mtdev->devs[i].y);
|
|
+ input_report_abs(mtdev->devs[i].input_dev,ABS_PRESSURE,mtdev->devs[i].z);
|
|
+ input_sync(mtdev->devs[i].input_dev);
|
|
+ //printk("mtdev_event %d id %d (%d,%d,%d)\n",i,mtdev->devs[i].id,mtdev->devs[i].x,mtdev->devs[i].y,mtdev->devs[i].z);
|
|
+ //i++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
+/*
|
|
+ * grab all the input of mt device, create new single touch input devices
|
|
+ *
|
|
+ */
|
|
+static int mtdev_connect(struct input_handler *handler, struct input_dev *dev,
|
|
+ const struct input_device_id *id)
|
|
+{
|
|
+ struct mtdev_dev* mtdev;
|
|
+ struct task_struct * task=NULL;
|
|
+ int i=0;
|
|
+ int err=0;
|
|
+ printk("mtdev_connect\n");
|
|
+ mtdev=kzalloc(sizeof(struct mtdev_dev),GFP_KERNEL);
|
|
+ if(!mtdev)
|
|
+ return -ENOMEM;
|
|
+ mtdev->handle.dev=input_get_device(dev);
|
|
+ mtdev->handle.name="mtdev";
|
|
+ mtdev->handle.handler=handler;
|
|
+ mtdev->handle.private=mtdev;
|
|
+ mtdev->count=0;
|
|
+ mtdev->last_count=0;
|
|
+ init_waitqueue_head(&mtdev->wq);
|
|
+ for(;i<MTDEV_MAX_POINTERS;i++)
|
|
+ {
|
|
+ //we just store the data here, and will register it
|
|
+ //when the first event comes
|
|
+ struct input_dev *pdev=NULL;
|
|
+ mtdev->devs[i].ready=false;
|
|
+ mtdev->devs[i].id=-1;
|
|
+ mtdev->devs[i].touch=-1;
|
|
+ mtdev->devs[i].input_dev=input_allocate_device();
|
|
+ if(!mtdev->devs[i].input_dev)
|
|
+ return -ENOMEM;
|
|
+ pdev=mtdev->devs[i].input_dev;
|
|
+ memcpy(pdev->evbit,dev->evbit,sizeof(pdev->evbit));
|
|
+ memcpy(pdev->keybit,dev->keybit,sizeof(pdev->keybit));
|
|
+ memcpy(pdev->absbit,dev->absbit,sizeof(pdev->absbit));
|
|
+
|
|
+ memcpy(pdev->abs,dev->abs,sizeof(pdev->abs));
|
|
+ memcpy(pdev->absmax,dev->absmax,sizeof(pdev->absmax));
|
|
+ memcpy(pdev->absmin,dev->absmin,sizeof(pdev->absmin));
|
|
+
|
|
+ pdev->name="mtdev virtual input";
|
|
+ }
|
|
+
|
|
+ //create a thread to create the new input devices
|
|
+ //because there's a mutex,which may cause dead lock
|
|
+ task=kthread_run(mtdev_kt,mtdev,"mtdev thread");
|
|
+ if(!task)
|
|
+ printk("error !!!!\n");
|
|
+ else
|
|
+ printk("kthread created OK\n");
|
|
+
|
|
+
|
|
+ err=input_grab_device(&mtdev->handle);
|
|
+ if(err)
|
|
+ {
|
|
+ printk("error in grab device %d\n",err);
|
|
+ return err;
|
|
+ }
|
|
+ else
|
|
+ printk("successfully grab device \n");
|
|
+
|
|
+ wake_up_all(&mtdev->wq);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mtdev_disconnect(struct input_handle *handle)
|
|
+{
|
|
+ printk("mtdev_disconnect\n");
|
|
+ input_release_device(handle);
|
|
+}
|
|
+
|
|
+static const struct input_device_id mtdev_ids[] = {
|
|
+ {
|
|
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
|
|
+ .vendor=0x1f87,
|
|
+ .product=0x0002,
|
|
+ },
|
|
+ {
|
|
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
|
|
+ .vendor=0x1f87,
|
|
+ .product=0x0001,
|
|
+ },
|
|
+ {
|
|
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
|
|
+ .vendor=0x0483,
|
|
+ .product=0x3261,
|
|
+ },
|
|
+ {
|
|
+ .flags=INPUT_DEVICE_ID_MATCH_VENDOR|INPUT_DEVICE_ID_MATCH_PRODUCT,
|
|
+ .vendor=0x2087,
|
|
+ .product=0x0a01,
|
|
+ },
|
|
+ {},
|
|
+};
|
|
+
|
|
+MODULE_DEVICE_TABLE(input,mtdev_ids);
|
|
+
|
|
+static struct input_handler mtdev_handler = {
|
|
+ .event = mtdev_event,
|
|
+ .connect = mtdev_connect,
|
|
+ .disconnect = mtdev_disconnect,
|
|
+ .name = "mtdev",
|
|
+ .id_table = mtdev_ids,
|
|
+};
|
|
+
|
|
+
|
|
+static int __init mtdev_init(void)
|
|
+{
|
|
+ return input_register_handler(&mtdev_handler);
|
|
+}
|
|
+
|
|
+static void __exit mtdev_exit(void)
|
|
+{
|
|
+ input_unregister_handler(&mtdev_handler);
|
|
+}
|
|
+
|
|
+module_init(mtdev_init);
|
|
+module_exit(mtdev_exit);
|
|
+
|
|
+MODULE_AUTHOR("He Min <min.he@intel.com>");
|
|
+MODULE_DESCRIPTION("Multi-touch input driver event devices");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/include/linux/input.h b/include/linux/input.h
|
|
index 663208a..55bf8bc 100644
|
|
--- a/include/linux/input.h
|
|
+++ b/include/linux/input.h
|
|
@@ -662,6 +662,7 @@ struct input_absinfo {
|
|
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
|
|
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
|
|
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
|
|
+#define ABS_MT_CONTACT_COUNT 0x3b /* Contact count */
|
|
|
|
#define ABS_MAX 0x3f
|
|
#define ABS_CNT (ABS_MAX+1)
|
|
--
|
|
1.6.2.2
|
|
|