diff mbox series

hid-multitouch: is pen hovering ever possible?

Message ID 0322c725-9eea-2947-bcf1-89958d91db92@astralinux.ru
State New
Headers show
Series hid-multitouch: is pen hovering ever possible? | expand

Commit Message

Dmitry Mastykin Aug. 21, 2020, 10:24 a.m. UTC
Hello guys,
thanks to all of you for your great work!

Please, answer, is pen hovering ever possible using hid-multitouch driver?
If I remove hid-multitouch - hovering works well with hid-generic.
I can't unbind from hid-multitouch and bind to hid-generic: bind fails 
with "No such device".
I tried to modify hid-multitouch, but was not able to get hovering work 
using multitouch reports.
Then I noticed, that wacom uses non-multitouch reports for their pen 
devices, and added a quirk to hid-multitouch that changes pen's behavior 
to non-multitouch (patch attached). It works, but the way must be wrong(
How should one proceed in right way?

Thank you very much!
Dmitry Mastykin
From 2ae5139e065975d29bab768ce87fc916d3519b48 Mon Sep 17 00:00:00 2001
From: Dmitry Mastykin <dmastykin@astralinux.ru>
Date: Fri, 21 Aug 2020 11:45:52 +0300
Subject: temp
diff mbox series

Patch

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 362805ddf377..b6c593e88fc4 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -48,6 +48,9 @@  MODULE_LICENSE("GPL");
 
 #include "hid-ids.h"
 
+#define MY(fmt,arg...) printk(KERN_INFO "%s: " fmt "\n", __func__, ##arg)
+// #define MY(fmt,arg...)
+
 /* quirks to control the device */
 #define MT_QUIRK_NOT_SEEN_MEANS_UP	BIT(0)
 #define MT_QUIRK_SLOT_IS_CONTACTID	BIT(1)
@@ -69,6 +72,7 @@  MODULE_LICENSE("GPL");
 #define MT_QUIRK_ASUS_CUSTOM_UP		BIT(17)
 #define MT_QUIRK_WIN8_PTP_BUTTONS	BIT(18)
 #define MT_QUIRK_SEPARATE_APP_REPORT	BIT(19)
+#define MT_QUIRK_NON_MT_PEN		BIT(20)
 
 #define MT_INPUTMODE_TOUCHSCREEN	0x02
 #define MT_INPUTMODE_TOUCHPAD		0x03
@@ -99,6 +103,9 @@  struct mt_usages {
 	bool *tip_state;	/* is the touch valid? */
 	bool *inrange_state;	/* is the finger in proximity of the sensor? */
 	bool *confidence_state;	/* is the touch made by a finger? */
+	bool *barrel_state;
+	bool *invert_state;
+	bool *eraser_state;
 };
 
 struct mt_application {
@@ -152,6 +159,7 @@  struct mt_report_data {
 	struct hid_report *report;
 	struct mt_application *application;
 	bool is_mt_collection;
+	bool non_mt_pen;
 };
 
 struct mt_device {
@@ -206,6 +214,7 @@  static void mt_post_parse(struct mt_device *td, struct mt_application *app);
 #define MT_CLS_GOOGLE				0x0111
 #define MT_CLS_RAZER_BLADE_STEALTH		0x0112
 #define MT_CLS_SMART_TECH			0x0113
+#define MT_CLS_NON_MT_PEN			0x0114
 
 #define MT_DEFAULT_MAXCONTACT	10
 #define MT_MAX_MAXCONTACT	250
@@ -363,6 +372,9 @@  static const struct mt_class mt_classes[] = {
 			MT_QUIRK_CONTACT_CNT_ACCURATE |
 			MT_QUIRK_SEPARATE_APP_REPORT,
 	},
+	{ .name = MT_CLS_NON_MT_PEN,
+		.quirks = MT_QUIRK_NON_MT_PEN,
+	},
 	{ }
 };
 
@@ -512,6 +524,9 @@  static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
 	usage->tip_state = DEFAULT_FALSE;
 	usage->inrange_state = DEFAULT_FALSE;
 	usage->confidence_state = DEFAULT_TRUE;
+	usage->barrel_state = DEFAULT_FALSE;
+	usage->invert_state = DEFAULT_FALSE;
+	usage->eraser_state = DEFAULT_FALSE;
 
 	list_add_tail(&usage->list, &application->mt_usages);
 
@@ -864,6 +879,67 @@  static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	return 0;
 }
 
+static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max, struct mt_application *app)
+{
+	struct mt_device *td = hid_get_drvdata(hdev);
+	struct mt_class *cls = &td->mtclass;
+
+	MY("application:%s:%x:%x", hdev->name, field->application, usage->hid);
+
+	switch (usage->hid & HID_USAGE_PAGE) {
+	case HID_UP_GENDESK:
+		switch (usage->hid) {
+		case HID_GD_X:
+			__set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
+			set_abs(hi->input, ABS_X, field, cls->sn_move);
+			MT_STORE_FIELD(x);
+			return 1;
+		case HID_GD_Y:
+			set_abs(hi->input, ABS_Y, field, cls->sn_move);
+			MT_STORE_FIELD(y);
+			return 1;
+		}
+		return -1;
+
+	case HID_UP_DIGITIZER:
+		switch (usage->hid) {
+		case HID_DG_INRANGE:
+			input_set_capability(hi->input,
+					     EV_KEY, BTN_TOOL_PEN);
+			input_set_abs_params(hi->input,
+					     ABS_DISTANCE, 0, 1, 0, 0);
+			MT_STORE_FIELD(inrange_state);
+			return 1;
+		case HID_DG_TIPSWITCH:
+			input_set_capability(hi->input,
+					     EV_KEY, BTN_TOUCH);
+			MT_STORE_FIELD(tip_state);
+			return 1;
+		case HID_DG_BARRELSWITCH:
+			input_set_capability(hi->input,
+					     EV_KEY, BTN_STYLUS2);
+			MT_STORE_FIELD(barrel_state);
+			return 1;
+		case HID_DG_INVERT:
+			MT_STORE_FIELD(invert_state);
+			return 1;
+		case HID_DG_ERASER:
+			MT_STORE_FIELD(eraser_state);
+			return 1;
+		case HID_DG_TIPPRESSURE:
+			set_abs(hi->input, ABS_PRESSURE, field,
+				cls->sn_pressure);
+			MT_STORE_FIELD(p);
+			return 1;
+		}
+		return -1;
+	}
+
+	return 0;
+}
+
 static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
 			   struct mt_usages *slot,
 			   struct input_dev *input)
@@ -1229,6 +1305,43 @@  static void mt_touch_report(struct hid_device *hid,
 	clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
 }
 
+static void mt_pen_report(struct hid_device *hid,
+		       struct mt_report_data *rdata)
+{
+	struct mt_application *app = rdata->application;
+	struct mt_usages *usage;
+	struct input_dev *input = rdata->report->field[0]->hidinput->input;
+	bool tip_state;
+	int p;
+
+	if (!(usage = list_first_entry_or_null(&app->mt_usages,
+					       struct mt_usages, list)))
+		return;
+
+
+	tip_state = *usage->tip_state;
+	p = *usage->p;
+	// tip_state = tip_state && p > 100;
+	// if (!tip_state)
+	// 	p = 0;
+
+	MY("inr:tip:tip:bar:inv:era %d:%d:%d:%d:%d:%d",
+		*usage->inrange_state,
+		*usage->tip_state,
+		tip_state,
+		*usage->barrel_state,
+		*usage->invert_state,
+		*usage->eraser_state
+	);
+	input_report_key(input, BTN_TOOL_PEN, *usage->inrange_state);
+	input_report_key(input, BTN_TOUCH, tip_state);
+	input_report_key(input, BTN_STYLUS2, *usage->barrel_state);
+	input_event(input, EV_ABS, ABS_X, *usage->x);
+	input_event(input, EV_ABS, ABS_Y, *usage->y);
+	input_event(input, EV_ABS, ABS_PRESSURE, p);
+	input_event(input, EV_ABS, ABS_DISTANCE, !tip_state);
+}
+
 static int mt_touch_input_configured(struct hid_device *hdev,
 				     struct hid_input *hi,
 				     struct mt_application *app)
@@ -1334,6 +1447,14 @@  static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		return 1;
 	}
 
+	if (field->application == HID_DG_PEN &&
+	    application->quirks & MT_QUIRK_NON_MT_PEN) {
+		rdata->is_mt_collection = false;
+		rdata->non_mt_pen = true;
+		return mt_pen_input_mapping(hdev, hi, field, usage, bit, max,
+					    application);
+	}
+
 	if (rdata->is_mt_collection)
 		return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
 					      application);
@@ -1357,7 +1478,7 @@  static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 	struct mt_report_data *rdata;
 
 	rdata = mt_find_report_data(td, field->report);
-	if (rdata && rdata->is_mt_collection) {
+	if (rdata && (rdata->is_mt_collection || rdata->non_mt_pen)) {
 		/* We own these mappings, tell hid-input to ignore them */
 		return -1;
 	}
@@ -1391,6 +1512,8 @@  static void mt_report(struct hid_device *hid, struct hid_report *report)
 	rdata = mt_find_report_data(td, report);
 	if (rdata && rdata->is_mt_collection)
 		return mt_touch_report(hid, rdata);
+	if (rdata && rdata->non_mt_pen)
+		mt_pen_report(hid, rdata);
 
 	if (field && field->hidinput && field->hidinput->input)
 		input_sync(field->hidinput->input);
@@ -2120,6 +2243,11 @@  static const struct hid_device_id mt_devices[] = {
 		HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
 			USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) },
 
+	{ .driver_data = MT_CLS_NON_MT_PEN,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			I2C_VENDOR_ID_GOODIX,
+			I2C_DEVICE_ID_GOODIX_0113) },
+
 	/* Generic MT device */
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },