linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices
@ 2018-05-29  9:57 Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot() Benjamin Tissoires
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

Hi Jiri,

this heavy rewrite of hid-multitouch serves two main purposes:
- the first point is to enable the support of the Totem on the Dell Canvas 27.
  This new type of devices (System Multi Axis) is used by Microsoft to show
  a new circular menu that is used by the second hand while you interact with
  your preferred hand with your tool.
  I couldn't enable it before because hid-multitouch expected to have only one
  multitouch collection, and this device is exported as a separate multitouch
  collextion in the same HID device than the one containing the touch sensor.

- the second point is to streamline the process of the multitouch events. We
  used to temporary store the events in a struct as they come in, and then do
  the processing on the cache we just made. When doing the processing was also
  not very clear. This made that even if hid-multitouch should IMO be merged in
  hid-core, we couldn't.

  The new processing of the events here adds a preparsing of the report in
  one HID collection (application usage), and from now on, the processing
  of the report is cleaner IMO. I still haven't merged hid-mt into hid-core,
  because even if I wrote a bunch of unit tests trying to not break any devices,
  we are not protected from a weird thing that magically happened before but is
  now broken.

I must say that when I worked on the tests, I came to realise that some legacy
Win7 devices were better handled now. Initially I thought my new code broke them
but comparing the outputs from https://github.com/bentiss/hid-devices before
and after the changes, the new changes are closer to what I would expect by
looking at the raw HID events.

I also included 2 patches to enable the Surface Dial. It's a BLE device similar
to the Totem from Dell, except that you can buy it for roughly $80 instead of
$1800 for the Canvas.


Dmitry, 2 patches are of interest for you:
- 1/9 Input: mt - export MT_TOOL in input_mt_init_slot()
- 7/9 HID: input: enable Totem on the Dell Canvas 27

The second one exports a new MT_TOOL. In theory, I think patch 1/9 could be
carried through your tree but it'll be better to have the full series applied
at once.

Cheers,
Benjamin

Benjamin Tissoires (9):
  Input: mt - export MT_TOOL in input_mt_init_slot()
  HID: multitouch: make sure the static list of class is not changed
  HID: multitouch: Store per collection multitouch data
  HID: multitouch: store a per application quirks value
  HID: multitouch: ditch mt_report_id
  HID: multitouch: remove one copy of values
  HID: input: enable Totem on the Dell Canvas 27
  HID: core: do not upper bound the collection stack
  HID: microsoft: support the Surface Dial

 drivers/hid/hid-core.c                   |  17 +-
 drivers/hid/hid-input.c                  |   3 +
 drivers/hid/hid-microsoft.c              |  49 +-
 drivers/hid/hid-multitouch.c             | 941 ++++++++++++++++++-------------
 drivers/input/input-mt.c                 |   1 +
 drivers/input/rmi4/rmi_2d_sensor.c       |   2 -
 drivers/input/touchscreen/atmel_mxt_ts.c |   2 -
 drivers/input/touchscreen/hideep.c       |   2 -
 drivers/input/touchscreen/wacom_w8001.c  |   2 -
 include/linux/hid.h                      |  15 +-
 include/uapi/linux/input.h               |   3 +-
 11 files changed, 616 insertions(+), 421 deletions(-)

-- 
2.14.3

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot()
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29 18:21   ` Dmitry Torokhov
  2018-05-29  9:57 ` [PATCH 2/9] HID: multitouch: make sure the static list of class is not changed Benjamin Tissoires
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

Looks like we require users to set a tool but input_mt_init_slots() never
set the tool bit for us. Meaning that this is a useless information the
driver tries to forward.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/input/input-mt.c                 | 1 +
 drivers/input/rmi4/rmi_2d_sensor.c       | 2 --
 drivers/input/touchscreen/atmel_mxt_ts.c | 2 --
 drivers/input/touchscreen/hideep.c       | 2 --
 drivers/input/touchscreen/wacom_w8001.c  | 2 --
 5 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index a1bbec9cda8d..3900686c5d0f 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -57,6 +57,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
 	mt->flags = flags;
 	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
 	input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
+	input_set_abs_params(dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);
 
 	if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
 		__set_bit(EV_KEY, dev->evbit);
diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index 8bb866c7b985..23e666bd2539 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -186,8 +186,6 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
 		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
 		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
 		input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
-		input_set_abs_params(input, ABS_MT_TOOL_TYPE,
-				     0, MT_TOOL_MAX, 0, 0);
 
 		if (sensor->sensor_type == rmi_sensor_touchpad)
 			input_flags = INPUT_MT_POINTER;
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 54fe190fd4bc..0dcf48100dc1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2021,8 +2021,6 @@ static int mxt_initialize_input_device(struct mxt_data *data)
 	}
 
 	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100) {
-		input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
-				     0, MT_TOOL_MAX, 0, 0);
 		input_set_abs_params(input_dev, ABS_MT_DISTANCE,
 				     MXT_DISTANCE_ACTIVE_TOUCH,
 				     MXT_DISTANCE_HOVERING,
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index f1cd4dd9a4a3..980539d8d551 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -799,8 +799,6 @@ static int hideep_init_input(struct hideep_ts *ts)
 	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
 	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 65535, 0, 0);
 	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
-	input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
-			     0, MT_TOOL_MAX, 0, 0);
 	touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
 
 	if (ts->prop.max_x == 0 || ts->prop.max_y == 0) {
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 3715d1eace92..946dca30560b 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -529,8 +529,6 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename,
 					0, touch.x, 0, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_Y,
 					0, touch.y, 0, 0);
-		input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
-					0, MT_TOOL_MAX, 0, 0);
 		input_abs_set_res(dev, ABS_MT_POSITION_X, touch.panel_res);
 		input_abs_set_res(dev, ABS_MT_POSITION_Y, touch.panel_res);
 
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/9] HID: multitouch: make sure the static list of class is not changed
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot() Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 3/9] HID: multitouch: Store per collection multitouch data Benjamin Tissoires
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

const is a magic keyword here :)

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-multitouch.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 38c4ca24343e..187d27f26eec 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -211,7 +211,7 @@ static int cypress_compute_slot(struct mt_device *td)
 		return -1;
 }
 
-static struct mt_class mt_classes[] = {
+static const struct mt_class mt_classes[] = {
 	{ .name = MT_CLS_DEFAULT,
 		.quirks = MT_QUIRK_ALWAYS_VALID |
 			MT_QUIRK_CONTACT_CNT_ACCURATE },
@@ -1429,7 +1429,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	int ret, i;
 	struct mt_device *td;
-	struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
+	const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
 
 	for (i = 0; mt_classes[i].name ; i++) {
 		if (id->driver_data == mt_classes[i].name) {
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/9] HID: multitouch: Store per collection multitouch data
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot() Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 2/9] HID: multitouch: make sure the static list of class is not changed Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 4/9] HID: multitouch: store a per application quirks value Benjamin Tissoires
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

Currently, hid-multitouch can only handle one multitouch collection at
a time. This is an issue for the Dell Canvas, as the Totem (a dial tool)
is also using a multitouch-like collection.

Factor out the multitouch collection data in their own struct.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-multitouch.c | 376 ++++++++++++++++++++++++++-----------------
 1 file changed, 230 insertions(+), 146 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 187d27f26eec..b3eb43ce2969 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -28,14 +28,11 @@
  */
 
 /*
- * This driver is regularly tested thanks to the tool hid-test[1].
- * This tool relies on hid-replay[2] and a database of hid devices[3].
+ * This driver is regularly tested thanks to the test suite in hid-tools[1].
  * Please run these regression tests before patching this module so that
  * your patch won't break existing known devices.
  *
- * [1] https://github.com/bentiss/hid-test
- * [2] https://github.com/bentiss/hid-replay
- * [3] https://github.com/bentiss/hid-devices
+ * [1] https://github.com/bentiss/hid-tools
  */
 
 #include <linux/device.h>
@@ -99,6 +96,37 @@ struct mt_slot {
 	bool has_azimuth;       /* the contact reports azimuth */
 };
 
+struct mt_application {
+	struct list_head list;
+	unsigned int application;
+	struct mt_slot curdata;		/* placeholder of incoming data */
+
+	int cc_index;	/* contact count field index in the report */
+	int cc_value_index;	/* contact count value index in the field */
+	int scantime_index;	/* scantime field index in the report */
+	int scantime_val_index;	/* scantime value index in the field */
+	unsigned int last_slot_field;	/* the last field of a slot */
+	bool curvalid;		/* is the current contact valid? */
+
+	int left_button_state;		/* left button state */
+	unsigned int mt_flags;		/* flags to pass to input-mt */
+
+	__u8 num_received;	/* how many contacts we received */
+	__u8 num_expected;	/* expected last contact index */
+	__u8 buttons_count;	/* number of physical buttons per touchpad */
+	__u8 touches_by_report;	/* how many touches are present in one report:
+				 * 1 means we should use a serial protocol
+				 * > 1 means hybrid (multitouch) protocol
+				 */
+
+	__s32 dev_time;		/* the scan time provided by the device */
+	unsigned long jiffies;	/* the frame's jiffies */
+	int timestamp;		/* the timestamp to be sent */
+	int prev_scantime;		/* scantime reported previously */
+
+	bool have_contact_count;
+};
+
 struct mt_class {
 	__s32 name;	/* MT_CLS */
 	__s32 quirks;
@@ -117,40 +145,24 @@ struct mt_fields {
 };
 
 struct mt_device {
-	struct mt_slot curdata;	/* placeholder of incoming data */
 	struct mt_class mtclass;	/* our mt device class */
 	struct timer_list release_timer;	/* to release sticky fingers */
 	struct hid_device *hdev;	/* hid_device we're attached to */
 	struct mt_fields *fields;	/* temporary placeholder for storing the
 					   multitouch fields */
 	unsigned long mt_io_flags;	/* mt flags (MT_IO_FLAGS_*) */
-	int cc_index;	/* contact count field index in the report */
-	int cc_value_index;	/* contact count value index in the field */
-	int scantime_index;	/* scantime field index in the report */
-	int scantime_val_index;	/* scantime value index in the field */
-	int prev_scantime;	/* scantime reported in the previous packet */
-	int left_button_state;	/* left button state */
-	unsigned last_slot_field;	/* the last field of a slot */
 	unsigned mt_report_id;	/* the report ID of the multitouch device */
 	__u8 inputmode_value;	/* InputMode HID feature value */
-	__u8 num_received;	/* how many contacts we received */
-	__u8 num_expected;	/* expected last contact index */
 	__u8 maxcontacts;
-	__u8 touches_by_report;	/* how many touches are present in one report:
-				* 1 means we should use a serial protocol
-				* > 1 means hybrid (multitouch) protocol */
-	__u8 buttons_count;	/* number of physical buttons per touchpad */
 	bool is_buttonpad;	/* is this device a button pad? */
 	bool serial_maybe;	/* need to check for serial protocol */
-	bool curvalid;		/* is the current contact valid? */
-	unsigned mt_flags;	/* flags to pass to input-mt */
-	__s32 dev_time;		/* the scan time provided by the device */
-	unsigned long jiffies;	/* the frame's jiffies */
-	int timestamp;		/* the timestamp to be sent */
+
+	struct list_head applications;
 };
 
-static void mt_post_parse_default_settings(struct mt_device *td);
-static void mt_post_parse(struct mt_device *td);
+static void mt_post_parse_default_settings(struct mt_device *td,
+					   struct mt_application *app);
+static void mt_post_parse(struct mt_device *td, struct mt_application *app);
 
 /* classes of device behavior */
 #define MT_CLS_DEFAULT				0x0001
@@ -203,10 +215,10 @@ static void mt_post_parse(struct mt_device *td);
  * to a valid contact that was just read.
  */
 
-static int cypress_compute_slot(struct mt_device *td)
+static int cypress_compute_slot(struct mt_application *app)
 {
-	if (td->curdata.contactid != 0 || td->num_received == 0)
-		return td->curdata.contactid;
+	if (app->curdata.contactid != 0 || app->num_received == 0)
+		return app->curdata.contactid;
 	else
 		return -1;
 }
@@ -353,15 +365,22 @@ static ssize_t mt_set_quirks(struct device *dev,
 {
 	struct hid_device *hdev = to_hid_device(dev);
 	struct mt_device *td = hid_get_drvdata(hdev);
+	struct mt_application *application;
 
 	unsigned long val;
+	bool confidence_found = false;
 
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
 
 	td->mtclass.quirks = val;
 
-	if (td->cc_index < 0)
+	list_for_each_entry(application, &td->applications, list) {
+		if (application->have_contact_count)
+			confidence_found = true;
+	}
+
+	if (!confidence_found)
 		td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 
 	return count;
@@ -457,6 +476,55 @@ static void set_abs(struct input_dev *input, unsigned int code,
 	input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
 }
 
+static struct mt_application *mt_allocate_application(struct mt_device *td,
+						      unsigned int application)
+{
+	struct mt_application *mt_application;
+
+	mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application),
+				      GFP_KERNEL);
+	if (!mt_application)
+		return NULL;
+
+	mt_application->application = application;
+
+	if (application == HID_DG_TOUCHSCREEN)
+		mt_application->mt_flags |= INPUT_MT_DIRECT;
+
+	/*
+	 * Model touchscreens providing buttons as touchpads.
+	 */
+	if (application == HID_DG_TOUCHPAD) {
+		mt_application->mt_flags |= INPUT_MT_POINTER;
+		td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
+	}
+
+	mt_application->cc_index = -1;
+	mt_application->scantime_index = -1;
+
+	list_add_tail(&mt_application->list, &td->applications);
+
+	return mt_application;
+}
+
+static struct mt_application *mt_find_application(struct mt_device *td,
+						  unsigned int application)
+{
+	struct mt_application *tmp, *mt_application = NULL;
+
+	list_for_each_entry(tmp, &td->applications, list) {
+		if (application == tmp->application) {
+			mt_application = tmp;
+			break;
+		}
+	}
+
+	if (!mt_application)
+		mt_application = mt_allocate_application(td, application);
+
+	return mt_application;
+}
+
 static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
 		struct hid_input *hi)
 {
@@ -470,28 +538,24 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
 
 static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned long **bit, int *max, struct mt_application *app)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
 	struct mt_class *cls = &td->mtclass;
 	int code;
 	struct hid_usage *prev_usage = NULL;
 
-	if (field->application == HID_DG_TOUCHSCREEN)
-		td->mt_flags |= INPUT_MT_DIRECT;
-
 	/*
 	 * Model touchscreens providing buttons as touchpads.
 	 */
-	if (field->application == HID_DG_TOUCHPAD ||
-	    (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
-		td->mt_flags |= INPUT_MT_POINTER;
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
+		app->mt_flags |= INPUT_MT_POINTER;
 		td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
 	}
 
 	/* count the buttons on touchpads */
 	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
-		td->buttons_count++;
+		app->buttons_count++;
 
 	if (usage->usage_index)
 		prev_usage = &field->usage[usage->usage_index - 1];
@@ -501,33 +565,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	case HID_UP_GENDESK:
 		switch (usage->hid) {
 		case HID_GD_X:
-			if (prev_usage && (prev_usage->hid == usage->hid)) {
-				hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_TOOL_X);
-				set_abs(hi->input, ABS_MT_TOOL_X, field,
-					cls->sn_move);
-			} else {
-				hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_POSITION_X);
-				set_abs(hi->input, ABS_MT_POSITION_X, field,
-					cls->sn_move);
-			}
+			if (prev_usage && (prev_usage->hid == usage->hid))
+				code = ABS_MT_TOOL_X;
+			else
+				code = ABS_MT_POSITION_X;
 
+			hid_map_usage(hi, usage, bit, max, EV_ABS, code);
+			set_abs(hi->input, code, field, cls->sn_move);
 			mt_store_field(usage, td, hi);
 			return 1;
 		case HID_GD_Y:
-			if (prev_usage && (prev_usage->hid == usage->hid)) {
-				hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_TOOL_Y);
-				set_abs(hi->input, ABS_MT_TOOL_Y, field,
-					cls->sn_move);
-			} else {
-				hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_POSITION_Y);
-				set_abs(hi->input, ABS_MT_POSITION_Y, field,
-					cls->sn_move);
-			}
+			if (prev_usage && (prev_usage->hid == usage->hid))
+				code = ABS_MT_TOOL_Y;
+			else
+				code = ABS_MT_POSITION_Y;
 
+			hid_map_usage(hi, usage, bit, max, EV_ABS, code);
+			set_abs(hi->input, code, field, cls->sn_move);
 			mt_store_field(usage, td, hi);
 			return 1;
 		}
@@ -558,7 +612,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 			return 1;
 		case HID_DG_CONTACTID:
 			mt_store_field(usage, td, hi);
-			td->touches_by_report++;
+			app->touches_by_report++;
 			td->mt_report_id = field->report->id;
 			return 1;
 		case HID_DG_WIDTH:
@@ -603,16 +657,16 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 			if (field->index >= field->report->maxfield ||
 			    usage->usage_index >= field->report_count)
 				return 1;
-			td->scantime_index = field->index;
-			td->scantime_val_index = usage->usage_index;
+			app->scantime_index = field->index;
+			app->scantime_val_index = usage->usage_index;
 			return 1;
 		case HID_DG_CONTACTCOUNT:
 			/* Ignore if indexes are out of bounds. */
 			if (field->index >= field->report->maxfield ||
 			    usage->usage_index >= field->report_count)
 				return 1;
-			td->cc_index = field->index;
-			td->cc_value_index = usage->usage_index;
+			app->cc_index = field->index;
+			app->cc_value_index = usage->usage_index;
 			return 1;
 		case HID_DG_AZIMUTH:
 			hid_map_usage(hi, usage, bit, max,
@@ -663,39 +717,41 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	return 0;
 }
 
-static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
+static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
+			   struct input_dev *input)
 {
 	__s32 quirks = td->mtclass.quirks;
 
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
-		return td->curdata.contactid;
+		return app->curdata.contactid;
 
 	if (quirks & MT_QUIRK_CYPRESS)
-		return cypress_compute_slot(td);
+		return cypress_compute_slot(app);
 
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
-		return td->num_received;
+		return app->num_received;
 
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
-		return td->curdata.contactid - 1;
+		return app->curdata.contactid - 1;
 
-	return input_mt_get_slot_by_key(input, td->curdata.contactid);
+	return input_mt_get_slot_by_key(input, app->curdata.contactid);
 }
 
 /*
  * this function is called when a whole contact has been processed,
  * so that it can assign it to a slot and store the data there
  */
-static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
+static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
+			     struct input_dev *input)
 {
 	if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
-	    td->num_received >= td->num_expected)
+	    app->num_received >= app->num_expected)
 		return;
 
-	if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
+	if (app->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
 		int active;
-		int slotnum = mt_compute_slot(td, input);
-		struct mt_slot *s = &td->curdata;
+		int slotnum = mt_compute_slot(td, app, input);
+		struct mt_slot *s = &app->curdata;
 		struct input_mt *mt = input->mt;
 
 		if (slotnum < 0 || slotnum >= td->maxcontacts)
@@ -750,23 +806,25 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 		}
 	}
 
-	td->num_received++;
+	app->num_received++;
 }
 
 /*
  * this function is called when a whole packet has been received and processed,
  * so that it can decide what to send to the input layer.
  */
-static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
+static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
+			  struct input_dev *input)
 {
 	if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
-		input_event(input, EV_KEY, BTN_LEFT, td->left_button_state);
+		input_event(input, EV_KEY, BTN_LEFT, app->left_button_state);
 
 	input_mt_sync_frame(input);
-	input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp);
+	input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp);
 	input_sync(input);
-	td->num_received = 0;
-	td->left_button_state = 0;
+	app->num_received = 0;
+	app->left_button_state = 0;
+
 	if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
 		set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
 	else
@@ -774,14 +832,13 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
 	clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
 }
 
-static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
-		__s32 value)
+static int mt_compute_timestamp(struct mt_application *app,
+				struct hid_field *field, __s32 value)
 {
-	long delta = value - td->dev_time;
-	unsigned long jdelta = jiffies_to_usecs(jiffies - td->jiffies);
+	long delta = value - app->prev_scantime;
+	unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
 
-	td->jiffies = jiffies;
-	td->dev_time = value;
+	app->jiffies = jiffies;
 
 	if (delta < 0)
 		delta += field->logical_maximum;
@@ -793,7 +850,7 @@ static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
 		/* No data received for a while, resync the timestamp. */
 		return 0;
 	else
-		return td->timestamp + delta;
+		return app->timestamp + delta;
 }
 
 static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
@@ -808,7 +865,7 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
 
 static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 				struct hid_usage *usage, __s32 value,
-				bool first_packet)
+				struct mt_application *app, bool first_packet)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
 	__s32 quirks = td->mtclass.quirks;
@@ -818,47 +875,48 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 		switch (usage->hid) {
 		case HID_DG_INRANGE:
 			if (quirks & MT_QUIRK_VALID_IS_INRANGE)
-				td->curvalid = value;
+				app->curvalid = value;
 			if (quirks & MT_QUIRK_HOVERING)
-				td->curdata.inrange_state = value;
+				app->curdata.inrange_state = value;
 			break;
 		case HID_DG_TIPSWITCH:
 			if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
-				td->curvalid = value;
-			td->curdata.touch_state = value;
+				app->curvalid = value;
+			app->curdata.touch_state = value;
 			break;
 		case HID_DG_CONFIDENCE:
 			if (quirks & MT_QUIRK_CONFIDENCE)
-				td->curdata.confidence_state = value;
+				app->curdata.confidence_state = value;
 			if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
-				td->curvalid = value;
+				app->curvalid = value;
 			break;
 		case HID_DG_CONTACTID:
-			td->curdata.contactid = value;
+			app->curdata.contactid = value;
 			break;
 		case HID_DG_TIPPRESSURE:
-			td->curdata.p = value;
+			app->curdata.p = value;
 			break;
 		case HID_GD_X:
 			if (usage->code == ABS_MT_TOOL_X)
-				td->curdata.cx = value;
+				app->curdata.cx = value;
 			else
-				td->curdata.x = value;
+				app->curdata.x = value;
 			break;
 		case HID_GD_Y:
 			if (usage->code == ABS_MT_TOOL_Y)
-				td->curdata.cy = value;
+				app->curdata.cy = value;
 			else
-				td->curdata.y = value;
+				app->curdata.y = value;
 			break;
 		case HID_DG_WIDTH:
-			td->curdata.w = value;
+			app->curdata.w = value;
 			break;
 		case HID_DG_HEIGHT:
-			td->curdata.h = value;
+			app->curdata.h = value;
 			break;
 		case HID_DG_SCANTIME:
-			td->timestamp = mt_compute_timestamp(td, field, value);
+			app->timestamp = mt_compute_timestamp(app, field,
+							      value);
 			break;
 		case HID_DG_CONTACTCOUNT:
 			break;
@@ -875,8 +933,8 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 			 */
 			if (value > field->logical_maximum / 2)
 				value -= field->logical_maximum;
-			td->curdata.a = -value;
-			td->curdata.has_azimuth = true;
+			app->curdata.a = -value;
+			app->curdata.has_azimuth = true;
 			break;
 		case HID_DG_TOUCH:
 			/* do nothing */
@@ -901,7 +959,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 			 */
 			if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
 			    usage->type == EV_KEY && usage->code == BTN_LEFT) {
-				td->left_button_state |= value;
+				app->left_button_state |= value;
 				return;
 			}
 
@@ -913,8 +971,9 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 
 		if (usage->usage_index + 1 == field->report_count) {
 			/* we only take into account the last report. */
-			if (usage->hid == td->last_slot_field)
-				mt_complete_slot(td, field->hidinput->input);
+			if (usage->hid == app->last_slot_field)
+				mt_complete_slot(td, app,
+						 field->hidinput->input);
 		}
 
 	}
@@ -923,26 +982,34 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
+	struct mt_application *app;
 	struct hid_field *field;
 	bool first_packet;
 	unsigned count;
-	int r, n, scantime = 0;
+	int r, n;
+	int scantime = 0;
+	int contact_count = -1;
 
 	/* sticky fingers release in progress, abort */
 	if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
 		return;
 
+	app = mt_find_application(td, report->application);
+
+	if (!app)
+		return;
+
 	/*
 	 * Includes multi-packet support where subsequent
 	 * packets are sent with zero contactcount.
 	 */
-	if (td->scantime_index >= 0) {
-		field = report->field[td->scantime_index];
-		scantime = field->value[td->scantime_val_index];
+	if (app->scantime_index >= 0) {
+		field = report->field[app->scantime_index];
+		scantime = field->value[app->scantime_val_index];
 	}
-	if (td->cc_index >= 0) {
-		struct hid_field *field = report->field[td->cc_index];
-		int value = field->value[td->cc_value_index];
+	if (app->cc_index >= 0) {
+		field = report->field[app->cc_index];
+		contact_count = field->value[app->cc_value_index];
 
 		/*
 		 * For Win8 PTPs the first packet (td->num_received == 0) may
@@ -952,15 +1019,16 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 		 * timestamp has changed.
 		 */
 		if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
-		    td->num_received == 0 && td->prev_scantime != scantime)
-			td->num_expected = value;
+		    app->num_received == 0 &&
+		    app->prev_scantime != scantime)
+			app->num_expected = contact_count;
 		/* A non 0 contact count always indicates a first packet */
-		else if (value)
-			td->num_expected = value;
+		else if (contact_count)
+			app->num_expected = contact_count;
 	}
-	td->prev_scantime = scantime;
+	app->prev_scantime = scantime;
 
-	first_packet = td->num_received == 0;
+	first_packet = app->num_received == 0;
 	for (r = 0; r < report->maxfield; r++) {
 		field = report->field[r];
 		count = field->report_count;
@@ -970,11 +1038,11 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 
 		for (n = 0; n < count; n++)
 			mt_process_mt_event(hid, field, &field->usage[n],
-					    field->value[n], first_packet);
+					    field->value[n], app, first_packet);
 	}
 
-	if (td->num_received >= td->num_expected)
-		mt_sync_frame(td, report->field[0]->hidinput->input);
+	if (app->num_received >= app->num_expected)
+		mt_sync_frame(td, app, report->field[0]->hidinput->input);
 
 	/*
 	 * Windows 8 specs says 2 things:
@@ -1006,7 +1074,8 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 }
 
 static int mt_touch_input_configured(struct hid_device *hdev,
-					struct hid_input *hi)
+				     struct hid_input *hi,
+				     struct mt_application *app)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
 	struct mt_class *cls = &td->mtclass;
@@ -1016,28 +1085,29 @@ static int mt_touch_input_configured(struct hid_device *hdev,
 	if (!td->maxcontacts)
 		td->maxcontacts = MT_DEFAULT_MAXCONTACT;
 
-	mt_post_parse(td);
+	mt_post_parse(td, app);
 	if (td->serial_maybe)
-		mt_post_parse_default_settings(td);
+		mt_post_parse_default_settings(td, app);
 
 	if (cls->is_indirect)
-		td->mt_flags |= INPUT_MT_POINTER;
+		app->mt_flags |= INPUT_MT_POINTER;
 
 	if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
-		td->mt_flags |= INPUT_MT_DROP_UNUSED;
+		app->mt_flags |= INPUT_MT_DROP_UNUSED;
 
 	/* check for clickpads */
-	if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1))
+	if ((app->mt_flags & INPUT_MT_POINTER) &&
+	    (app->buttons_count == 1))
 		td->is_buttonpad = true;
 
 	if (td->is_buttonpad)
 		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 
-	ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+	ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags);
 	if (ret)
 		return ret;
 
-	td->mt_flags = 0;
+	app->mt_flags = 0;
 	return 0;
 }
 
@@ -1048,6 +1118,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		unsigned long **bit, int *max)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
+	struct mt_application *application;
 
 	/*
 	 * If mtclass.export_all_inputs is not set, only map fields from
@@ -1090,6 +1161,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		return 1;
 	}
 
+	application = mt_find_application(td, field->application);
+
 	/*
 	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
 	 * for the stylus.
@@ -1106,7 +1179,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 
 	if (field->application == HID_DG_TOUCHSCREEN ||
 	    field->application == HID_DG_TOUCHPAD)
-		return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+		return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
+					      application);
 
 	/* let hid-core decide for the others */
 	return 0;
@@ -1256,12 +1330,13 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
 	}
 }
 
-static void mt_post_parse_default_settings(struct mt_device *td)
+static void mt_post_parse_default_settings(struct mt_device *td,
+					   struct mt_application *app)
 {
 	__s32 quirks = td->mtclass.quirks;
 
 	/* unknown serial device needs special quirks */
-	if (td->touches_by_report == 1) {
+	if (app->touches_by_report == 1) {
 		quirks |= MT_QUIRK_ALWAYS_VALID;
 		quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
 		quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
@@ -1272,17 +1347,19 @@ static void mt_post_parse_default_settings(struct mt_device *td)
 	td->mtclass.quirks = quirks;
 }
 
-static void mt_post_parse(struct mt_device *td)
+static void mt_post_parse(struct mt_device *td, struct mt_application *app)
 {
 	struct mt_fields *f = td->fields;
 	struct mt_class *cls = &td->mtclass;
 
-	if (td->touches_by_report > 0) {
-		int field_count_per_touch = f->length / td->touches_by_report;
-		td->last_slot_field = f->usages[field_count_per_touch - 1];
+	if (app->touches_by_report > 0) {
+		int field_count_per_touch;
+
+		field_count_per_touch = f->length / app->touches_by_report;
+		app->last_slot_field = f->usages[field_count_per_touch - 1];
 	}
 
-	if (td->cc_index < 0)
+	if (app->cc_index < 0)
 		cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 }
 
@@ -1292,13 +1369,17 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 	char *name;
 	const char *suffix = NULL;
 	unsigned int application = 0;
+	struct mt_application *mt_application = NULL;
 	struct hid_report *report;
 	int ret;
 
 	list_for_each_entry(report, &hi->reports, hidinput_list) {
 		application = report->application;
+		mt_application = mt_find_application(td, application);
+
 		if (report->id == td->mt_report_id) {
-			ret = mt_touch_input_configured(hdev, hi);
+			ret = mt_touch_input_configured(hdev, hi,
+							mt_application);
 			if (ret)
 				return ret;
 		}
@@ -1387,6 +1468,7 @@ static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage)
 static void mt_release_contacts(struct hid_device *hid)
 {
 	struct hid_input *hidinput;
+	struct mt_application *application;
 	struct mt_device *td = hid_get_drvdata(hid);
 
 	list_for_each_entry(hidinput, &hid->inputs, list) {
@@ -1406,7 +1488,9 @@ static void mt_release_contacts(struct hid_device *hid)
 		}
 	}
 
-	td->num_received = 0;
+	list_for_each_entry(application, &td->applications, list) {
+		application->num_received = 0;
+	}
 }
 
 static void mt_expired_timeout(struct timer_list *t)
@@ -1446,11 +1530,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	td->hdev = hdev;
 	td->mtclass = *mtclass;
 	td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
-	td->cc_index = -1;
-	td->scantime_index = -1;
 	td->mt_report_id = -1;
 	hid_set_drvdata(hdev, td);
 
+	INIT_LIST_HEAD(&td->applications);
+
 	td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
 				  GFP_KERNEL);
 	if (!td->fields) {
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/9] HID: multitouch: store a per application quirks value
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
                   ` (2 preceding siblings ...)
  2018-05-29  9:57 ` [PATCH 3/9] HID: multitouch: Store per collection multitouch data Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 5/9] HID: multitouch: ditch mt_report_id Benjamin Tissoires
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

If a device has more than one multitouch collection, there is a chance
we need per tool quirks. This is the case for the Totem on the Dell
Canvas.

Note that thesysfs attribute quirks can now get out of sync, but there
should not be much users of it as it's debugging only.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-multitouch.c | 64 ++++++++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index b3eb43ce2969..9356e4ba4e01 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -99,6 +99,9 @@ struct mt_slot {
 struct mt_application {
 	struct list_head list;
 	unsigned int application;
+
+	__s32 quirks;
+
 	struct mt_slot curdata;		/* placeholder of incoming data */
 
 	int cc_index;	/* contact count field index in the report */
@@ -368,7 +371,6 @@ static ssize_t mt_set_quirks(struct device *dev,
 	struct mt_application *application;
 
 	unsigned long val;
-	bool confidence_found = false;
 
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
@@ -376,13 +378,11 @@ static ssize_t mt_set_quirks(struct device *dev,
 	td->mtclass.quirks = val;
 
 	list_for_each_entry(application, &td->applications, list) {
-		if (application->have_contact_count)
-			confidence_found = true;
+		application->quirks = val;
+		if (!application->have_contact_count)
+			application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 	}
 
-	if (!confidence_found)
-		td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
-
 	return count;
 }
 
@@ -501,6 +501,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
 
 	mt_application->cc_index = -1;
 	mt_application->scantime_index = -1;
+	mt_application->quirks = td->mtclass.quirks;
 
 	list_add_tail(&mt_application->list, &td->applications);
 
@@ -590,7 +591,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	case HID_UP_DIGITIZER:
 		switch (usage->hid) {
 		case HID_DG_INRANGE:
-			if (cls->quirks & MT_QUIRK_HOVERING) {
+			if (app->quirks & MT_QUIRK_HOVERING) {
 				hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_DISTANCE);
 				input_set_abs_params(hi->input,
@@ -602,7 +603,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 			if ((cls->name == MT_CLS_WIN_8 ||
 				cls->name == MT_CLS_WIN_8_DUAL) &&
 				field->application == HID_DG_TOUCHPAD)
-				cls->quirks |= MT_QUIRK_CONFIDENCE;
+				app->quirks |= MT_QUIRK_CONFIDENCE;
 			mt_store_field(usage, td, hi);
 			return 1;
 		case HID_DG_TIPSWITCH:
@@ -618,7 +619,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		case HID_DG_WIDTH:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_TOUCH_MAJOR);
-			if (!(cls->quirks & MT_QUIRK_NO_AREA))
+			if (!(app->quirks & MT_QUIRK_NO_AREA))
 				set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
 					cls->sn_width);
 			mt_store_field(usage, td, hi);
@@ -626,7 +627,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		case HID_DG_HEIGHT:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_TOUCH_MINOR);
-			if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
+			if (!(app->quirks & MT_QUIRK_NO_AREA)) {
 				set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
 					cls->sn_height);
 
@@ -701,7 +702,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		 * MS PTP spec says that external buttons left and right have
 		 * usages 2 and 3.
 		 */
-		if ((cls->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
+		if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
 		    field->application == HID_DG_TOUCHPAD &&
 		    (usage->hid & HID_USAGE) > 1)
 			code--;
@@ -720,7 +721,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
 			   struct input_dev *input)
 {
-	__s32 quirks = td->mtclass.quirks;
+	__s32 quirks = app->quirks;
 
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
 		return app->curdata.contactid;
@@ -744,11 +745,11 @@ static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
 static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
 			     struct input_dev *input)
 {
-	if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
+	if ((app->quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
 	    app->num_received >= app->num_expected)
 		return;
 
-	if (app->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
+	if (app->curvalid || (app->quirks & MT_QUIRK_ALWAYS_VALID)) {
 		int active;
 		int slotnum = mt_compute_slot(td, app, input);
 		struct mt_slot *s = &app->curdata;
@@ -757,14 +758,14 @@ static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
 		if (slotnum < 0 || slotnum >= td->maxcontacts)
 			return;
 
-		if ((td->mtclass.quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
+		if ((app->quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
 			struct input_mt_slot *slot = &mt->slots[slotnum];
 			if (input_mt_is_active(slot) &&
 			    input_mt_is_used(mt, slot))
 				return;
 		}
 
-		if (!(td->mtclass.quirks & MT_QUIRK_CONFIDENCE))
+		if (!(app->quirks & MT_QUIRK_CONFIDENCE))
 			s->confidence_state = true;
 		active = (s->touch_state || s->inrange_state) &&
 							s->confidence_state;
@@ -785,7 +786,7 @@ static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
 			 * divided by two to match visual scale of touch
 			 * for devices with this quirk
 			 */
-			if (td->mtclass.quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
+			if (app->quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
 				major = major >> 1;
 				minor = minor >> 1;
 			}
@@ -816,7 +817,7 @@ static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
 static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
 			  struct input_dev *input)
 {
-	if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
+	if (app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
 		input_event(input, EV_KEY, BTN_LEFT, app->left_button_state);
 
 	input_mt_sync_frame(input);
@@ -868,7 +869,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 				struct mt_application *app, bool first_packet)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
-	__s32 quirks = td->mtclass.quirks;
+	__s32 quirks = app->quirks;
 	struct input_dev *input = field->hidinput->input;
 
 	if (hid->claimed & HID_CLAIMED_INPUT) {
@@ -1018,7 +1019,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 		 * of a possible multi-packet frame be checking that the
 		 * timestamp has changed.
 		 */
-		if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
+		if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
 		    app->num_received == 0 &&
 		    app->prev_scantime != scantime)
 			app->num_expected = contact_count;
@@ -1062,7 +1063,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 	 * only affect laggish machines and the ones that have a firmware
 	 * defect.
 	 */
-	if (td->mtclass.quirks & MT_QUIRK_STICKY_FINGERS) {
+	if (app->quirks & MT_QUIRK_STICKY_FINGERS) {
 		if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
 			mod_timer(&td->release_timer,
 				  jiffies + msecs_to_jiffies(100));
@@ -1092,7 +1093,7 @@ static int mt_touch_input_configured(struct hid_device *hdev,
 	if (cls->is_indirect)
 		app->mt_flags |= INPUT_MT_POINTER;
 
-	if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+	if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
 		app->mt_flags |= INPUT_MT_DROP_UNUSED;
 
 	/* check for clickpads */
@@ -1120,6 +1121,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	struct mt_device *td = hid_get_drvdata(hdev);
 	struct mt_application *application;
 
+	application = mt_find_application(td, field->application);
+
 	/*
 	 * If mtclass.export_all_inputs is not set, only map fields from
 	 * TouchScreen or TouchPad collections. We need to ignore fields
@@ -1135,7 +1138,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	    field->application != HID_CP_CONSUMER_CONTROL &&
 	    field->application != HID_GD_WIRELESS_RADIO_CTLS &&
 	    !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
-	      td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP))
+	      application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
 		return -1;
 
 	/*
@@ -1144,7 +1147,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	 * map usages to input keys.
 	 */
 	if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
-	    td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP &&
+	    application->quirks & MT_QUIRK_ASUS_CUSTOM_UP &&
 	    (usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) {
 		set_bit(EV_REP, hi->input->evbit);
 		if (field->flags & HID_MAIN_ITEM_VARIABLE)
@@ -1161,8 +1164,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		return 1;
 	}
 
-	application = mt_find_application(td, field->application);
-
 	/*
 	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
 	 * for the stylus.
@@ -1268,9 +1269,9 @@ static bool mt_need_to_apply_feature(struct hid_device *hdev,
 		return true;
 
 	case HID_DG_CONTACTMAX:
-		if (td->mtclass.maxcontacts) {
+		if (cls->maxcontacts) {
 			max = min_t(int, field->logical_maximum,
-				    td->mtclass.maxcontacts);
+				    cls->maxcontacts);
 			if (field->value[index] != max) {
 				field->value[index] = max;
 				return true;
@@ -1333,7 +1334,7 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
 static void mt_post_parse_default_settings(struct mt_device *td,
 					   struct mt_application *app)
 {
-	__s32 quirks = td->mtclass.quirks;
+	__s32 quirks = app->quirks;
 
 	/* unknown serial device needs special quirks */
 	if (app->touches_by_report == 1) {
@@ -1344,13 +1345,12 @@ static void mt_post_parse_default_settings(struct mt_device *td,
 		quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 	}
 
-	td->mtclass.quirks = quirks;
+	app->quirks = quirks;
 }
 
 static void mt_post_parse(struct mt_device *td, struct mt_application *app)
 {
 	struct mt_fields *f = td->fields;
-	struct mt_class *cls = &td->mtclass;
 
 	if (app->touches_by_report > 0) {
 		int field_count_per_touch;
@@ -1360,7 +1360,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
 	}
 
 	if (app->cc_index < 0)
-		cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
+		app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 }
 
 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/9] HID: multitouch: ditch mt_report_id
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
                   ` (3 preceding siblings ...)
  2018-05-29  9:57 ` [PATCH 4/9] HID: multitouch: store a per application quirks value Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 6/9] HID: multitouch: remove one copy of values Benjamin Tissoires
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

Now that the driver can handle more than one multitouch collection in
a single HID device, ditch the last bit that contains us to use only
one mt collection.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-multitouch.c | 126 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 94 insertions(+), 32 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 9356e4ba4e01..ff763c0b936a 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -147,6 +147,13 @@ struct mt_fields {
 	unsigned int length;
 };
 
+struct mt_report_data {
+	struct list_head list;
+	struct hid_report *report;
+	struct mt_application *application;
+	bool is_mt_collection;
+};
+
 struct mt_device {
 	struct mt_class mtclass;	/* our mt device class */
 	struct timer_list release_timer;	/* to release sticky fingers */
@@ -154,13 +161,13 @@ struct mt_device {
 	struct mt_fields *fields;	/* temporary placeholder for storing the
 					   multitouch fields */
 	unsigned long mt_io_flags;	/* mt flags (MT_IO_FLAGS_*) */
-	unsigned mt_report_id;	/* the report ID of the multitouch device */
 	__u8 inputmode_value;	/* InputMode HID feature value */
 	__u8 maxcontacts;
 	bool is_buttonpad;	/* is this device a button pad? */
 	bool serial_maybe;	/* need to check for serial protocol */
 
 	struct list_head applications;
+	struct list_head reports;
 };
 
 static void mt_post_parse_default_settings(struct mt_device *td,
@@ -526,6 +533,60 @@ static struct mt_application *mt_find_application(struct mt_device *td,
 	return mt_application;
 }
 
+static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
+						      struct hid_report *report)
+{
+	struct mt_report_data *rdata;
+	struct hid_field *field;
+	int r, n;
+
+	rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL);
+	if (!rdata)
+		return NULL;
+
+	rdata->report = report;
+	rdata->application = mt_find_application(td, report->application);
+
+	if (!rdata->application) {
+		devm_kfree(&td->hdev->dev, rdata);
+		return NULL;
+	}
+
+	for (r = 0; r < report->maxfield; r++) {
+		field = report->field[r];
+
+		if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
+			continue;
+
+		for (n = 0; n < field->report_count; n++) {
+			if (field->usage[n].hid == HID_DG_CONTACTID)
+				rdata->is_mt_collection = true;
+		}
+	}
+
+	list_add_tail(&rdata->list, &td->reports);
+
+	return rdata;
+}
+
+static struct mt_report_data *mt_find_report_data(struct mt_device *td,
+						  struct hid_report *report)
+{
+	struct mt_report_data *tmp, *rdata = NULL;
+
+	list_for_each_entry(tmp, &td->reports, list) {
+		if (report == tmp->report) {
+			rdata = tmp;
+			break;
+		}
+	}
+
+	if (!rdata)
+		rdata = mt_allocate_report_data(td, report);
+
+	return rdata;
+}
+
 static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
 		struct hid_input *hi)
 {
@@ -614,7 +675,6 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		case HID_DG_CONTACTID:
 			mt_store_field(usage, td, hi);
 			app->touches_by_report++;
-			td->mt_report_id = field->report->id;
 			return 1;
 		case HID_DG_WIDTH:
 			hid_map_usage(hi, usage, bit, max,
@@ -980,10 +1040,12 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 	}
 }
 
-static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
+static void mt_touch_report(struct hid_device *hid,
+			    struct mt_report_data *rdata)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
-	struct mt_application *app;
+	struct hid_report *report = rdata->report;
+	struct mt_application *app = rdata->application;
 	struct hid_field *field;
 	bool first_packet;
 	unsigned count;
@@ -995,11 +1057,6 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 	if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
 		return;
 
-	app = mt_find_application(td, report->application);
-
-	if (!app)
-		return;
-
 	/*
 	 * Includes multi-packet support where subsequent
 	 * packets are sent with zero contactcount.
@@ -1120,8 +1177,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
 	struct mt_application *application;
+	struct mt_report_data *rdata;
+
+	rdata = mt_find_report_data(td, field->report);
+	if (!rdata) {
+		hid_err(hdev, "failed to allocate data for report\n");
+		return 0;
+	}
 
-	application = mt_find_application(td, field->application);
+	application = rdata->application;
 
 	/*
 	 * If mtclass.export_all_inputs is not set, only map fields from
@@ -1164,22 +1228,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		return 1;
 	}
 
-	/*
-	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
-	 * for the stylus.
-	 * The check for mt_report_id ensures we don't process
-	 * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical
-	 * collection, but within the report ID.
-	 */
-	if (field->physical == HID_DG_STYLUS)
-		return 0;
-	else if ((field->physical == 0) &&
-		 (field->report->id != td->mt_report_id) &&
-		 (td->mt_report_id != -1))
-		return 0;
-
-	if (field->application == HID_DG_TOUCHSCREEN ||
-	    field->application == HID_DG_TOUCHPAD)
+	if (rdata->is_mt_collection &&
+	    (field->application == HID_DG_TOUCHSCREEN ||
+	     field->application == HID_DG_TOUCHPAD))
 		return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
 					      application);
 
@@ -1212,8 +1263,10 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
 				struct hid_usage *usage, __s32 value)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
+	struct mt_report_data *rdata;
 
-	if (field->report->id == td->mt_report_id)
+	rdata = mt_find_report_data(td, field->report);
+	if (rdata && rdata->is_mt_collection)
 		return mt_touch_event(hid, field, usage, value);
 
 	return 0;
@@ -1223,12 +1276,14 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
 	struct hid_field *field = report->field[0];
+	struct mt_report_data *rdata;
 
 	if (!(hid->claimed & HID_CLAIMED_INPUT))
 		return;
 
-	if (report->id == td->mt_report_id)
-		return mt_touch_report(hid, report);
+	rdata = mt_find_report_data(td, report);
+	if (rdata && rdata->is_mt_collection)
+		return mt_touch_report(hid, rdata);
 
 	if (field && field->hidinput && field->hidinput->input)
 		input_sync(field->hidinput->input);
@@ -1369,15 +1424,22 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 	char *name;
 	const char *suffix = NULL;
 	unsigned int application = 0;
+	struct mt_report_data *rdata;
 	struct mt_application *mt_application = NULL;
 	struct hid_report *report;
 	int ret;
 
 	list_for_each_entry(report, &hi->reports, hidinput_list) {
 		application = report->application;
-		mt_application = mt_find_application(td, application);
+		rdata = mt_find_report_data(td, report);
+		if (!rdata) {
+			hid_err(hdev, "failed to allocate data for report\n");
+			return -ENOMEM;
+		}
+
+		mt_application = rdata->application;
 
-		if (report->id == td->mt_report_id) {
+		if (rdata->is_mt_collection) {
 			ret = mt_touch_input_configured(hdev, hi,
 							mt_application);
 			if (ret)
@@ -1530,10 +1592,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	td->hdev = hdev;
 	td->mtclass = *mtclass;
 	td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
-	td->mt_report_id = -1;
 	hid_set_drvdata(hdev, td);
 
 	INIT_LIST_HEAD(&td->applications);
+	INIT_LIST_HEAD(&td->reports);
 
 	td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
 				  GFP_KERNEL);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 6/9] HID: multitouch: remove one copy of values
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
                   ` (4 preceding siblings ...)
  2018-05-29  9:57 ` [PATCH 5/9] HID: multitouch: ditch mt_report_id Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 7/9] HID: input: enable Totem on the Dell Canvas 27 Benjamin Tissoires
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

The current way of handling multitouch data is not very straightforward:
- in mt_event() we do nothing
- in mt_report() we:
  - do some gym to fetch the scantime and the contact count
  - then iterate over the input fields where we copy the data to a
    temporary place
  - when we see the last field in a slot, we then use this data to emit
    the input data

A more streamlined way is to first get all of the address in the report
of all fields, and then just pick the fields we are interested in in
mt_report()

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-multitouch.c | 546 +++++++++++++++++++++----------------------
 1 file changed, 264 insertions(+), 282 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index ff763c0b936a..424fb5f66b7d 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -87,30 +87,34 @@ enum latency_mode {
 #define MT_IO_FLAGS_ACTIVE_SLOTS	1
 #define MT_IO_FLAGS_PENDING_SLOTS	2
 
-struct mt_slot {
-	__s32 x, y, cx, cy, p, w, h, a;
-	__s32 contactid;	/* the device ContactID assigned to this slot */
-	bool touch_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 has_azimuth;       /* the contact reports azimuth */
+static const bool mtrue = true;		/* default for true */
+static const bool mfalse;		/* default for false */
+static const __s32 mzero;		/* default for 0 */
+
+#define DEFAULT_TRUE	((void *)&mtrue)
+#define DEFAULT_FALSE	((void *)&mfalse)
+#define DEFAULT_ZERO	((void *)&mzero)
+
+struct mt_usages {
+	struct list_head list;
+	__s32 *x, *y, *cx, *cy, *p, *w, *h, *a;
+	__s32 *contactid;	/* the device ContactID assigned to this slot */
+	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? */
 };
 
 struct mt_application {
 	struct list_head list;
 	unsigned int application;
+	struct list_head mt_usages;	/* mt usages list */
 
 	__s32 quirks;
 
-	struct mt_slot curdata;		/* placeholder of incoming data */
-
-	int cc_index;	/* contact count field index in the report */
-	int cc_value_index;	/* contact count value index in the field */
-	int scantime_index;	/* scantime field index in the report */
-	int scantime_val_index;	/* scantime value index in the field */
-	unsigned int last_slot_field;	/* the last field of a slot */
-	bool curvalid;		/* is the current contact valid? */
+	__s32 *scantime;		/* scantime reported */
+	__s32 scantime_logical_max;	/* max value for raw scantime */
 
+	__s32 *raw_cc;			/* contact count in the report */
 	int left_button_state;		/* left button state */
 	unsigned int mt_flags;		/* flags to pass to input-mt */
 
@@ -142,11 +146,6 @@ struct mt_class {
 	bool export_all_inputs;	/* do not ignore mouse, keyboards, etc... */
 };
 
-struct mt_fields {
-	unsigned usages[HID_MAX_FIELDS];
-	unsigned int length;
-};
-
 struct mt_report_data {
 	struct list_head list;
 	struct hid_report *report;
@@ -158,8 +157,6 @@ struct mt_device {
 	struct mt_class mtclass;	/* our mt device class */
 	struct timer_list release_timer;	/* to release sticky fingers */
 	struct hid_device *hdev;	/* hid_device we're attached to */
-	struct mt_fields *fields;	/* temporary placeholder for storing the
-					   multitouch fields */
 	unsigned long mt_io_flags;	/* mt flags (MT_IO_FLAGS_*) */
 	__u8 inputmode_value;	/* InputMode HID feature value */
 	__u8 maxcontacts;
@@ -225,10 +222,11 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
  * to a valid contact that was just read.
  */
 
-static int cypress_compute_slot(struct mt_application *app)
+static int cypress_compute_slot(struct mt_application *application,
+				struct mt_usages *slot)
 {
-	if (app->curdata.contactid != 0 || app->num_received == 0)
-		return app->curdata.contactid;
+	if (*slot->contactid != 0 || application->num_received == 0)
+		return *slot->contactid;
 	else
 		return -1;
 }
@@ -483,6 +481,34 @@ static void set_abs(struct input_dev *input, unsigned int code,
 	input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
 }
 
+static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
+					   struct mt_application *application)
+{
+	struct mt_usages *usage;
+
+	usage = devm_kzalloc(&hdev->dev, sizeof(*usage), GFP_KERNEL);
+	if (!usage)
+		return NULL;
+
+	/* set some defaults so we do not need to check for null pointers */
+	usage->x = DEFAULT_ZERO;
+	usage->y = DEFAULT_ZERO;
+	usage->cx = DEFAULT_ZERO;
+	usage->cy = DEFAULT_ZERO;
+	usage->p = DEFAULT_ZERO;
+	usage->w = DEFAULT_ZERO;
+	usage->h = DEFAULT_ZERO;
+	usage->a = DEFAULT_ZERO;
+	usage->contactid = DEFAULT_ZERO;
+	usage->tip_state = DEFAULT_FALSE;
+	usage->inrange_state = DEFAULT_FALSE;
+	usage->confidence_state = DEFAULT_TRUE;
+
+	list_add_tail(&usage->list, &application->mt_usages);
+
+	return usage;
+}
+
 static struct mt_application *mt_allocate_application(struct mt_device *td,
 						      unsigned int application)
 {
@@ -494,6 +520,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
 		return NULL;
 
 	mt_application->application = application;
+	INIT_LIST_HEAD(&mt_application->mt_usages);
 
 	if (application == HID_DG_TOUCHSCREEN)
 		mt_application->mt_flags |= INPUT_MT_DIRECT;
@@ -506,8 +533,8 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
 		td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
 	}
 
-	mt_application->cc_index = -1;
-	mt_application->scantime_index = -1;
+	mt_application->scantime = DEFAULT_ZERO;
+	mt_application->raw_cc = DEFAULT_ZERO;
 	mt_application->quirks = td->mtclass.quirks;
 
 	list_add_tail(&mt_application->list, &td->applications);
@@ -587,17 +614,45 @@ static struct mt_report_data *mt_find_report_data(struct mt_device *td,
 	return rdata;
 }
 
-static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
-		struct hid_input *hi)
+static void mt_store_field(struct hid_device *hdev,
+			   struct mt_application *application,
+			   __s32 *value,
+			   size_t offset)
 {
-	struct mt_fields *f = td->fields;
+	struct mt_usages *usage;
+	__s32 **target;
+
+	if (list_empty(&application->mt_usages))
+		usage = mt_allocate_usage(hdev, application);
+	else
+		usage = list_last_entry(&application->mt_usages,
+					struct mt_usages,
+					list);
 
-	if (f->length >= HID_MAX_FIELDS)
+	if (!usage)
 		return;
 
-	f->usages[f->length++] = usage->hid;
+	target = (__s32 **)((char *)usage + offset);
+
+	/* the value has already been filled, create a new slot */
+	if (*target != DEFAULT_TRUE &&
+	    *target != DEFAULT_FALSE &&
+	    *target != DEFAULT_ZERO) {
+		usage = mt_allocate_usage(hdev, application);
+		if (!usage)
+			return;
+
+		target = (__s32 **)((char *)usage + offset);
+	}
+
+	*target = value;
 }
 
+#define MT_STORE_FIELD(__name)						\
+	mt_store_field(hdev, app,					\
+		       &field->value[usage->usage_index],		\
+		       offsetof(struct mt_usages, __name))
+
 static int mt_touch_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)
@@ -627,24 +682,28 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	case HID_UP_GENDESK:
 		switch (usage->hid) {
 		case HID_GD_X:
-			if (prev_usage && (prev_usage->hid == usage->hid))
+			if (prev_usage && (prev_usage->hid == usage->hid)) {
 				code = ABS_MT_TOOL_X;
-			else
+				MT_STORE_FIELD(cx);
+			} else {
 				code = ABS_MT_POSITION_X;
+				MT_STORE_FIELD(x);
+			}
 
-			hid_map_usage(hi, usage, bit, max, EV_ABS, code);
 			set_abs(hi->input, code, field, cls->sn_move);
-			mt_store_field(usage, td, hi);
+
 			return 1;
 		case HID_GD_Y:
-			if (prev_usage && (prev_usage->hid == usage->hid))
+			if (prev_usage && (prev_usage->hid == usage->hid)) {
 				code = ABS_MT_TOOL_Y;
-			else
+				MT_STORE_FIELD(cy);
+			} else {
 				code = ABS_MT_POSITION_Y;
+				MT_STORE_FIELD(y);
+			}
 
-			hid_map_usage(hi, usage, bit, max, EV_ABS, code);
 			set_abs(hi->input, code, field, cls->sn_move);
-			mt_store_field(usage, td, hi);
+
 			return 1;
 		}
 		return 0;
@@ -653,40 +712,33 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		switch (usage->hid) {
 		case HID_DG_INRANGE:
 			if (app->quirks & MT_QUIRK_HOVERING) {
-				hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_DISTANCE);
 				input_set_abs_params(hi->input,
 					ABS_MT_DISTANCE, 0, 1, 0, 0);
 			}
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(inrange_state);
 			return 1;
 		case HID_DG_CONFIDENCE:
 			if ((cls->name == MT_CLS_WIN_8 ||
 				cls->name == MT_CLS_WIN_8_DUAL) &&
 				field->application == HID_DG_TOUCHPAD)
 				app->quirks |= MT_QUIRK_CONFIDENCE;
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(confidence_state);
 			return 1;
 		case HID_DG_TIPSWITCH:
-			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
 			input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(tip_state);
 			return 1;
 		case HID_DG_CONTACTID:
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(contactid);
 			app->touches_by_report++;
 			return 1;
 		case HID_DG_WIDTH:
-			hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_TOUCH_MAJOR);
 			if (!(app->quirks & MT_QUIRK_NO_AREA))
 				set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
 					cls->sn_width);
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(w);
 			return 1;
 		case HID_DG_HEIGHT:
-			hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_TOUCH_MINOR);
 			if (!(app->quirks & MT_QUIRK_NO_AREA)) {
 				set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
 					cls->sn_height);
@@ -700,38 +752,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 					input_set_abs_params(hi->input,
 						ABS_MT_ORIENTATION, 0, 1, 0, 0);
 			}
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(h);
 			return 1;
 		case HID_DG_TIPPRESSURE:
-			hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_PRESSURE);
 			set_abs(hi->input, ABS_MT_PRESSURE, field,
 				cls->sn_pressure);
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(p);
 			return 1;
 		case HID_DG_SCANTIME:
-			hid_map_usage(hi, usage, bit, max,
-				EV_MSC, MSC_TIMESTAMP);
 			input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
-			mt_store_field(usage, td, hi);
-			/* Ignore if indexes are out of bounds. */
-			if (field->index >= field->report->maxfield ||
-			    usage->usage_index >= field->report_count)
-				return 1;
-			app->scantime_index = field->index;
-			app->scantime_val_index = usage->usage_index;
+			app->scantime = &field->value[usage->usage_index];
+			app->scantime_logical_max = field->logical_maximum;
 			return 1;
 		case HID_DG_CONTACTCOUNT:
-			/* Ignore if indexes are out of bounds. */
-			if (field->index >= field->report->maxfield ||
-			    usage->usage_index >= field->report_count)
-				return 1;
-			app->cc_index = field->index;
-			app->cc_value_index = usage->usage_index;
+			app->have_contact_count = true;
+			app->raw_cc = &field->value[usage->usage_index];
 			return 1;
 		case HID_DG_AZIMUTH:
-			hid_map_usage(hi, usage, bit, max,
-				EV_ABS, ABS_MT_ORIENTATION);
 			/*
 			 * Azimuth has the range of [0, MAX) representing a full
 			 * revolution. Set ABS_MT_ORIENTATION to a quarter of
@@ -742,11 +779,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 				field->logical_maximum / 4,
 				cls->sn_move ?
 				field->logical_maximum / cls->sn_move : 0, 0);
-			mt_store_field(usage, td, hi);
+			MT_STORE_FIELD(a);
 			return 1;
 		case HID_DG_CONTACTMAX:
-			/* we don't set td->last_slot_field as contactcount and
-			 * contact max are global to the report */
+			/* contact max are global to the report */
 			return -1;
 		case HID_DG_TOUCH:
 			/* Legacy devices use TIPSWITCH and not TOUCH.
@@ -779,95 +815,24 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 }
 
 static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
+			   struct mt_usages *slot,
 			   struct input_dev *input)
 {
 	__s32 quirks = app->quirks;
 
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
-		return app->curdata.contactid;
+		return *slot->contactid;
 
 	if (quirks & MT_QUIRK_CYPRESS)
-		return cypress_compute_slot(app);
+		return cypress_compute_slot(app, slot);
 
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
 		return app->num_received;
 
 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
-		return app->curdata.contactid - 1;
+		return *slot->contactid - 1;
 
-	return input_mt_get_slot_by_key(input, app->curdata.contactid);
-}
-
-/*
- * this function is called when a whole contact has been processed,
- * so that it can assign it to a slot and store the data there
- */
-static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
-			     struct input_dev *input)
-{
-	if ((app->quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
-	    app->num_received >= app->num_expected)
-		return;
-
-	if (app->curvalid || (app->quirks & MT_QUIRK_ALWAYS_VALID)) {
-		int active;
-		int slotnum = mt_compute_slot(td, app, input);
-		struct mt_slot *s = &app->curdata;
-		struct input_mt *mt = input->mt;
-
-		if (slotnum < 0 || slotnum >= td->maxcontacts)
-			return;
-
-		if ((app->quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
-			struct input_mt_slot *slot = &mt->slots[slotnum];
-			if (input_mt_is_active(slot) &&
-			    input_mt_is_used(mt, slot))
-				return;
-		}
-
-		if (!(app->quirks & MT_QUIRK_CONFIDENCE))
-			s->confidence_state = true;
-		active = (s->touch_state || s->inrange_state) &&
-							s->confidence_state;
-
-		input_mt_slot(input, slotnum);
-		input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
-		if (active) {
-			/* this finger is in proximity of the sensor */
-			int wide = (s->w > s->h);
-			int major = max(s->w, s->h);
-			int minor = min(s->w, s->h);
-			int orientation = wide;
-
-			if (s->has_azimuth)
-				orientation = s->a;
-
-			/*
-			 * divided by two to match visual scale of touch
-			 * for devices with this quirk
-			 */
-			if (app->quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
-				major = major >> 1;
-				minor = minor >> 1;
-			}
-
-			input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
-			input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
-			input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx);
-			input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
-			input_event(input, EV_ABS, ABS_MT_DISTANCE,
-				!s->touch_state);
-			input_event(input, EV_ABS, ABS_MT_ORIENTATION,
-				orientation);
-			input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
-			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
-			input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
-
-			set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
-		}
-	}
-
-	app->num_received++;
+	return input_mt_get_slot_by_key(input, *slot->contactid);
 }
 
 /*
@@ -893,8 +858,7 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
 	clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
 }
 
-static int mt_compute_timestamp(struct mt_application *app,
-				struct hid_field *field, __s32 value)
+static int mt_compute_timestamp(struct mt_application *app, __s32 value)
 {
 	long delta = value - app->prev_scantime;
 	unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
@@ -902,7 +866,7 @@ static int mt_compute_timestamp(struct mt_application *app,
 	app->jiffies = jiffies;
 
 	if (delta < 0)
-		delta += field->logical_maximum;
+		delta += app->scantime_logical_max;
 
 	/* HID_DG_SCANTIME is expressed in 100us, we want it in us. */
 	delta *= 100;
@@ -924,64 +888,69 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
 	return 1;
 }
 
-static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
-				struct hid_usage *usage, __s32 value,
-				struct mt_application *app, bool first_packet)
+static int mt_process_slot(struct mt_device *td, struct input_dev *input,
+			    struct mt_application *app,
+			    struct mt_usages *slot)
 {
-	struct mt_device *td = hid_get_drvdata(hid);
+	struct input_mt *mt = input->mt;
 	__s32 quirks = app->quirks;
-	struct input_dev *input = field->hidinput->input;
+	bool valid = true;
+	bool confidence_state = true;
+	bool inrange_state = false;
+	int active;
+	int slotnum;
 
-	if (hid->claimed & HID_CLAIMED_INPUT) {
-		switch (usage->hid) {
-		case HID_DG_INRANGE:
-			if (quirks & MT_QUIRK_VALID_IS_INRANGE)
-				app->curvalid = value;
-			if (quirks & MT_QUIRK_HOVERING)
-				app->curdata.inrange_state = value;
-			break;
-		case HID_DG_TIPSWITCH:
-			if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
-				app->curvalid = value;
-			app->curdata.touch_state = value;
-			break;
-		case HID_DG_CONFIDENCE:
-			if (quirks & MT_QUIRK_CONFIDENCE)
-				app->curdata.confidence_state = value;
-			if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
-				app->curvalid = value;
-			break;
-		case HID_DG_CONTACTID:
-			app->curdata.contactid = value;
-			break;
-		case HID_DG_TIPPRESSURE:
-			app->curdata.p = value;
-			break;
-		case HID_GD_X:
-			if (usage->code == ABS_MT_TOOL_X)
-				app->curdata.cx = value;
-			else
-				app->curdata.x = value;
-			break;
-		case HID_GD_Y:
-			if (usage->code == ABS_MT_TOOL_Y)
-				app->curdata.cy = value;
-			else
-				app->curdata.y = value;
-			break;
-		case HID_DG_WIDTH:
-			app->curdata.w = value;
-			break;
-		case HID_DG_HEIGHT:
-			app->curdata.h = value;
-			break;
-		case HID_DG_SCANTIME:
-			app->timestamp = mt_compute_timestamp(app, field,
-							      value);
-			break;
-		case HID_DG_CONTACTCOUNT:
-			break;
-		case HID_DG_AZIMUTH:
+	if (!slot)
+		return -EINVAL;
+
+	if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
+	    app->num_received >= app->num_expected)
+		return -EAGAIN;
+
+	if (!(quirks & MT_QUIRK_ALWAYS_VALID)) {
+		if (quirks & MT_QUIRK_VALID_IS_INRANGE)
+			valid = *slot->inrange_state;
+		if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+			valid = *slot->tip_state;
+		if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
+			valid = *slot->confidence_state;
+
+		if (!valid)
+			return 0;
+	}
+
+	slotnum = mt_compute_slot(td, app, slot, input);
+	if (slotnum < 0 || slotnum >= td->maxcontacts)
+		return 0;
+
+	if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
+		struct input_mt_slot *i_slot = &mt->slots[slotnum];
+
+		if (input_mt_is_active(i_slot) &&
+		    input_mt_is_used(mt, i_slot))
+			return -EAGAIN;
+	}
+
+	if (quirks & MT_QUIRK_CONFIDENCE)
+		confidence_state = *slot->confidence_state;
+
+	if (quirks & MT_QUIRK_HOVERING)
+		inrange_state = *slot->inrange_state;
+
+	active = (*slot->tip_state || inrange_state) && confidence_state;
+
+	input_mt_slot(input, slotnum);
+	input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
+	if (active) {
+		/* this finger is in proximity of the sensor */
+		int wide = (*slot->w > *slot->h);
+		int major = max(*slot->w, *slot->h);
+		int minor = min(*slot->w, *slot->h);
+		int orientation = wide;
+		int max_azimuth;
+		int azimuth;
+
+		if (slot->a != DEFAULT_ZERO) {
 			/*
 			 * Azimuth is counter-clockwise and ranges from [0, MAX)
 			 * (a full revolution). Convert it to clockwise ranging
@@ -992,52 +961,76 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 			 * out of range to [-MAX/2, MAX/2] to report an upside
 			 * down ellipsis.
 			 */
-			if (value > field->logical_maximum / 2)
-				value -= field->logical_maximum;
-			app->curdata.a = -value;
-			app->curdata.has_azimuth = true;
-			break;
-		case HID_DG_TOUCH:
-			/* do nothing */
-			break;
+			azimuth = *slot->a;
+			max_azimuth = input_abs_get_max(input,
+							ABS_MT_ORIENTATION);
+			if (azimuth > max_azimuth * 2)
+				azimuth -= max_azimuth * 4;
+			orientation = -azimuth;
+		}
 
-		default:
-			/*
-			 * For Win8 PTP touchpads we should only look at
-			 * non finger/touch events in the first_packet of
-			 * a (possible) multi-packet frame.
-			 */
-			if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
-			    !first_packet)
-				return;
+		/*
+		 * divided by two to match visual scale of touch
+		 * for devices with this quirk
+		 */
+		if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
+			major = major >> 1;
+			minor = minor >> 1;
+		}
 
-			/*
-			 * For Win8 PTP touchpads we map both the clickpad click
-			 * and any "external" left buttons to BTN_LEFT if a
-			 * device claims to have both we need to report 1 for
-			 * BTN_LEFT if either is pressed, so we or all values
-			 * together and report the result in mt_sync_frame().
-			 */
-			if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
-			    usage->type == EV_KEY && usage->code == BTN_LEFT) {
-				app->left_button_state |= value;
-				return;
-			}
+		input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
+		input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
+		input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
+		input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
+		input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
+		input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
+		input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p);
+		input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+		input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+
+		set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
+	}
 
-			if (usage->type)
-				input_event(input, usage->type, usage->code,
-						value);
+	return 0;
+}
+
+static void mt_process_mt_event(struct hid_device *hid,
+				struct mt_application *app,
+				struct hid_field *field,
+				struct hid_usage *usage,
+				__s32 value,
+				bool first_packet)
+{
+	__s32 quirks = app->quirks;
+	struct input_dev *input = field->hidinput->input;
+
+	if (!usage->type || !(hid->claimed & HID_CLAIMED_INPUT))
+		return;
+
+	if (quirks & MT_QUIRK_WIN8_PTP_BUTTONS) {
+
+		/*
+		 * For Win8 PTP touchpads we should only look at
+		 * non finger/touch events in the first_packet of a
+		 * (possible) multi-packet frame.
+		 */
+		if (!first_packet)
 			return;
-		}
 
-		if (usage->usage_index + 1 == field->report_count) {
-			/* we only take into account the last report. */
-			if (usage->hid == app->last_slot_field)
-				mt_complete_slot(td, app,
-						 field->hidinput->input);
+		/*
+		 * For Win8 PTP touchpads we map both the clickpad click
+		 * and any "external" left buttons to BTN_LEFT if a
+		 * device claims to have both we need to report 1 for
+		 * BTN_LEFT if either is pressed, so we or all values
+		 * together and report the result in mt_sync_frame().
+		 */
+		if (usage->type == EV_KEY && usage->code == BTN_LEFT) {
+			app->left_button_state |= value;
+			return;
 		}
-
 	}
+
+	input_event(input, usage->type, usage->code, value);
 }
 
 static void mt_touch_report(struct hid_device *hid,
@@ -1047,6 +1040,8 @@ static void mt_touch_report(struct hid_device *hid,
 	struct hid_report *report = rdata->report;
 	struct mt_application *app = rdata->application;
 	struct hid_field *field;
+	struct input_dev *input;
+	struct mt_usages *slot;
 	bool first_packet;
 	unsigned count;
 	int r, n;
@@ -1057,18 +1052,16 @@ static void mt_touch_report(struct hid_device *hid,
 	if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
 		return;
 
+	scantime = *app->scantime;
+	app->timestamp = mt_compute_timestamp(app, scantime);
+	if (app->raw_cc != DEFAULT_ZERO)
+		contact_count = *app->raw_cc;
+
 	/*
 	 * Includes multi-packet support where subsequent
 	 * packets are sent with zero contactcount.
 	 */
-	if (app->scantime_index >= 0) {
-		field = report->field[app->scantime_index];
-		scantime = field->value[app->scantime_val_index];
-	}
-	if (app->cc_index >= 0) {
-		field = report->field[app->cc_index];
-		contact_count = field->value[app->cc_value_index];
-
+	if (contact_count >= 0) {
 		/*
 		 * For Win8 PTPs the first packet (td->num_received == 0) may
 		 * have a contactcount of 0 if there only is a button event.
@@ -1087,6 +1080,14 @@ static void mt_touch_report(struct hid_device *hid,
 	app->prev_scantime = scantime;
 
 	first_packet = app->num_received == 0;
+
+	input = report->field[0]->hidinput->input;
+
+	list_for_each_entry(slot, &app->mt_usages, list) {
+		if (!mt_process_slot(td, input, app, slot))
+			app->num_received++;
+	}
+
 	for (r = 0; r < report->maxfield; r++) {
 		field = report->field[r];
 		count = field->report_count;
@@ -1095,12 +1096,13 @@ static void mt_touch_report(struct hid_device *hid,
 			continue;
 
 		for (n = 0; n < count; n++)
-			mt_process_mt_event(hid, field, &field->usage[n],
-					    field->value[n], app, first_packet);
+			mt_process_mt_event(hid, app, field,
+					    &field->usage[n], field->value[n],
+					    first_packet);
 	}
 
 	if (app->num_received >= app->num_expected)
-		mt_sync_frame(td, app, report->field[0]->hidinput->input);
+		mt_sync_frame(td, app, input);
 
 	/*
 	 * Windows 8 specs says 2 things:
@@ -1392,7 +1394,7 @@ static void mt_post_parse_default_settings(struct mt_device *td,
 	__s32 quirks = app->quirks;
 
 	/* unknown serial device needs special quirks */
-	if (app->touches_by_report == 1) {
+	if (list_is_singular(&app->mt_usages)) {
 		quirks |= MT_QUIRK_ALWAYS_VALID;
 		quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
 		quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
@@ -1405,16 +1407,7 @@ static void mt_post_parse_default_settings(struct mt_device *td,
 
 static void mt_post_parse(struct mt_device *td, struct mt_application *app)
 {
-	struct mt_fields *f = td->fields;
-
-	if (app->touches_by_report > 0) {
-		int field_count_per_touch;
-
-		field_count_per_touch = f->length / app->touches_by_report;
-		app->last_slot_field = f->usages[field_count_per_touch - 1];
-	}
-
-	if (app->cc_index < 0)
+	if (!app->have_contact_count)
 		app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 }
 
@@ -1597,13 +1590,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	INIT_LIST_HEAD(&td->applications);
 	INIT_LIST_HEAD(&td->reports);
 
-	td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
-				  GFP_KERNEL);
-	if (!td->fields) {
-		dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
-		return -ENOMEM;
-	}
-
 	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
 		td->serial_maybe = true;
 
@@ -1639,10 +1625,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 	mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
 
-	/* release .fields memory as it is not used anymore */
-	devm_kfree(&hdev->dev, td->fields);
-	td->fields = NULL;
-
 	return 0;
 }
 
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 7/9] HID: input: enable Totem on the Dell Canvas 27
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
                   ` (5 preceding siblings ...)
  2018-05-29  9:57 ` [PATCH 6/9] HID: multitouch: remove one copy of values Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29  9:57 ` [PATCH 8/9] HID: core: do not upper bound the collection stack Benjamin Tissoires
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

The Dell Canvas 27 has a tool that can be put on the surface and acts
as a dial. The firmware processes the detection of the tool and forward
regular HID reports with X, Y, Azimuth, rotation, width/height.

The firmware also exports Contact ID, Countact Count which may hint that
several totems can be used at the same time (the FW only supports one).

We need a way to express that MT_TOOL_DIAL will be reported. However,
there is not much to do besides adding a new ioctl, so we will currently
use a special udev hwdb entries in user space.

This tool is aimed at being used by the system and not the applications,
so the user space processing should not go through the regular touch
inputs.
We set INPUT_PROP_DIRECT which applies ID_INPUT_TOUCHSCREEN to this new
type of devices, but we will counter this for the time being with the
special udev hwdb entry mentioned above.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=1511846

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-input.c      |  3 +++
 drivers/hid/hid-multitouch.c | 43 +++++++++++++++++++++++++++++--------------
 include/linux/hid.h          |  6 ++++++
 include/uapi/linux/input.h   |  3 ++-
 4 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index ab93dd5927c3..4e94ea3e280a 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1550,6 +1550,9 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
 		case HID_GD_WIRELESS_RADIO_CTLS:
 			suffix = "Wireless Radio Control";
 			break;
+		case HID_GD_SYSTEM_MULTIAXIS:
+			suffix = "System Multi Axis";
+			break;
 		default:
 			break;
 		}
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 424fb5f66b7d..fa56b0b020df 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -665,7 +665,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	/*
 	 * Model touchscreens providing buttons as touchpads.
 	 */
-	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
+	if (field->application == HID_DG_TOUCHSCREEN &&
+	    (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
 		app->mt_flags |= INPUT_MT_POINTER;
 		td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
 	}
@@ -692,6 +693,14 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 
 			set_abs(hi->input, code, field, cls->sn_move);
 
+			/*
+			 * A system multi-axis that exports X and Y has a high
+			 * chance of being used directly on a surface
+			 */
+			if (field->application == HID_GD_SYSTEM_MULTIAXIS)
+				__set_bit(INPUT_PROP_DIRECT,
+					  hi->input->propbit);
+
 			return 1;
 		case HID_GD_Y:
 			if (prev_usage && (prev_usage->hid == usage->hid)) {
@@ -725,7 +734,9 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 			MT_STORE_FIELD(confidence_state);
 			return 1;
 		case HID_DG_TIPSWITCH:
-			input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
+			if (field->application != HID_GD_SYSTEM_MULTIAXIS)
+				input_set_capability(hi->input,
+						     EV_KEY, BTN_TOUCH);
 			MT_STORE_FIELD(tip_state);
 			return 1;
 		case HID_DG_CONTACTID:
@@ -802,6 +813,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		    field->application == HID_DG_TOUCHPAD &&
 		    (usage->hid & HID_USAGE) > 1)
 			code--;
+
+		if (field->application == HID_GD_SYSTEM_MULTIAXIS)
+			code = BTN_0  + ((usage->hid - 1) & HID_USAGE);
+
 		hid_map_usage(hi, usage, bit, max, EV_KEY, code);
 		input_set_capability(hi->input, EV_KEY, code);
 		return 1;
@@ -899,6 +914,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
 	bool inrange_state = false;
 	int active;
 	int slotnum;
+	int tool = MT_TOOL_FINGER;
 
 	if (!slot)
 		return -EINVAL;
@@ -939,8 +955,11 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
 
 	active = (*slot->tip_state || inrange_state) && confidence_state;
 
+	if (app->application == HID_GD_SYSTEM_MULTIAXIS)
+		tool = MT_TOOL_DIAL;
+
 	input_mt_slot(input, slotnum);
-	input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
+	input_mt_report_slot_state(input, tool, active);
 	if (active) {
 		/* this finger is in proximity of the sensor */
 		int wide = (*slot->w > *slot->h);
@@ -1203,6 +1222,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	    field->application != HID_GD_SYSTEM_CONTROL &&
 	    field->application != HID_CP_CONSUMER_CONTROL &&
 	    field->application != HID_GD_WIRELESS_RADIO_CTLS &&
+	    field->application != HID_GD_SYSTEM_MULTIAXIS &&
 	    !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
 	      application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
 		return -1;
@@ -1230,9 +1250,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		return 1;
 	}
 
-	if (rdata->is_mt_collection &&
-	    (field->application == HID_DG_TOUCHSCREEN ||
-	     field->application == HID_DG_TOUCHPAD))
+	if (rdata->is_mt_collection)
 		return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
 					      application);
 
@@ -1244,15 +1262,11 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
-	/*
-	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
-	 * for the stylus.
-	 */
-	if (field->physical == HID_DG_STYLUS)
-		return 0;
+	struct mt_device *td = hid_get_drvdata(hdev);
+	struct mt_report_data *rdata;
 
-	if (field->application == HID_DG_TOUCHSCREEN ||
-	    field->application == HID_DG_TOUCHPAD) {
+	rdata = mt_find_report_data(td, field->report);
+	if (rdata && rdata->is_mt_collection) {
 		/* We own these mappings, tell hid-input to ignore them */
 		return -1;
 	}
@@ -1460,6 +1474,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 		case HID_GD_SYSTEM_CONTROL:
 		case HID_CP_CONSUMER_CONTROL:
 		case HID_GD_WIRELESS_RADIO_CTLS:
+		case HID_GD_SYSTEM_MULTIAXIS:
 			/* already handled by hid core */
 			break;
 		case HID_DG_TOUCHSCREEN:
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 41a3d5775394..9caa193e0c67 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -190,6 +190,12 @@ struct hid_item {
  * http://www.usb.org/developers/hidpage/HUTRR40RadioHIDUsagesFinal.pdf
  */
 #define HID_GD_WIRELESS_RADIO_CTLS	0x0001000c
+/*
+ * System Multi-Axis, see:
+ * http://www.usb.org/developers/hidpage/HUTRR62_-_Generic_Desktop_CA_for_System_Multi-Axis_Controllers.txt
+ */
+#define HID_GD_SYSTEM_MULTIAXIS	0x0001000e
+
 #define HID_GD_X		0x00010030
 #define HID_GD_Y		0x00010031
 #define HID_GD_Z		0x00010032
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 7288a7c573cc..e01caa038778 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -273,7 +273,8 @@ struct input_mask {
 #define MT_TOOL_FINGER		0
 #define MT_TOOL_PEN		1
 #define MT_TOOL_PALM		2
-#define MT_TOOL_MAX		2
+#define MT_TOOL_DIAL		3
+#define MT_TOOL_MAX		3
 
 /*
  * Values describing the status of a force-feedback effect
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 8/9] HID: core: do not upper bound the collection stack
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
                   ` (6 preceding siblings ...)
  2018-05-29  9:57 ` [PATCH 7/9] HID: input: enable Totem on the Dell Canvas 27 Benjamin Tissoires
@ 2018-05-29  9:57 ` Benjamin Tissoires
  2018-05-29  9:58 ` [PATCH 9/9] HID: microsoft: support the Surface Dial Benjamin Tissoires
  2018-05-29 10:38 ` [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Florian Echtler
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:57 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

Looks like 4 was sufficient until now. However, the Surface Dial needs
a stack of 5 and simply fails at probing.
Dynamically add HID_COLLECTION_STACK_SIZE to the size of the stack if
we hit the upper bound.

Checkpatch complains about bare unsigned, so converting those to
'unsigned int' in struct hid_parser

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-core.c | 17 ++++++++++++++---
 include/linux/hid.h    |  9 +++++----
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 355dc7e49562..2f7367b1de00 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -128,9 +128,19 @@ static int open_collection(struct hid_parser *parser, unsigned type)
 
 	usage = parser->local.usage[0];
 
-	if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
-		hid_err(parser->device, "collection stack overflow\n");
-		return -EINVAL;
+	if (parser->collection_stack_ptr == parser->collection_stack_size) {
+		unsigned int *collection_stack;
+		unsigned int new_size = parser->collection_stack_size +
+					HID_COLLECTION_STACK_SIZE;
+
+		collection_stack = krealloc(parser->collection_stack,
+					    new_size * sizeof(unsigned int),
+					    GFP_KERNEL);
+		if (!collection_stack)
+			return -ENOMEM;
+
+		parser->collection_stack = collection_stack;
+		parser->collection_stack_size = new_size;
 	}
 
 	if (parser->device->maxcollection == parser->device->collection_size) {
@@ -837,6 +847,7 @@ static int hid_scan_report(struct hid_device *hid)
 		break;
 	}
 
+	kfree(parser->collection_stack);
 	vfree(parser);
 	return 0;
 }
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 9caa193e0c67..ee2510019033 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -643,12 +643,13 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
 struct hid_parser {
 	struct hid_global     global;
 	struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
-	unsigned              global_stack_ptr;
+	unsigned int          global_stack_ptr;
 	struct hid_local      local;
-	unsigned              collection_stack[HID_COLLECTION_STACK_SIZE];
-	unsigned              collection_stack_ptr;
+	unsigned int         *collection_stack;
+	unsigned int          collection_stack_ptr;
+	unsigned int          collection_stack_size;
 	struct hid_device    *device;
-	unsigned              scan_flags;
+	unsigned int          scan_flags;
 };
 
 struct hid_class_descriptor {
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 9/9] HID: microsoft: support the Surface Dial
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
                   ` (7 preceding siblings ...)
  2018-05-29  9:57 ` [PATCH 8/9] HID: core: do not upper bound the collection stack Benjamin Tissoires
@ 2018-05-29  9:58 ` Benjamin Tissoires
  2018-05-29 10:38 ` [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Florian Echtler
  9 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29  9:58 UTC (permalink / raw)
  To: Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
	Benjamin Tissoires

The tool works nicely with hid-generic, but it ends up creating 9
different input nodes with most of them only having ABS_MISC set.

Filter the axis out, which reduces the amount of devices to 2. One is
the proper System Multi-axis collection, the other exported device
seems to provide SLEEP and POWER Key, not sure how one can trigger
those events though.

Filtering the ABS_X and ABS_Y axes also prevents udev to detect this as
a touchscreen.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-microsoft.c | 49 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 43 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 96e7d3231d2f..72d983626afd 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -22,12 +22,13 @@
 
 #include "hid-ids.h"
 
-#define MS_HIDINPUT		0x01
-#define MS_ERGONOMY		0x02
-#define MS_PRESENTER		0x04
-#define MS_RDESC		0x08
-#define MS_NOGET		0x10
-#define MS_DUPLICATE_USAGES	0x20
+#define MS_HIDINPUT		BIT(0)
+#define MS_ERGONOMY		BIT(1)
+#define MS_PRESENTER		BIT(2)
+#define MS_RDESC		BIT(3)
+#define MS_NOGET		BIT(4)
+#define MS_DUPLICATE_USAGES	BIT(5)
+#define MS_SURFACE_DIAL		BIT(6)
 
 static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
@@ -130,6 +131,30 @@ static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
 	return 1;
 }
 
+static int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	switch (usage->hid & HID_USAGE_PAGE) {
+	case 0xff070000:
+		/* fall-through */
+	case HID_UP_DIGITIZER:
+		/* ignore those axis */
+		return -1;
+	case HID_UP_GENDESK:
+		switch (usage->hid) {
+		case HID_GD_X:
+			/* fall-through */
+		case HID_GD_Y:
+			/* fall-through */
+		case HID_GD_RFKILL_BTN:
+			/* ignore those axis */
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
@@ -146,6 +171,13 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 			ms_presenter_8k_quirk(hi, usage, bit, max))
 		return 1;
 
+	if (quirks & MS_SURFACE_DIAL) {
+		int ret = ms_surface_dial_quirk(hi, field, usage, bit, max);
+
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
@@ -229,6 +261,9 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (quirks & MS_NOGET)
 		hdev->quirks |= HID_QUIRK_NOGET;
 
+	if (quirks & MS_SURFACE_DIAL)
+		hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
+
 	ret = hid_parse(hdev);
 	if (ret) {
 		hid_err(hdev, "parse failed\n");
@@ -281,6 +316,8 @@ static const struct hid_device_id ms_devices[] = {
 
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
 		.driver_data = MS_PRESENTER },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B),
+		.driver_data = MS_SURFACE_DIAL },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, ms_devices);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices
  2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
                   ` (8 preceding siblings ...)
  2018-05-29  9:58 ` [PATCH 9/9] HID: microsoft: support the Surface Dial Benjamin Tissoires
@ 2018-05-29 10:38 ` Florian Echtler
  2018-05-29 15:06   ` Benjamin Tissoires
  9 siblings, 1 reply; 14+ messages in thread
From: Florian Echtler @ 2018-05-29 10:38 UTC (permalink / raw)
  To: Benjamin Tissoires, Jiri Kosina, Dmitry Torokhov
  Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel


[-- Attachment #1.1: Type: text/plain, Size: 4054 bytes --]

Hello Benjamin,

I have a side question about your patchset: for the SUR40 touchscreen, we had a
discussion a while ago about how to support the different object types which the
firmware can detect (plain touch contact, printed token with ID, generic blob
outline). Would the pass-through for the tool type allow us to differentiate
those, once we define suitable tool types for each object class?

Thanks & best regards, Florian

On 29.05.2018 11:57, Benjamin Tissoires wrote:
> Hi Jiri,
> 
> this heavy rewrite of hid-multitouch serves two main purposes:
> - the first point is to enable the support of the Totem on the Dell Canvas 27.
>   This new type of devices (System Multi Axis) is used by Microsoft to show
>   a new circular menu that is used by the second hand while you interact with
>   your preferred hand with your tool.
>   I couldn't enable it before because hid-multitouch expected to have only one
>   multitouch collection, and this device is exported as a separate multitouch
>   collextion in the same HID device than the one containing the touch sensor.
> 
> - the second point is to streamline the process of the multitouch events. We
>   used to temporary store the events in a struct as they come in, and then do
>   the processing on the cache we just made. When doing the processing was also
>   not very clear. This made that even if hid-multitouch should IMO be merged in
>   hid-core, we couldn't.
> 
>   The new processing of the events here adds a preparsing of the report in
>   one HID collection (application usage), and from now on, the processing
>   of the report is cleaner IMO. I still haven't merged hid-mt into hid-core,
>   because even if I wrote a bunch of unit tests trying to not break any devices,
>   we are not protected from a weird thing that magically happened before but is
>   now broken.
> 
> I must say that when I worked on the tests, I came to realise that some legacy
> Win7 devices were better handled now. Initially I thought my new code broke them
> but comparing the outputs from https://github.com/bentiss/hid-devices before
> and after the changes, the new changes are closer to what I would expect by
> looking at the raw HID events.
> 
> I also included 2 patches to enable the Surface Dial. It's a BLE device similar
> to the Totem from Dell, except that you can buy it for roughly $80 instead of
> $1800 for the Canvas.
> 
> 
> Dmitry, 2 patches are of interest for you:
> - 1/9 Input: mt - export MT_TOOL in input_mt_init_slot()
> - 7/9 HID: input: enable Totem on the Dell Canvas 27
> 
> The second one exports a new MT_TOOL. In theory, I think patch 1/9 could be
> carried through your tree but it'll be better to have the full series applied
> at once.
> 
> Cheers,
> Benjamin
> 
> Benjamin Tissoires (9):
>   Input: mt - export MT_TOOL in input_mt_init_slot()
>   HID: multitouch: make sure the static list of class is not changed
>   HID: multitouch: Store per collection multitouch data
>   HID: multitouch: store a per application quirks value
>   HID: multitouch: ditch mt_report_id
>   HID: multitouch: remove one copy of values
>   HID: input: enable Totem on the Dell Canvas 27
>   HID: core: do not upper bound the collection stack
>   HID: microsoft: support the Surface Dial
> 
>  drivers/hid/hid-core.c                   |  17 +-
>  drivers/hid/hid-input.c                  |   3 +
>  drivers/hid/hid-microsoft.c              |  49 +-
>  drivers/hid/hid-multitouch.c             | 941 ++++++++++++++++++-------------
>  drivers/input/input-mt.c                 |   1 +
>  drivers/input/rmi4/rmi_2d_sensor.c       |   2 -
>  drivers/input/touchscreen/atmel_mxt_ts.c |   2 -
>  drivers/input/touchscreen/hideep.c       |   2 -
>  drivers/input/touchscreen/wacom_w8001.c  |   2 -
>  include/linux/hid.h                      |  15 +-
>  include/uapi/linux/input.h               |   3 +-
>  11 files changed, 616 insertions(+), 421 deletions(-)
> 


-- 
SENT FROM MY DEC VT50 TERMINAL


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices
  2018-05-29 10:38 ` [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Florian Echtler
@ 2018-05-29 15:06   ` Benjamin Tissoires
  0 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-29 15:06 UTC (permalink / raw)
  To: Florian Echtler
  Cc: Jiri Kosina, Dmitry Torokhov, Mario.Limonciello, Peter Hutterer,
	open list:HID CORE LAYER, lkml

Hi Florian,

On Tue, May 29, 2018 at 12:38 PM, Florian Echtler <floe@butterbrot.org> wrote:
> Hello Benjamin,
>
> I have a side question about your patchset: for the SUR40 touchscreen, we had a
> discussion a while ago about how to support the different object types which the
> firmware can detect (plain touch contact, printed token with ID, generic blob
> outline).

Plain touch contact should already be reported by MT_TOOL_FINGER.
Printed token with ID seems challenging as even if it is a different
tool (not a finger) I am not sure we can convey which ID is which.
And generic blob is even worse because we need a tracking ID that
would regroup the various touch points, and it doesn't reflect a
particular tool.

> Would the pass-through for the tool type allow us to differentiate
> those, once we define suitable tool types for each object class?

I am honestly puzzled by this and can't do much for you here. Could
you please re-tell us the specific use cases, so we can think about
the solutions?

Cheers,
Benjamin

>
> Thanks & best regards, Florian
>
> On 29.05.2018 11:57, Benjamin Tissoires wrote:
>> Hi Jiri,
>>
>> this heavy rewrite of hid-multitouch serves two main purposes:
>> - the first point is to enable the support of the Totem on the Dell Canvas 27.
>>   This new type of devices (System Multi Axis) is used by Microsoft to show
>>   a new circular menu that is used by the second hand while you interact with
>>   your preferred hand with your tool.
>>   I couldn't enable it before because hid-multitouch expected to have only one
>>   multitouch collection, and this device is exported as a separate multitouch
>>   collextion in the same HID device than the one containing the touch sensor.
>>
>> - the second point is to streamline the process of the multitouch events. We
>>   used to temporary store the events in a struct as they come in, and then do
>>   the processing on the cache we just made. When doing the processing was also
>>   not very clear. This made that even if hid-multitouch should IMO be merged in
>>   hid-core, we couldn't.
>>
>>   The new processing of the events here adds a preparsing of the report in
>>   one HID collection (application usage), and from now on, the processing
>>   of the report is cleaner IMO. I still haven't merged hid-mt into hid-core,
>>   because even if I wrote a bunch of unit tests trying to not break any devices,
>>   we are not protected from a weird thing that magically happened before but is
>>   now broken.
>>
>> I must say that when I worked on the tests, I came to realise that some legacy
>> Win7 devices were better handled now. Initially I thought my new code broke them
>> but comparing the outputs from https://github.com/bentiss/hid-devices before
>> and after the changes, the new changes are closer to what I would expect by
>> looking at the raw HID events.
>>
>> I also included 2 patches to enable the Surface Dial. It's a BLE device similar
>> to the Totem from Dell, except that you can buy it for roughly $80 instead of
>> $1800 for the Canvas.
>>
>>
>> Dmitry, 2 patches are of interest for you:
>> - 1/9 Input: mt - export MT_TOOL in input_mt_init_slot()
>> - 7/9 HID: input: enable Totem on the Dell Canvas 27
>>
>> The second one exports a new MT_TOOL. In theory, I think patch 1/9 could be
>> carried through your tree but it'll be better to have the full series applied
>> at once.
>>
>> Cheers,
>> Benjamin
>>
>> Benjamin Tissoires (9):
>>   Input: mt - export MT_TOOL in input_mt_init_slot()
>>   HID: multitouch: make sure the static list of class is not changed
>>   HID: multitouch: Store per collection multitouch data
>>   HID: multitouch: store a per application quirks value
>>   HID: multitouch: ditch mt_report_id
>>   HID: multitouch: remove one copy of values
>>   HID: input: enable Totem on the Dell Canvas 27
>>   HID: core: do not upper bound the collection stack
>>   HID: microsoft: support the Surface Dial
>>
>>  drivers/hid/hid-core.c                   |  17 +-
>>  drivers/hid/hid-input.c                  |   3 +
>>  drivers/hid/hid-microsoft.c              |  49 +-
>>  drivers/hid/hid-multitouch.c             | 941 ++++++++++++++++++-------------
>>  drivers/input/input-mt.c                 |   1 +
>>  drivers/input/rmi4/rmi_2d_sensor.c       |   2 -
>>  drivers/input/touchscreen/atmel_mxt_ts.c |   2 -
>>  drivers/input/touchscreen/hideep.c       |   2 -
>>  drivers/input/touchscreen/wacom_w8001.c  |   2 -
>>  include/linux/hid.h                      |  15 +-
>>  include/uapi/linux/input.h               |   3 +-
>>  11 files changed, 616 insertions(+), 421 deletions(-)
>>
>
>
> --
> SENT FROM MY DEC VT50 TERMINAL
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot()
  2018-05-29  9:57 ` [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot() Benjamin Tissoires
@ 2018-05-29 18:21   ` Dmitry Torokhov
  2018-05-30  8:53     ` Benjamin Tissoires
  0 siblings, 1 reply; 14+ messages in thread
From: Dmitry Torokhov @ 2018-05-29 18:21 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Jiri Kosina, Mario.Limonciello, Peter Hutterer, linux-input,
	linux-kernel

Hi Benjamin,

On Tue, May 29, 2018 at 11:57:52AM +0200, Benjamin Tissoires wrote:
> Looks like we require users to set a tool but input_mt_init_slots() never
> set the tool bit for us. Meaning that this is a useless information the
> driver tries to forward.

I am not sure if I agree with this patch: up until now drivers could
decide if they export presence of the tool type to userspace and
userspace could distinguish between "pure" touchscreens and touchscreens
that support additional tools, such as stylus. Now we unconditionally
claim that all multi-touch devices support multiple tools.

The fact that we were dropping MT_TOOL_TYPE for devices that do not
support anything but finger I'd consider a "feature".

> 
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> ---
>  drivers/input/input-mt.c                 | 1 +
>  drivers/input/rmi4/rmi_2d_sensor.c       | 2 --
>  drivers/input/touchscreen/atmel_mxt_ts.c | 2 --
>  drivers/input/touchscreen/hideep.c       | 2 --
>  drivers/input/touchscreen/wacom_w8001.c  | 2 --
>  5 files changed, 1 insertion(+), 8 deletions(-)
> 
> diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
> index a1bbec9cda8d..3900686c5d0f 100644
> --- a/drivers/input/input-mt.c
> +++ b/drivers/input/input-mt.c
> @@ -57,6 +57,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
>  	mt->flags = flags;
>  	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
>  	input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
> +	input_set_abs_params(dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);
>  
>  	if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
>  		__set_bit(EV_KEY, dev->evbit);
> diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
> index 8bb866c7b985..23e666bd2539 100644
> --- a/drivers/input/rmi4/rmi_2d_sensor.c
> +++ b/drivers/input/rmi4/rmi_2d_sensor.c
> @@ -186,8 +186,6 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
>  		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
>  		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
>  		input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
> -		input_set_abs_params(input, ABS_MT_TOOL_TYPE,
> -				     0, MT_TOOL_MAX, 0, 0);
>  
>  		if (sensor->sensor_type == rmi_sensor_touchpad)
>  			input_flags = INPUT_MT_POINTER;
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index 54fe190fd4bc..0dcf48100dc1 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -2021,8 +2021,6 @@ static int mxt_initialize_input_device(struct mxt_data *data)
>  	}
>  
>  	if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100) {
> -		input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
> -				     0, MT_TOOL_MAX, 0, 0);
>  		input_set_abs_params(input_dev, ABS_MT_DISTANCE,
>  				     MXT_DISTANCE_ACTIVE_TOUCH,
>  				     MXT_DISTANCE_HOVERING,
> diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
> index f1cd4dd9a4a3..980539d8d551 100644
> --- a/drivers/input/touchscreen/hideep.c
> +++ b/drivers/input/touchscreen/hideep.c
> @@ -799,8 +799,6 @@ static int hideep_init_input(struct hideep_ts *ts)
>  	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
>  	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 65535, 0, 0);
>  	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
> -	input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
> -			     0, MT_TOOL_MAX, 0, 0);
>  	touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
>  
>  	if (ts->prop.max_x == 0 || ts->prop.max_y == 0) {
> diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
> index 3715d1eace92..946dca30560b 100644
> --- a/drivers/input/touchscreen/wacom_w8001.c
> +++ b/drivers/input/touchscreen/wacom_w8001.c
> @@ -529,8 +529,6 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename,
>  					0, touch.x, 0, 0);
>  		input_set_abs_params(dev, ABS_MT_POSITION_Y,
>  					0, touch.y, 0, 0);
> -		input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
> -					0, MT_TOOL_MAX, 0, 0);
>  		input_abs_set_res(dev, ABS_MT_POSITION_X, touch.panel_res);
>  		input_abs_set_res(dev, ABS_MT_POSITION_Y, touch.panel_res);
>  
> -- 
> 2.14.3
> 

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot()
  2018-05-29 18:21   ` Dmitry Torokhov
@ 2018-05-30  8:53     ` Benjamin Tissoires
  0 siblings, 0 replies; 14+ messages in thread
From: Benjamin Tissoires @ 2018-05-30  8:53 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jiri Kosina, Mario.Limonciello, Peter Hutterer,
	open list:HID CORE LAYER, lkml

Hi Dmitry,

On Tue, May 29, 2018 at 8:21 PM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Benjamin,
>
> On Tue, May 29, 2018 at 11:57:52AM +0200, Benjamin Tissoires wrote:
>> Looks like we require users to set a tool but input_mt_init_slots() never
>> set the tool bit for us. Meaning that this is a useless information the
>> driver tries to forward.
>
> I am not sure if I agree with this patch: up until now drivers could
> decide if they export presence of the tool type to userspace and
> userspace could distinguish between "pure" touchscreens and touchscreens
> that support additional tools, such as stylus. Now we unconditionally
> claim that all multi-touch devices support multiple tools.
>
> The fact that we were dropping MT_TOOL_TYPE for devices that do not
> support anything but finger I'd consider a "feature".

OK. I was not sure to agree with this, but I had a quick chat with
Peter and he also agrees. There is no real point in forwarding an
event that will never be updated, so let's just skip that patch then.

Expect this to be removed in v2 then.

Cheers,
Benjamin

>
>>
>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>> ---
>>  drivers/input/input-mt.c                 | 1 +
>>  drivers/input/rmi4/rmi_2d_sensor.c       | 2 --
>>  drivers/input/touchscreen/atmel_mxt_ts.c | 2 --
>>  drivers/input/touchscreen/hideep.c       | 2 --
>>  drivers/input/touchscreen/wacom_w8001.c  | 2 --
>>  5 files changed, 1 insertion(+), 8 deletions(-)
>>
>> diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
>> index a1bbec9cda8d..3900686c5d0f 100644
>> --- a/drivers/input/input-mt.c
>> +++ b/drivers/input/input-mt.c
>> @@ -57,6 +57,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
>>       mt->flags = flags;
>>       input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
>>       input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
>> +     input_set_abs_params(dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);
>>
>>       if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
>>               __set_bit(EV_KEY, dev->evbit);
>> diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
>> index 8bb866c7b985..23e666bd2539 100644
>> --- a/drivers/input/rmi4/rmi_2d_sensor.c
>> +++ b/drivers/input/rmi4/rmi_2d_sensor.c
>> @@ -186,8 +186,6 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
>>               input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
>>               input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
>>               input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
>> -             input_set_abs_params(input, ABS_MT_TOOL_TYPE,
>> -                                  0, MT_TOOL_MAX, 0, 0);
>>
>>               if (sensor->sensor_type == rmi_sensor_touchpad)
>>                       input_flags = INPUT_MT_POINTER;
>> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
>> index 54fe190fd4bc..0dcf48100dc1 100644
>> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
>> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
>> @@ -2021,8 +2021,6 @@ static int mxt_initialize_input_device(struct mxt_data *data)
>>       }
>>
>>       if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100) {
>> -             input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
>> -                                  0, MT_TOOL_MAX, 0, 0);
>>               input_set_abs_params(input_dev, ABS_MT_DISTANCE,
>>                                    MXT_DISTANCE_ACTIVE_TOUCH,
>>                                    MXT_DISTANCE_HOVERING,
>> diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
>> index f1cd4dd9a4a3..980539d8d551 100644
>> --- a/drivers/input/touchscreen/hideep.c
>> +++ b/drivers/input/touchscreen/hideep.c
>> @@ -799,8 +799,6 @@ static int hideep_init_input(struct hideep_ts *ts)
>>       input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
>>       input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 65535, 0, 0);
>>       input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
>> -     input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
>> -                          0, MT_TOOL_MAX, 0, 0);
>>       touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
>>
>>       if (ts->prop.max_x == 0 || ts->prop.max_y == 0) {
>> diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
>> index 3715d1eace92..946dca30560b 100644
>> --- a/drivers/input/touchscreen/wacom_w8001.c
>> +++ b/drivers/input/touchscreen/wacom_w8001.c
>> @@ -529,8 +529,6 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename,
>>                                       0, touch.x, 0, 0);
>>               input_set_abs_params(dev, ABS_MT_POSITION_Y,
>>                                       0, touch.y, 0, 0);
>> -             input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
>> -                                     0, MT_TOOL_MAX, 0, 0);
>>               input_abs_set_res(dev, ABS_MT_POSITION_X, touch.panel_res);
>>               input_abs_set_res(dev, ABS_MT_POSITION_Y, touch.panel_res);
>>
>> --
>> 2.14.3
>>
>
> Thanks.
>
> --
> Dmitry

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2018-05-30  8:53 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-29  9:57 [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 1/9] Input: mt - export MT_TOOL in input_mt_init_slot() Benjamin Tissoires
2018-05-29 18:21   ` Dmitry Torokhov
2018-05-30  8:53     ` Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 2/9] HID: multitouch: make sure the static list of class is not changed Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 3/9] HID: multitouch: Store per collection multitouch data Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 4/9] HID: multitouch: store a per application quirks value Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 5/9] HID: multitouch: ditch mt_report_id Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 6/9] HID: multitouch: remove one copy of values Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 7/9] HID: input: enable Totem on the Dell Canvas 27 Benjamin Tissoires
2018-05-29  9:57 ` [PATCH 8/9] HID: core: do not upper bound the collection stack Benjamin Tissoires
2018-05-29  9:58 ` [PATCH 9/9] HID: microsoft: support the Surface Dial Benjamin Tissoires
2018-05-29 10:38 ` [PATCH 0/9] Hid multitouch rewrite, support os system multi-axis devices Florian Echtler
2018-05-29 15:06   ` Benjamin Tissoires

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).