715 lines
20 KiB
Diff
715 lines
20 KiB
Diff
From f7e13f4d9a7a9025244b37a3ad188af7dae841d9 Mon Sep 17 00:00:00 2001
|
|
From: Stephane Chatty <chatty@enac.fr>
|
|
Date: Fri, 9 Apr 2010 15:33:54 -0700
|
|
Subject: [PATCH 105/105] Stantum and Mosart multitouch drivers
|
|
|
|
HID Driver and configs for Stantum and Mosart multitouch panels.
|
|
|
|
Patch-mainline: 2.6.34
|
|
|
|
Signed-off-by: Stephane Chatty <chatty@enac.fr>
|
|
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
|
|
Signed-off-by: Priya Vijayan <priya.vijayan@intel.com>
|
|
---
|
|
drivers/hid/Kconfig | 12 ++
|
|
drivers/hid/Makefile | 3 +-
|
|
drivers/hid/hid-core.c | 7 +-
|
|
drivers/hid/hid-ids.h | 15 ++-
|
|
drivers/hid/hid-mosart.c | 274 +++++++++++++++++++++++++++++++++++++++++++
|
|
drivers/hid/hid-stantum.c | 285 +++++++++++++++++++++++++++++++++++++++++++++
|
|
6 files changed, 590 insertions(+), 6 deletions(-)
|
|
create mode 100644 drivers/hid/hid-mosart.c
|
|
create mode 100644 drivers/hid/hid-stantum.c
|
|
|
|
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
|
|
index 37fb241..55906bc 100644
|
|
--- a/drivers/hid/Kconfig
|
|
+++ b/drivers/hid/Kconfig
|
|
@@ -203,6 +203,12 @@ config HID_MONTEREY
|
|
---help---
|
|
Support for Monterey Genius KB29E.
|
|
|
|
+config HID_MOSART
|
|
+ tristate "MosArt"
|
|
+ depends on USB_HID
|
|
+ ---help---
|
|
+ Support for MosArt dual-touch panels.
|
|
+
|
|
config HID_NTRIG
|
|
tristate "NTrig" if EMBEDDED
|
|
depends on USB_HID
|
|
@@ -247,6 +253,12 @@ config HID_SONY
|
|
---help---
|
|
Support for Sony PS3 controller.
|
|
|
|
+config HID_STANTUM
|
|
+ tristate "Stantum"
|
|
+ depends on USB_HID
|
|
+ ---help---
|
|
+ Support for Stantum multitouch panel.
|
|
+
|
|
config HID_SUNPLUS
|
|
tristate "Sunplus" if EMBEDDED
|
|
depends on USB_HID
|
|
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
|
|
index b05f921..bbda0b0 100644
|
|
--- a/drivers/hid/Makefile
|
|
+++ b/drivers/hid/Makefile
|
|
@@ -34,12 +34,14 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o
|
|
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
|
|
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
|
|
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
|
|
+obj-$(CONFIG_HID_MOSART) += hid-mosart.o
|
|
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
|
|
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
|
|
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
|
|
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
|
|
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
|
|
obj-$(CONFIG_HID_SONY) += hid-sony.o
|
|
+obj-$(CONFIG_HID_STANTUM) += hid-stantum.o
|
|
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
|
|
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
|
|
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
|
|
@@ -51,4 +53,3 @@ obj-$(CONFIG_HID_WACOM) += hid-wacom.o
|
|
obj-$(CONFIG_USB_HID) += usbhid/
|
|
obj-$(CONFIG_USB_MOUSE) += usbhid/
|
|
obj-$(CONFIG_USB_KBD) += usbhid/
|
|
-
|
|
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
|
index b126102..fbf6f3e 100644
|
|
--- a/drivers/hid/hid-core.c
|
|
+++ b/drivers/hid/hid-core.c
|
|
@@ -1342,6 +1342,9 @@ static const struct hid_device_id hid_blacklist[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM2, USB_DEVICE_ID_MTP2) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_STMICRO, USB_DEVICE_ID_STMICRO_MTP1) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
|
|
@@ -1544,8 +1546,9 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
|
|
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
|
|
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
|
|
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
|
index 6865ca2..92c8a78 100644
|
|
--- a/drivers/hid/hid-ids.h
|
|
+++ b/drivers/hid/hid-ids.h
|
|
@@ -96,9 +96,12 @@
|
|
#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
|
|
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
|
|
|
|
-#define USB_VENDOR_ID_ASUS 0x0b05
|
|
-#define USB_DEVICE_ID_ASUS_LCM 0x1726
|
|
-#define USB_DEVICE_ID_ASUS_LCM2 0x175b
|
|
+#define USB_VENDOR_ID_ASUS 0x0486
|
|
+#define USB_DEVICE_ID_ASUS_T91MT 0x0185
|
|
+
|
|
+#define USB_VENDOR_ID_ASUSTEK 0x0b05
|
|
+#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
|
|
+#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
|
|
|
|
#define USB_VENDOR_ID_ATEN 0x0557
|
|
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
|
|
@@ -399,6 +402,15 @@
|
|
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
|
|
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046
|
|
|
|
+#define USB_VENDOR_ID_STANTUM 0x1f87
|
|
+#define USB_DEVICE_ID_MTP 0x0002
|
|
+
|
|
+#define USB_VENDOR_ID_STANTUM2 0x1f87
|
|
+#define USB_DEVICE_ID_MTP2 0x0001
|
|
+
|
|
+#define USB_VENDOR_ID_STMICRO 0x0483
|
|
+#define USB_DEVICE_ID_STMICRO_MTP1 0x3261
|
|
+
|
|
#define USB_VENDOR_ID_SUN 0x0430
|
|
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
|
|
|
|
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
|
|
new file mode 100644
|
|
index 0000000..e91437c
|
|
--- /dev/null
|
|
+++ b/drivers/hid/hid-mosart.c
|
|
@@ -0,0 +1,274 @@
|
|
+/*
|
|
+ * HID driver for the multitouch panel on the ASUS EeePC T91MT
|
|
+ *
|
|
+ * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
|
|
+ * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * 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/slab.h>
|
|
+#include <linux/usb.h>
|
|
+#include "usbhid/usbhid.h"
|
|
+
|
|
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
|
|
+MODULE_DESCRIPTION("MosArt dual-touch panel");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+#include "hid-ids.h"
|
|
+
|
|
+struct mosart_data {
|
|
+ __u16 x, y;
|
|
+ __u8 id;
|
|
+ bool valid; /* valid finger data, or just placeholder? */
|
|
+ bool first; /* is this the first finger in this frame? */
|
|
+ bool activity_now; /* at least one active finger in this frame? */
|
|
+ bool activity; /* at least one active finger previously? */
|
|
+};
|
|
+
|
|
+static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
+ struct hid_field *field, struct hid_usage *usage,
|
|
+ unsigned long **bit, int *max)
|
|
+{
|
|
+ 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);
|
|
+ /* touchscreen emulation */
|
|
+ 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);
|
|
+ /* touchscreen emulation */
|
|
+ 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) {
|
|
+ case HID_DG_CONFIDENCE:
|
|
+ case HID_DG_TIPSWITCH:
|
|
+ case HID_DG_INPUTMODE:
|
|
+ case HID_DG_DEVICEINDEX:
|
|
+ case HID_DG_CONTACTCOUNT:
|
|
+ case HID_DG_CONTACTMAX:
|
|
+ case HID_DG_TIPPRESSURE:
|
|
+ case HID_DG_WIDTH:
|
|
+ case HID_DG_HEIGHT:
|
|
+ return -1;
|
|
+ case HID_DG_INRANGE:
|
|
+ /* touchscreen emulation */
|
|
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
|
|
+ return 1;
|
|
+
|
|
+ case HID_DG_CONTACTID:
|
|
+ hid_map_usage(hi, usage, bit, max,
|
|
+ EV_ABS, ABS_MT_TRACKING_ID);
|
|
+ return 1;
|
|
+
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+ case 0xff000000:
|
|
+ /* ignore HID features */
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
|
+ struct hid_field *field, struct hid_usage *usage,
|
|
+ unsigned long **bit, int *max)
|
|
+{
|
|
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
|
|
+ clear_bit(usage->code, *bit);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * this function is called when a whole finger has been parsed,
|
|
+ * so that it can decide what to send to the input layer.
|
|
+ */
|
|
+static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
|
|
+{
|
|
+ td->first = !td->first; /* touchscreen emulation */
|
|
+
|
|
+ if (!td->valid) {
|
|
+ /*
|
|
+ * touchscreen emulation: if no finger in this frame is valid
|
|
+ * and there previously was finger activity, this is a release
|
|
+ */
|
|
+ if (!td->first && !td->activity_now && td->activity) {
|
|
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
|
|
+ td->activity = false;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
|
|
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
|
|
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
|
|
+
|
|
+ input_mt_sync(input);
|
|
+ td->valid = false;
|
|
+
|
|
+ /* touchscreen emulation: if first active finger in this frame... */
|
|
+ if (!td->activity_now) {
|
|
+ /* if there was no previous activity, emit touch event */
|
|
+ if (!td->activity) {
|
|
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
|
|
+ td->activity = true;
|
|
+ }
|
|
+ td->activity_now = true;
|
|
+ /* and in any case this is our preferred finger */
|
|
+ input_event(input, EV_ABS, ABS_X, td->x);
|
|
+ input_event(input, EV_ABS, ABS_Y, td->y);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static int mosart_event(struct hid_device *hid, struct hid_field *field,
|
|
+ struct hid_usage *usage, __s32 value)
|
|
+{
|
|
+ struct mosart_data *td = hid_get_drvdata(hid);
|
|
+
|
|
+ if (hid->claimed & HID_CLAIMED_INPUT) {
|
|
+ struct input_dev *input = field->hidinput->input;
|
|
+ switch (usage->hid) {
|
|
+ case HID_DG_INRANGE:
|
|
+ td->valid = !!value;
|
|
+ break;
|
|
+ case HID_GD_X:
|
|
+ td->x = value;
|
|
+ break;
|
|
+ case HID_GD_Y:
|
|
+ td->y = value;
|
|
+ mosart_filter_event(td, input);
|
|
+ break;
|
|
+ case HID_DG_CONTACTID:
|
|
+ td->id = value;
|
|
+ break;
|
|
+ case HID_DG_CONTACTCOUNT:
|
|
+ /* touch emulation: this is the last field in a frame */
|
|
+ td->first = false;
|
|
+ td->activity_now = false;
|
|
+ break;
|
|
+ case HID_DG_CONFIDENCE:
|
|
+ case HID_DG_TIPSWITCH:
|
|
+ /* avoid interference from generic hidinput handling */
|
|
+ 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;
|
|
+}
|
|
+
|
|
+static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
+{
|
|
+ int ret;
|
|
+ struct mosart_data *td;
|
|
+
|
|
+
|
|
+ td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
|
|
+ if (!td) {
|
|
+ dev_err(&hdev->dev, "cannot allocate MosArt data\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ td->valid = false;
|
|
+ td->activity = false;
|
|
+ td->activity_now = false;
|
|
+ td->first = false;
|
|
+ hid_set_drvdata(hdev, td);
|
|
+
|
|
+ /* currently, it's better to have one evdev device only */
|
|
+#if 0
|
|
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
|
|
+#endif
|
|
+
|
|
+ ret = hid_parse(hdev);
|
|
+ if (ret == 0)
|
|
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
|
+
|
|
+ if (ret == 0) {
|
|
+ struct hid_report_enum *re = hdev->report_enum
|
|
+ + HID_FEATURE_REPORT;
|
|
+ struct hid_report *r = re->report_id_hash[7];
|
|
+
|
|
+ r->field[0]->value[0] = 0x02;
|
|
+ usbhid_submit_report(hdev, r, USB_DIR_OUT);
|
|
+ } else
|
|
+ kfree(td);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void mosart_remove(struct hid_device *hdev)
|
|
+{
|
|
+ hid_hw_stop(hdev);
|
|
+ kfree(hid_get_drvdata(hdev));
|
|
+ hid_set_drvdata(hdev, NULL);
|
|
+}
|
|
+
|
|
+static const struct hid_device_id mosart_devices[] = {
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(hid, mosart_devices);
|
|
+
|
|
+static const struct hid_usage_id mosart_grabbed_usages[] = {
|
|
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
|
|
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
|
|
+};
|
|
+
|
|
+static struct hid_driver mosart_driver = {
|
|
+ .name = "mosart",
|
|
+ .id_table = mosart_devices,
|
|
+ .probe = mosart_probe,
|
|
+ .remove = mosart_remove,
|
|
+ .input_mapping = mosart_input_mapping,
|
|
+ .input_mapped = mosart_input_mapped,
|
|
+ .usage_table = mosart_grabbed_usages,
|
|
+ .event = mosart_event,
|
|
+};
|
|
+
|
|
+static int __init mosart_init(void)
|
|
+{
|
|
+ return hid_register_driver(&mosart_driver);
|
|
+}
|
|
+
|
|
+static void __exit mosart_exit(void)
|
|
+{
|
|
+ hid_unregister_driver(&mosart_driver);
|
|
+}
|
|
+
|
|
+module_init(mosart_init);
|
|
+module_exit(mosart_exit);
|
|
+
|
|
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
|
|
new file mode 100644
|
|
index 0000000..bb4430f
|
|
--- /dev/null
|
|
+++ b/drivers/hid/hid-stantum.c
|
|
@@ -0,0 +1,286 @@
|
|
+/*
|
|
+ * HID driver for Stantum multitouch panels
|
|
+ *
|
|
+ * Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * 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/slab.h>
|
|
+
|
|
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
|
|
+MODULE_DESCRIPTION("Stantum HID multitouch panels");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+#include "hid-ids.h"
|
|
+
|
|
+struct stantum_data {
|
|
+ __s32 x, y, z, w, h; /* x, y, pressure, width, height */
|
|
+ __u16 id; /* touch id */
|
|
+ bool valid; /* valid finger data, or just placeholder? */
|
|
+ bool first; /* first finger in the HID packet? */
|
|
+ bool activity; /* at least one active finger so far? */
|
|
+};
|
|
+
|
|
+static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
+ struct hid_field *field, struct hid_usage *usage,
|
|
+ unsigned long **bit, int *max)
|
|
+{
|
|
+ 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);
|
|
+ /* touchscreen emulation */
|
|
+ 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);
|
|
+ /* touchscreen emulation */
|
|
+ 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) {
|
|
+ case HID_DG_INRANGE:
|
|
+ case HID_DG_CONFIDENCE:
|
|
+ case HID_DG_INPUTMODE:
|
|
+ case HID_DG_DEVICEINDEX:
|
|
+ case HID_DG_CONTACTCOUNT:
|
|
+ case HID_DG_CONTACTMAX:
|
|
+ return -1;
|
|
+
|
|
+ case HID_DG_TIPSWITCH:
|
|
+ /* touchscreen emulation */
|
|
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
|
|
+ return 1;
|
|
+
|
|
+ case HID_DG_WIDTH:
|
|
+ hid_map_usage(hi, usage, bit, max,
|
|
+ EV_ABS, ABS_MT_TOUCH_MAJOR);
|
|
+ return 1;
|
|
+ case HID_DG_HEIGHT:
|
|
+ hid_map_usage(hi, usage, bit, max,
|
|
+ EV_ABS, ABS_MT_TOUCH_MINOR);
|
|
+ input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
|
|
+ 1, 1, 0, 0);
|
|
+ return 1;
|
|
+ case HID_DG_TIPPRESSURE:
|
|
+ hid_map_usage(hi, usage, bit, max,
|
|
+ EV_ABS, ABS_MT_PRESSURE);
|
|
+ return 1;
|
|
+
|
|
+ case HID_DG_CONTACTID:
|
|
+ hid_map_usage(hi, usage, bit, max,
|
|
+ EV_ABS, ABS_MT_TRACKING_ID);
|
|
+ return 1;
|
|
+
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+ case 0xff000000:
|
|
+ /* no input-oriented meaning */
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
|
+ struct hid_field *field, struct hid_usage *usage,
|
|
+ unsigned long **bit, int *max)
|
|
+{
|
|
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
|
|
+ clear_bit(usage->code, *bit);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * this function is called when a whole finger has been parsed,
|
|
+ * so that it can decide what to send to the input layer.
|
|
+ */
|
|
+static void stantum_filter_event(struct stantum_data *sd,
|
|
+ struct input_dev *input)
|
|
+{
|
|
+ bool wide;
|
|
+
|
|
+ if (!sd->valid) {
|
|
+ /*
|
|
+ * touchscreen emulation: if the first finger is not valid and
|
|
+ * there previously was finger activity, this is a release
|
|
+ */
|
|
+ if (sd->first && sd->activity) {
|
|
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
|
|
+ sd->activity = false;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id);
|
|
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x);
|
|
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y);
|
|
+
|
|
+ wide = (sd->w > sd->h);
|
|
+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
|
|
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h);
|
|
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w);
|
|
+
|
|
+ input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z);
|
|
+
|
|
+ input_mt_sync(input);
|
|
+ sd->valid = false;
|
|
+
|
|
+ /* touchscreen emulation */
|
|
+ if (sd->first) {
|
|
+ if (!sd->activity) {
|
|
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
|
|
+ sd->activity = true;
|
|
+ }
|
|
+ input_event(input, EV_ABS, ABS_X, sd->x);
|
|
+ input_event(input, EV_ABS, ABS_Y, sd->y);
|
|
+ }
|
|
+ sd->first = false;
|
|
+}
|
|
+
|
|
+
|
|
+static int stantum_event(struct hid_device *hid, struct hid_field *field,
|
|
+ struct hid_usage *usage, __s32 value)
|
|
+{
|
|
+ struct stantum_data *sd = hid_get_drvdata(hid);
|
|
+
|
|
+ if (hid->claimed & HID_CLAIMED_INPUT) {
|
|
+ struct input_dev *input = field->hidinput->input;
|
|
+
|
|
+ switch (usage->hid) {
|
|
+ case HID_DG_INRANGE:
|
|
+ /* this is the last field in a finger */
|
|
+ stantum_filter_event(sd, input);
|
|
+ break;
|
|
+ case HID_DG_WIDTH:
|
|
+ sd->w = value;
|
|
+ break;
|
|
+ case HID_DG_HEIGHT:
|
|
+ sd->h = value;
|
|
+ break;
|
|
+ case HID_GD_X:
|
|
+ sd->x = value;
|
|
+ break;
|
|
+ case HID_GD_Y:
|
|
+ sd->y = value;
|
|
+ break;
|
|
+ case HID_DG_TIPPRESSURE:
|
|
+ sd->z = value;
|
|
+ break;
|
|
+ case HID_DG_CONTACTID:
|
|
+ sd->id = value;
|
|
+ break;
|
|
+ case HID_DG_CONFIDENCE:
|
|
+ sd->valid = !!value;
|
|
+ break;
|
|
+ case 0xff000002:
|
|
+ /* this comes only before the first finger */
|
|
+ sd->first = true;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ /* ignore the others */
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* 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;
|
|
+}
|
|
+
|
|
+static int stantum_probe(struct hid_device *hdev,
|
|
+ const struct hid_device_id *id)
|
|
+{
|
|
+ int ret;
|
|
+ struct stantum_data *sd;
|
|
+
|
|
+ sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
|
|
+ if (!sd) {
|
|
+ dev_err(&hdev->dev, "cannot allocate Stantum data\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ sd->valid = false;
|
|
+ sd->first = false;
|
|
+ sd->activity = false;
|
|
+ hid_set_drvdata(hdev, sd);
|
|
+
|
|
+ ret = hid_parse(hdev);
|
|
+ if (!ret)
|
|
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
|
+
|
|
+ if (ret)
|
|
+ kfree(sd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void stantum_remove(struct hid_device *hdev)
|
|
+{
|
|
+ hid_hw_stop(hdev);
|
|
+ kfree(hid_get_drvdata(hdev));
|
|
+ hid_set_drvdata(hdev, NULL);
|
|
+}
|
|
+
|
|
+static const struct hid_device_id stantum_devices[] = {
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM2, USB_DEVICE_ID_MTP2) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_STMICRO, USB_DEVICE_ID_STMICRO_MTP1) },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(hid, stantum_devices);
|
|
+
|
|
+static const struct hid_usage_id stantum_grabbed_usages[] = {
|
|
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
|
|
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
|
|
+};
|
|
+
|
|
+static struct hid_driver stantum_driver = {
|
|
+ .name = "stantum",
|
|
+ .id_table = stantum_devices,
|
|
+ .probe = stantum_probe,
|
|
+ .remove = stantum_remove,
|
|
+ .input_mapping = stantum_input_mapping,
|
|
+ .input_mapped = stantum_input_mapped,
|
|
+ .usage_table = stantum_grabbed_usages,
|
|
+ .event = stantum_event,
|
|
+};
|
|
+
|
|
+static int __init stantum_init(void)
|
|
+{
|
|
+ return hid_register_driver(&stantum_driver);
|
|
+}
|
|
+
|
|
+static void __exit stantum_exit(void)
|
|
+{
|
|
+ hid_unregister_driver(&stantum_driver);
|
|
+}
|
|
+
|
|
+module_init(stantum_init);
|
|
+module_exit(stantum_exit);
|
|
+
|
|
--
|
|
1.6.2.2
|
|
|