All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/10] Support for Win 8 digitizers
@ 2012-10-25 14:09 Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 01/10] HID: core: fix unit exponent parsing Benjamin Tissoires
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Hi guys,

well, this is my first series as a Red Hat employee. I should be able to
communicate my email address soon (once I'm able to read it).

So, this is an update for supporting Win 8 multitouch devices in the kernel.
As I wanted to reliably forward the resolution, I noticed a bug in the
processing of the unit exponent in the hid core layer.
Thus the fixes for hid-core and hid-input.

The last patch removes the dependency for usbhid as now touchscreen may
be connected through i2c.

Cheers,
Benjamin



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

* [PATCH 01/10] HID: core: fix unit exponent parsing
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 02/10] HID: hid-input: add usage_index argument in input_mapping and event Benjamin Tissoires
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

HID spec details special values for the HID field unit exponent.
Basically, the range [0x8..0xf] correspond to [-8..-1].

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
---
 drivers/hid/hid-core.c  | 10 +++++++++-
 drivers/hid/hid-input.c | 19 +++++++++++++------
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 5de3bb3..b2533f1 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -315,6 +315,7 @@ static s32 item_sdata(struct hid_item *item)
 
 static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 {
+	__u32 raw_value;
 	switch (item->tag) {
 	case HID_GLOBAL_ITEM_TAG_PUSH:
 
@@ -365,7 +366,14 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 		return 0;
 
 	case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-		parser->global.unit_exponent = item_sdata(item);
+		/* Units exponent negative numbers are given through a special
+		 * table.
+		 * See "6.2.2.7 Global Items" for more information. */
+		raw_value = item_udata(item);
+		if ((raw_value >> 3) == 1)
+			parser->global.unit_exponent = raw_value - 16;
+		else
+			parser->global.unit_exponent = raw_value;
 		return 0;
 
 	case HID_GLOBAL_ITEM_TAG_UNIT:
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 1b0adc3..fc9f2b5 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -215,7 +215,7 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
 					field->logical_minimum;
 	__s32 physical_extents = field->physical_maximum -
 					field->physical_minimum;
-	__s32 prev;
+	__s32 prev, tmp_exponent;
 
 	/* Check if the extents are sane */
 	if (logical_extents <= 0 || physical_extents <= 0)
@@ -235,17 +235,24 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
 	case ABS_MT_TOOL_Y:
 	case ABS_MT_TOUCH_MAJOR:
 	case ABS_MT_TOUCH_MINOR:
-		if (field->unit == 0x11) {		/* If centimeters */
+		if (field->unit & 0xffffff00)		/* Not a length */
+			return 0;
+		tmp_exponent = field->unit >> 4;
+		if ((tmp_exponent >> 3) == 1)
+			tmp_exponent -= 16;
+		switch (field->unit & 0xf) {
+		case 0x1:				/* If centimeters */
 			/* Convert to millimeters */
-			unit_exponent += 1;
-		} else if (field->unit == 0x13) {	/* If inches */
+			unit_exponent += tmp_exponent;
+			break;
+		case 0x3:				/* If inches */
 			/* Convert to millimeters */
 			prev = physical_extents;
 			physical_extents *= 254;
 			if (physical_extents < prev)
 				return 0;
-			unit_exponent -= 1;
-		} else {
+			unit_exponent += tmp_exponent - 2;
+		default:
 			return 0;
 		}
 		break;
-- 
1.7.11.7


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

* [PATCH 02/10] HID: hid-input: add usage_index argument in input_mapping and event.
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 01/10] HID: core: fix unit exponent parsing Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 03/10] HID: hid-multitouch: support arrays for the split of the touches in a report Benjamin Tissoires
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Currently, there is no way to know the index of the current field
in the .input_mapping and .event callbacks  when this field is inside
an array of HID fields.
This patch transfers this index to the input_mapping and event
callbacks.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
---
 drivers/hid/hid-a4tech.c       |  2 +-
 drivers/hid/hid-apple.c        |  4 ++--
 drivers/hid/hid-belkin.c       |  2 +-
 drivers/hid/hid-cherry.c       |  2 +-
 drivers/hid/hid-chicony.c      |  2 +-
 drivers/hid/hid-core.c         | 16 +++++++++++-----
 drivers/hid/hid-cypress.c      |  2 +-
 drivers/hid/hid-ezkey.c        |  4 ++--
 drivers/hid/hid-gyration.c     |  4 ++--
 drivers/hid/hid-input.c        | 10 ++++++----
 drivers/hid/hid-kensington.c   |  2 +-
 drivers/hid/hid-lcpower.c      |  2 +-
 drivers/hid/hid-lenovo-tpkbd.c |  3 ++-
 drivers/hid/hid-lg.c           |  4 ++--
 drivers/hid/hid-magicmouse.c   |  3 ++-
 drivers/hid/hid-microsoft.c    |  4 ++--
 drivers/hid/hid-monterey.c     |  2 +-
 drivers/hid/hid-multitouch.c   |  4 ++--
 drivers/hid/hid-ntrig.c        |  4 +++-
 drivers/hid/hid-petalynx.c     |  2 +-
 drivers/hid/hid-prodikeys.c    |  2 +-
 drivers/hid/hid-samsung.c      |  2 +-
 drivers/hid/hid-speedlink.c    |  6 +++---
 drivers/hid/hid-sunplus.c      |  2 +-
 drivers/hid/hid-tivo.c         |  2 +-
 drivers/hid/hid-topseed.c      |  2 +-
 drivers/hid/hid-twinhan.c      |  2 +-
 include/linux/hid.h            |  6 ++++--
 28 files changed, 58 insertions(+), 44 deletions(-)

diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 902d1df..b7aa5a2 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -49,7 +49,7 @@ static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 }
 
 static int a4_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
 	struct input_dev *input;
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 585344b..cb5eeae 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -248,7 +248,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 }
 
 static int apple_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	struct apple_sc *asc = hid_get_drvdata(hdev);
 
@@ -311,7 +311,7 @@ static void apple_setup_input(struct input_dev *input)
 
 static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if (usage->hid == (HID_UP_CUSTOM | 0x0003)) {
 		/* The fn key on Apple USB keyboards */
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
index a1a765a..5a68ad4 100644
--- a/drivers/hid/hid-belkin.c
+++ b/drivers/hid/hid-belkin.c
@@ -29,7 +29,7 @@
 					EV_KEY, (c))
 static int belkin_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index 888ece6..1b26dd0 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -41,7 +41,7 @@ static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 					EV_KEY, (c))
 static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
 		return 0;
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
index a2abb8e..4510ea5 100644
--- a/drivers/hid/hid-chicony.c
+++ b/drivers/hid/hid-chicony.c
@@ -27,7 +27,7 @@
 					EV_KEY, (c))
 static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
 		return 0;
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index b2533f1..93c893b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1009,7 +1009,8 @@ static int hid_match_usage(struct hid_device *hid, struct hid_usage *usage)
 }
 
 static void hid_process_event(struct hid_device *hid, struct hid_field *field,
-		struct hid_usage *usage, __s32 value, int interrupt)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value,
+		int interrupt)
 {
 	struct hid_driver *hdrv = hid->driver;
 	int ret;
@@ -1018,7 +1019,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
 		hid_dump_input(hid, usage, value);
 
 	if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
-		ret = hdrv->event(hid, field, usage, value);
+		ret = hdrv->event(hid, field, usage, usage_index, value);
 		if (ret != 0) {
 			if (ret < 0)
 				hid_err(hid, "%s's event failed with %d\n",
@@ -1071,19 +1072,24 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
 	for (n = 0; n < count; n++) {
 
 		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-			hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
+			hid_process_event(hid, field, &field->usage[n], n,
+				value[n], interrupt);
 			continue;
 		}
 
 		if (field->value[n] >= min && field->value[n] <= max
 			&& field->usage[field->value[n] - min].hid
 			&& search(value, field->value[n], count))
-				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
+				hid_process_event(hid, field,
+					&field->usage[field->value[n] - min], n,
+					0, interrupt);
 
 		if (value[n] >= min && value[n] <= max
 			&& field->usage[value[n] - min].hid
 			&& search(field->value, value[n], count))
-				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
+				hid_process_event(hid, field,
+					&field->usage[value[n] - min], n,
+					1, interrupt);
 	}
 
 	memcpy(field->value, value, count * sizeof(__s32));
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 9e43aac..e3c8569 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -71,7 +71,7 @@ static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 }
 
 static int cp_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c
index ca1163e..664f4fd 100644
--- a/drivers/hid/hid-ezkey.c
+++ b/drivers/hid/hid-ezkey.c
@@ -28,7 +28,7 @@
 
 static int ez_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
 		return 0;
@@ -49,7 +49,7 @@ static int ez_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 }
 
 static int ez_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
 			!usage->type)
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
index e88b951..7d27943 100644
--- a/drivers/hid/hid-gyration.c
+++ b/drivers/hid/hid-gyration.c
@@ -27,7 +27,7 @@
 					EV_KEY, (c))
 static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
 		return 0;
@@ -56,7 +56,7 @@ static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 }
 
 static int gyration_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 
 	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index fc9f2b5..16cc89a 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -464,7 +464,8 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
 #endif	/* CONFIG_HID_BATTERY_STRENGTH */
 
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
-				     struct hid_usage *usage)
+				     struct hid_usage *usage,
+				     unsigned int usage_index)
 {
 	struct input_dev *input = hidinput->input;
 	struct hid_device *device = input_get_drvdata(input);
@@ -484,7 +485,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
 	if (device->driver->input_mapping) {
 		int ret = device->driver->input_mapping(device, hidinput, field,
-				usage, &bit, &max);
+				usage, usage_index, &bit, &max);
 		if (ret > 0)
 			goto mapped;
 		if (ret < 0)
@@ -1233,8 +1234,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
 
 			for (i = 0; i < report->maxfield; i++)
 				for (j = 0; j < report->field[i]->maxusage; j++)
-					hidinput_configure_usage(hidinput, report->field[i],
-								 report->field[i]->usage + j);
+					hidinput_configure_usage(hidinput,
+						report->field[i],
+						report->field[i]->usage + j, j);
 
 			if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
 				/* This will leave hidinput NULL, so that it
diff --git a/drivers/hid/hid-kensington.c b/drivers/hid/hid-kensington.c
index a5b4016..af9b9da 100644
--- a/drivers/hid/hid-kensington.c
+++ b/drivers/hid/hid-kensington.c
@@ -22,7 +22,7 @@
 
 static int ks_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
 		return 0;
diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c
index c4fe9bd0..d499a0a 100644
--- a/drivers/hid/hid-lcpower.c
+++ b/drivers/hid/hid-lcpower.c
@@ -22,7 +22,7 @@
 					EV_KEY, (c))
 static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000)
 		return 0;
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index 60c4e1e..86ea802 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -39,7 +39,8 @@ struct tpkbd_data_pointer {
 
 static int tpkbd_input_mapping(struct hid_device *hdev,
 		struct hid_input *hi, struct hid_field *field,
-		struct hid_usage *usage, unsigned long **bit, int *max)
+		struct hid_usage *usage, unsigned int usage_index,
+		unsigned long **bit, int *max)
 {
 	struct usbhid_device *uhdev;
 
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index fc37ed6..cdcd4d5 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -264,7 +264,7 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
 
 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	/* extended mapping for certain Logitech hardware (Logitech cordless
 	   desktop LX500) */
@@ -333,7 +333,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 }
 
 static int lg_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 25ddf3e..aca56ee 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -447,7 +447,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
 
 static int magicmouse_input_mapping(struct hid_device *hdev,
 		struct hid_input *hi, struct hid_field *field,
-		struct hid_usage *usage, unsigned long **bit, int *max)
+		struct hid_usage *usage, unsigned int usage_index,
+		unsigned long **bit, int *max)
 {
 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
 
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index e5c699b..62304e1 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -90,7 +90,7 @@ static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
 
 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)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
@@ -123,7 +123,7 @@ static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 }
 
 static int ms_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
index dedf757..513cd1b 100644
--- a/drivers/hid/hid-monterey.c
+++ b/drivers/hid/hid-monterey.c
@@ -36,7 +36,7 @@ static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 					EV_KEY, (c))
 static int mr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
 		return 0;
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 9a0804b..1382554 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -314,7 +314,7 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
 
 static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
 	struct mt_class *cls = &td->mtclass;
@@ -520,7 +520,7 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
 }
 
 static int mt_event(struct hid_device *hid, struct hid_field *field,
-				struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	struct mt_device *td = hid_get_drvdata(hid);
 	__s32 quirks = td->mtclass.quirks;
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 9fae2eb..b0b66606 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -456,6 +456,7 @@ static struct attribute_group ntrig_attribute_group = {
 
 static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 			       struct hid_field *field, struct hid_usage *usage,
+			       unsigned int usage_index,
 			       unsigned long **bit, int *max)
 {
 	struct ntrig_data *nd = hid_get_drvdata(hdev);
@@ -567,7 +568,8 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
  * and call input_mt_sync after each point if necessary
  */
 static int ntrig_event (struct hid_device *hid, struct hid_field *field,
-			struct hid_usage *usage, __s32 value)
+			struct hid_usage *usage, unsigned int usage_index,
+			__s32 value)
 {
 	struct ntrig_data *nd = hid_get_drvdata(hid);
 	struct input_dev *input;
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index f1ea3ff..30aacb8 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -40,7 +40,7 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 					EV_KEY, (c))
 static int pl_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) {
 		switch (usage->hid & HID_USAGE) {
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index b71b77a..2faf83a 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -757,7 +757,7 @@ static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
 static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev);
 	struct pcmidi_snd *pm;
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index 3c1fd8a..d0dd311 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -141,7 +141,7 @@ static __u8 *samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
 static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	struct hid_field *field, struct hid_usage *usage,
-	unsigned long **bit, int *max)
+	unsigned int usage_index, unsigned long **bit, int *max)
 {
 	int ret = 0;
 
diff --git a/drivers/hid/hid-speedlink.c b/drivers/hid/hid-speedlink.c
index 6020137..da50735 100644
--- a/drivers/hid/hid-speedlink.c
+++ b/drivers/hid/hid-speedlink.c
@@ -27,8 +27,8 @@ static const struct hid_device_id speedlink_devices[] = {
 };
 
 static int speedlink_input_mapping(struct hid_device *hdev,
-		struct hid_input *hi,
-		struct hid_field *field, struct hid_usage *usage,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned int usage_index,
 		unsigned long **bit, int *max)
 {
 	/*
@@ -45,7 +45,7 @@ static int speedlink_input_mapping(struct hid_device *hdev,
 }
 
 static int speedlink_event(struct hid_device *hdev, struct hid_field *field,
-		struct hid_usage *usage, __s32 value)
+		struct hid_usage *usage, unsigned int usage_index, __s32 value)
 {
 	/* No other conditions due to usage_table. */
 	/* Fix "jumpy" cursor (invalid events sent by device). */
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
index d484a00..4e62a26 100644
--- a/drivers/hid/hid-sunplus.c
+++ b/drivers/hid/hid-sunplus.c
@@ -38,7 +38,7 @@ static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		EV_KEY, (c))
 static int sp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
 		return 0;
diff --git a/drivers/hid/hid-tivo.c b/drivers/hid/hid-tivo.c
index 9f85f82..e7684fd 100644
--- a/drivers/hid/hid-tivo.c
+++ b/drivers/hid/hid-tivo.c
@@ -24,7 +24,7 @@
 
 static int tivo_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	switch (usage->hid & HID_USAGE_PAGE) {
 	case HID_UP_TIVOVENDOR:
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 613ff7b..e924b7d 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -28,7 +28,7 @@
 					EV_KEY, (c))
 static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
 		return 0;
diff --git a/drivers/hid/hid-twinhan.c b/drivers/hid/hid-twinhan.c
index f23456b..b38e6b3 100644
--- a/drivers/hid/hid-twinhan.c
+++ b/drivers/hid/hid-twinhan.c
@@ -62,7 +62,7 @@
 					EV_KEY, (c))
 static int twinhan_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+		unsigned int usage_index, unsigned long **bit, int *max)
 {
 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD)
 		return 0;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 9edb06c..6216529 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -660,14 +660,16 @@ struct hid_driver {
 			u8 *data, int size);
 	const struct hid_usage_id *usage_table;
 	int (*event)(struct hid_device *hdev, struct hid_field *field,
-			struct hid_usage *usage, __s32 value);
+			struct hid_usage *usage, unsigned int usage_index,
+			__s32 value);
 
 	__u8 *(*report_fixup)(struct hid_device *hdev, __u8 *buf,
 			unsigned int *size);
 
 	int (*input_mapping)(struct hid_device *hdev,
 			struct hid_input *hidinput, struct hid_field *field,
-			struct hid_usage *usage, unsigned long **bit, int *max);
+			struct hid_usage *usage, unsigned int usage_index,
+			unsigned long **bit, int *max);
 	int (*input_mapped)(struct hid_device *hdev,
 			struct hid_input *hidinput, struct hid_field *field,
 			struct hid_usage *usage, unsigned long **bit, int *max);
-- 
1.7.11.7


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

* [PATCH 03/10] HID: hid-multitouch: support arrays for the split of the touches in a report
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 01/10] HID: core: fix unit exponent parsing Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 02/10] HID: hid-input: add usage_index argument in input_mapping and event Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 04/10] HID: hid-multitouch: get maxcontacts also from logical_max value Benjamin Tissoires
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Win8 certification introduced the ability to transmit two X and two Y per
touch. The specification precises that it must be in an array, with a
report count == 2.

This test guarantees that we split the touches on the last element
in this array.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@enac.fr>
---
 drivers/hid/hid-multitouch.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 1382554..e96ecc3 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -577,12 +577,16 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
 			return 0;
 		}
 
-		if (usage->hid == td->last_slot_field)
-			mt_complete_slot(td, field->hidinput->input);
-
-		if (field->index == td->last_field_index
-			&& td->num_received >= td->num_expected)
-			mt_sync_frame(td, field->hidinput->input);
+		if (usage_index + 1 == field->report_count) {
+			/* we only take into account the last report
+			 * of a field if report_count > 1 */
+			if (usage->hid == td->last_slot_field)
+				mt_complete_slot(td, field->hidinput->input);
+
+			if (field->index == td->last_field_index
+				&& td->num_received >= td->num_expected)
+				mt_sync_frame(td, field->hidinput->input);
+		}
 
 	}
 
-- 
1.7.11.7


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

* [PATCH 04/10] HID: hid-multitouch: get maxcontacts also from logical_max value
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (2 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 03/10] HID: hid-multitouch: support arrays for the split of the touches in a report Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 05/10] HID: hid-multitouch: support T and C for win8 devices Benjamin Tissoires
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Win8 devices are required to present the feature "Maximum Contact Number".
Fortunately all win7 devices I've seen presents this feature.
If the current value is 0, then, the driver can get the actual supported
contact count by refering to the logical_max.
This win8 specification ensures that logical_max may not be above 250.
This also allows us to detect when devices like irtouch or stantum reports
an obviously wrong value of 255.

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

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index e96ecc3..38a4feb 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -121,6 +121,7 @@ struct mt_device {
 #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS	0x0109
 
 #define MT_DEFAULT_MAXCONTACT	10
+#define MT_MAX_MAXCONTACT	250
 
 #define MT_USB_DEVICE(v, p)	HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
 #define MT_BT_DEVICE(v, p)	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
@@ -283,6 +284,9 @@ static void mt_feature_mapping(struct hid_device *hdev,
 	case HID_DG_CONTACTMAX:
 		td->maxcontact_report_id = field->report->id;
 		td->maxcontacts = field->value[0];
+		if (!td->maxcontacts &&
+		    field->logical_maximum <= MT_MAX_MAXCONTACT)
+			td->maxcontacts = field->logical_maximum;
 		if (td->mtclass.maxcontacts)
 			/* check if the maxcontacts is given by the class */
 			td->maxcontacts = td->mtclass.maxcontacts;
-- 
1.7.11.7


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

* [PATCH 05/10] HID: hid-multitouch: support T and C for win8 devices
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (3 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 04/10] HID: hid-multitouch: get maxcontacts also from logical_max value Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 06/10] HID: hid-multitouch: move ALWAYS_VALID quirk check Benjamin Tissoires
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Win8 input specification clarifies the X and Y sent by devices.
It distincts the position where the user wants to Touch (T) from
the center of the ellipsoide (C). This patch enable supports for this
distinction in hid-multitouch.

We recognize Win8 certified devices from their vendor feature 0xff0000c5
where Microsoft put a signed blob in the report to check if the device
passed the certification.

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

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 38a4feb..ff2354c 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -52,9 +52,10 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_VALID_IS_CONFIDENCE	(1 << 6)
 #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE	(1 << 8)
 #define MT_QUIRK_NO_AREA		(1 << 9)
+#define MT_QUIRK_WIN_8_CERTIFIED	(1 << 10)
 
 struct mt_slot {
-	__s32 x, y, p, w, h;
+	__s32 x, y, cx, cy, p, w, h;
 	__s32 contactid;	/* the device ContactID assigned to this slot */
 	bool touch_state;	/* is the touch valid? */
 };
@@ -292,6 +293,10 @@ static void mt_feature_mapping(struct hid_device *hdev,
 			td->maxcontacts = td->mtclass.maxcontacts;
 
 		break;
+	case 0xff0000c5:
+		if (field->report_count == 256 && field->report_size == 8)
+			td->mtclass.quirks |= MT_QUIRK_WIN_8_CERTIFIED;
+		break;
 	}
 }
 
@@ -350,18 +355,36 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 	case HID_UP_GENDESK:
 		switch (usage->hid) {
 		case HID_GD_X:
-			hid_map_usage(hi, usage, bit, max,
+			if (cls->quirks & MT_QUIRK_WIN_8_CERTIFIED &&
+				usage_index) {
+				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);
+				set_abs(hi->input, ABS_MT_POSITION_X, field,
+					cls->sn_move);
+			}
+
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
 		case HID_GD_Y:
-			hid_map_usage(hi, usage, bit, max,
+			if (cls->quirks & MT_QUIRK_WIN_8_CERTIFIED &&
+				usage_index) {
+				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);
+				set_abs(hi->input, ABS_MT_POSITION_Y, field,
+					cls->sn_move);
+			}
+
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
@@ -502,6 +525,12 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 
 			input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
 			input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
+			if (td->mtclass.quirks & MT_QUIRK_WIN_8_CERTIFIED) {
+				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_ORIENTATION, wide);
 			input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
 			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
@@ -553,10 +582,16 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
 			td->curdata.p = value;
 			break;
 		case HID_GD_X:
-			td->curdata.x = value;
+			if (usage->code == ABS_MT_POSITION_X)
+				td->curdata.x = value;
+			else
+				td->curdata.cx = value;
 			break;
 		case HID_GD_Y:
-			td->curdata.y = value;
+			if (usage->code == ABS_MT_POSITION_Y)
+				td->curdata.y = value;
+			else
+				td->curdata.cy = value;
 			break;
 		case HID_DG_WIDTH:
 			td->curdata.w = value;
-- 
1.7.11.7


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

* [PATCH 06/10] HID: hid-multitouch: move ALWAYS_VALID quirk check
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (4 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 05/10] HID: hid-multitouch: support T and C for win8 devices Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 07/10] HID: hid-multitouch: fix Win 8 protocol Benjamin Tissoires
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Win 8 device specification changed the requirements for the hid usages
of the multitouch devices. Now InRange is optional and must be only
used when the device supports hovering.

This ensures that the quirk ALWAYS_VALID is taken into account and
also ensures its precedence over the other VALID* quirks.

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

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index ff2354c..c8290e2 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -506,7 +506,7 @@ static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
  */
 static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 {
-	if (td->curvalid) {
+	if (td->curvalid || td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID) {
 		int slotnum = mt_compute_slot(td, input);
 		struct mt_slot *s = &td->curdata;
 
@@ -561,9 +561,7 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
 	if (hid->claimed & HID_CLAIMED_INPUT) {
 		switch (usage->hid) {
 		case HID_DG_INRANGE:
-			if (quirks & MT_QUIRK_ALWAYS_VALID)
-				td->curvalid = true;
-			else if (quirks & MT_QUIRK_VALID_IS_INRANGE)
+			if (quirks & MT_QUIRK_VALID_IS_INRANGE)
 				td->curvalid = value;
 			break;
 		case HID_DG_TIPSWITCH:
-- 
1.7.11.7


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

* [PATCH 07/10] HID: hid-multitouch: fix Win 8 protocol
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (5 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 06/10] HID: hid-multitouch: move ALWAYS_VALID quirk check Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 08/10] HID: hid-multitouch: support for hovering devices Benjamin Tissoires
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Win 8 specification is much more precise than the Win 7 one.
Moreover devices that need to take certification must be submitted
to Microsoft.

The result is a better protocol support and we can rely on that to
skip all the messy tests we used to do.

The protocol specify the fact that each valid touch must be reported
within a frame, and that the release touch coordinate must be the
same than the last known touch.
So we can use the always_valid quirk and dismiss reports when we
touch coordiante do not follow this rule.

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

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index c8290e2..6d4ad30 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -510,6 +510,18 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 		int slotnum = mt_compute_slot(td, input);
 		struct mt_slot *s = &td->curdata;
 
+		if (td->mtclass.quirks & MT_QUIRK_WIN_8_CERTIFIED &&
+		    !s->touch_state) {
+			struct input_mt_slot *slot = &input->mt->slots[slotnum];
+			int prv_x = input_mt_get_value(slot, ABS_MT_POSITION_X);
+			int prv_y = input_mt_get_value(slot, ABS_MT_POSITION_Y);
+			/* valid releases occurs when the last x and y positions
+			 * are the same as the last known touch. */
+			if (!input_mt_is_active(slot) ||
+			    prv_x != s->x || prv_y != s->y)
+				return;
+		}
+
 		if (slotnum < 0 || slotnum >= td->maxcontacts)
 			return;
 
@@ -681,8 +693,8 @@ static void mt_post_parse_default_settings(struct mt_device *td)
 {
 	__s32 quirks = td->mtclass.quirks;
 
-	/* unknown serial device needs special quirks */
-	if (td->touches_by_report == 1) {
+	/* unknown serial devices or win8 ones need special quirks */
+	if (td->touches_by_report == 1 || quirks & MT_QUIRK_WIN_8_CERTIFIED) {
 		quirks |= MT_QUIRK_ALWAYS_VALID;
 		quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
 		quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
-- 
1.7.11.7


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

* [PATCH 08/10] HID: hid-multitouch: support for hovering devices
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (6 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 07/10] HID: hid-multitouch: fix Win 8 protocol Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 09/10] HID: introduce Scan Time Benjamin Tissoires
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Win8 devices supporting hovering must provides InRange HID field.
The information that the finger is here but is not touching the surface
is sent to the user space through ABS_MT_DISTANCE as required by the
multitouch protocol.

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

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 6d4ad30..5aebbff 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -55,7 +55,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_WIN_8_CERTIFIED	(1 << 10)
 
 struct mt_slot {
-	__s32 x, y, cx, cy, p, w, h;
+	__s32 x, y, cx, cy, z, p, w, h;
 	__s32 contactid;	/* the device ContactID assigned to this slot */
 	bool touch_state;	/* is the touch valid? */
 };
@@ -394,6 +394,12 @@ static int mt_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_WIN_8_CERTIFIED) {
+				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);
 			td->last_field_index = field->index;
 			return 1;
@@ -511,6 +517,11 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 		struct mt_slot *s = &td->curdata;
 
 		if (td->mtclass.quirks & MT_QUIRK_WIN_8_CERTIFIED &&
+		    !test_bit(ABS_MT_DISTANCE, input->absbit))
+			/* If InRange is not present, rely on TipSwitch */
+			s->touch_state = !s->z;
+
+		if (td->mtclass.quirks & MT_QUIRK_WIN_8_CERTIFIED &&
 		    !s->touch_state) {
 			struct input_mt_slot *slot = &input->mt->slots[slotnum];
 			int prv_x = input_mt_get_value(slot, ABS_MT_POSITION_X);
@@ -543,6 +554,7 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 				input_event(input, EV_ABS, ABS_MT_TOOL_Y,
 					s->cy);
 			}
+			input_event(input, EV_ABS, ABS_MT_DISTANCE, s->z);
 			input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
 			input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
 			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
@@ -575,11 +587,16 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
 		case HID_DG_INRANGE:
 			if (quirks & MT_QUIRK_VALID_IS_INRANGE)
 				td->curvalid = value;
+			if (quirks & MT_QUIRK_WIN_8_CERTIFIED)
+				td->curdata.touch_state = value;
 			break;
 		case HID_DG_TIPSWITCH:
 			if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
 				td->curvalid = value;
-			td->curdata.touch_state = value;
+			if (quirks & MT_QUIRK_WIN_8_CERTIFIED)
+				td->curdata.z = !value;
+			else
+				td->curdata.touch_state = value;
 			break;
 		case HID_DG_CONFIDENCE:
 			if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
-- 
1.7.11.7


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

* [PATCH 09/10] HID: introduce Scan Time
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (7 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 08/10] HID: hid-multitouch: support for hovering devices Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:09 ` [PATCH 10/10] HID: hid-multitouch: get rid of usbhid depedency for general path Benjamin Tissoires
  2012-10-25 14:14 ` [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Win 8 digitizer devices provides the actual scan time computed by the
hardware itself. The value is global to the frame and is not specific
to the multitouch protocol (though only touch, not pen, should use it
according to the specification).

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
---
 Documentation/input/event-codes.txt |  7 +++++++
 drivers/hid/hid-input.c             |  4 ++++
 drivers/hid/hid-multitouch.c        | 13 ++++++++++---
 include/linux/hid.h                 |  1 +
 include/linux/input.h               |  1 +
 5 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt
index 53305bd..8f8c908 100644
--- a/Documentation/input/event-codes.txt
+++ b/Documentation/input/event-codes.txt
@@ -174,6 +174,13 @@ A few EV_ABS codes have special meanings:
     the input device may be used freely in three dimensions, consider ABS_Z
     instead.
 
+* ABS_SCAN_TIME:
+  - Used when the device provides a timestamp for each frame. The unit must be
+    100us, and may be reset when the device don't send any events for a
+    period of time. The values increment at each frame and thus, it can roll
+    back to 0 when reach logical_max. If the device does not provide this
+    information, the driver must not provide it to the user space.
+
 * ABS_MT_<name>:
   - Used to describe multitouch input events. Please see
     multi-touch-protocol.txt for details.
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 16cc89a..5fe7bd3 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -675,6 +675,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 			map_key_clear(BTN_STYLUS2);
 			break;
 
+		case 0x56: /* Scan Time */
+			map_abs(ABS_SCAN_TIME);
+			break;
+
 		default:  goto unknown;
 		}
 		break;
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 5aebbff..5d7fd39 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -447,19 +447,26 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 			mt_store_field(usage, td, hi);
 			td->last_field_index = field->index;
 			return 1;
+		case HID_DG_SCANTIME:
+			hid_map_usage(hi, usage, bit, max,
+				EV_ABS, ABS_SCAN_TIME);
+			set_abs(hi->input, ABS_SCAN_TIME, field, 0);
+			td->last_field_index = field->index;
+			return 1;
 		case HID_DG_CONTACTCOUNT:
 			td->last_field_index = field->index;
 			return 1;
 		case HID_DG_CONTACTMAX:
-			/* we don't set td->last_slot_field as contactcount and
-			 * contact max are global to the report */
+			/* we don't set td->last_slot_field as scan time,
+			 * contactcount and contact max are global to the
+			 * report */
 			td->last_field_index = field->index;
 			return -1;
-		}
 		case HID_DG_TOUCH:
 			/* Legacy devices use TIPSWITCH and not TOUCH.
 			 * Let's just ignore this field. */
 			return -1;
+		}
 		/* let hid-input decide for the others */
 		return 0;
 
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 6216529..99a6418 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -279,6 +279,7 @@ struct hid_item {
 #define HID_DG_DEVICEINDEX	0x000d0053
 #define HID_DG_CONTACTCOUNT	0x000d0054
 #define HID_DG_CONTACTMAX	0x000d0055
+#define HID_DG_SCANTIME		0x000d0056
 
 /*
  * HID report types --- Ouch! HID spec says 1 2 3!
diff --git a/include/linux/input.h b/include/linux/input.h
index ba48743..73c3a96 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -796,6 +796,7 @@ struct input_keymap_entry {
 #define ABS_TILT_X		0x1a
 #define ABS_TILT_Y		0x1b
 #define ABS_TOOL_WIDTH		0x1c
+#define ABS_SCAN_TIME		0x1d
 
 #define ABS_VOLUME		0x20
 
-- 
1.7.11.7


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

* [PATCH 10/10] HID: hid-multitouch: get rid of usbhid depedency for general path
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (8 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 09/10] HID: introduce Scan Time Benjamin Tissoires
@ 2012-10-25 14:09 ` Benjamin Tissoires
  2012-10-25 14:14 ` [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:09 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

This patch factorizes the hid set_feature command by using
hid_device->hid_output_raw_report instead of direclty relying on
usbhid. This makes the driver usb independant.

However I still can't remove the 2 usb related headers because the
function mt_resume has a specific patch for usb devices.

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

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 5d7fd39..8033a6b 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -670,47 +670,58 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
 	return 1;
 }
 
-static void mt_set_input_mode(struct hid_device *hdev)
+static void mt_set_feature(struct hid_device *hdev, __s8 feature_id,
+	u8 value, size_t index)
 {
-	struct mt_device *td = hid_get_drvdata(hdev);
 	struct hid_report *r;
 	struct hid_report_enum *re;
+	u8 *data;
+	u8 max_value;
+	int len;
+
+	if (feature_id < 0 || !hdev->hid_output_raw_report)
+		return;
+
+	re = &hdev->report_enum[HID_FEATURE_REPORT];
+	r = re->report_id_hash[feature_id];
+	if (!r)
+		return;
+
+	len = ((r->size - 1) >> 3) + 1 + (r->id > 0);
+	max_value = r->field[0]->logical_maximum;
+	value = min(value, max_value);
 
-	if (td->inputmode < 0)
+	if (r->field[0]->value[index] == value || len < 2 || index + 1 >= len)
 		return;
 
-	re = &(hdev->report_enum[HID_FEATURE_REPORT]);
-	r = re->report_id_hash[td->inputmode];
-	if (r) {
-		r->field[0]->value[td->inputmode_index] = 0x02;
-		usbhid_submit_report(hdev, r, USB_DIR_OUT);
+	data = kmalloc(len, GFP_ATOMIC);
+	if (!data) {
+		hid_warn(hdev, "output queueing failed\n");
+		return;
 	}
+
+	data[0] = r->id;
+	data[index + 1] = value;
+	hdev->hid_output_raw_report(hdev, data, len, HID_FEATURE_REPORT);
+	kfree(data);
 }
 
-static void mt_set_maxcontacts(struct hid_device *hdev)
+static void mt_set_input_mode(struct hid_device *hdev)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
-	struct hid_report *r;
-	struct hid_report_enum *re;
-	int fieldmax, max;
 
-	if (td->maxcontact_report_id < 0)
-		return;
+	mt_set_feature(hdev, td->inputmode, 0x02, td->inputmode_index);
+}
 
-	if (!td->mtclass.maxcontacts)
+static void mt_set_maxcontacts(struct hid_device *hdev)
+{
+	struct mt_device *td = hid_get_drvdata(hdev);
+	int max = td->mtclass.maxcontacts;
+
+	if (!max)
 		return;
 
-	re = &hdev->report_enum[HID_FEATURE_REPORT];
-	r = re->report_id_hash[td->maxcontact_report_id];
-	if (r) {
-		max = td->mtclass.maxcontacts;
-		fieldmax = r->field[0]->logical_maximum;
-		max = min(fieldmax, max);
-		if (r->field[0]->value[0] != max) {
-			r->field[0]->value[0] = max;
-			usbhid_submit_report(hdev, r, USB_DIR_OUT);
-		}
-	}
+	mt_set_feature(hdev, td->maxcontact_report_id, max, 0);
 }
 
 static void mt_post_parse_default_settings(struct mt_device *td)
-- 
1.7.11.7


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

* Re: [PATCH 0/10] Support for Win 8 digitizers
  2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
                   ` (9 preceding siblings ...)
  2012-10-25 14:09 ` [PATCH 10/10] HID: hid-multitouch: get rid of usbhid depedency for general path Benjamin Tissoires
@ 2012-10-25 14:14 ` Benjamin Tissoires
  10 siblings, 0 replies; 12+ messages in thread
From: Benjamin Tissoires @ 2012-10-25 14:14 UTC (permalink / raw)
  To: benjamin.tissoires, Dmitry Torokhov, Henrik Rydberg, Jiri Kosina,
	Stephane Chatty, linux-input, linux-kernel

Of course, I was in a rush to send the patches, and they don't apply
smoothly on top of Jiri's tree.
Sorry for that, I'll send an update tomorrow.

Cheers,
Benjamin

On Thu, Oct 25, 2012 at 4:09 PM, Benjamin Tissoires
<benjamin.tissoires@gmail.com> wrote:
> Hi guys,
>
> well, this is my first series as a Red Hat employee. I should be able to
> communicate my email address soon (once I'm able to read it).
>
> So, this is an update for supporting Win 8 multitouch devices in the kernel.
> As I wanted to reliably forward the resolution, I noticed a bug in the
> processing of the unit exponent in the hid core layer.
> Thus the fixes for hid-core and hid-input.
>
> The last patch removes the dependency for usbhid as now touchscreen may
> be connected through i2c.
>
> Cheers,
> Benjamin
>
>

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

end of thread, other threads:[~2012-10-25 14:14 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-25 14:09 [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 01/10] HID: core: fix unit exponent parsing Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 02/10] HID: hid-input: add usage_index argument in input_mapping and event Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 03/10] HID: hid-multitouch: support arrays for the split of the touches in a report Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 04/10] HID: hid-multitouch: get maxcontacts also from logical_max value Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 05/10] HID: hid-multitouch: support T and C for win8 devices Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 06/10] HID: hid-multitouch: move ALWAYS_VALID quirk check Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 07/10] HID: hid-multitouch: fix Win 8 protocol Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 08/10] HID: hid-multitouch: support for hovering devices Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 09/10] HID: introduce Scan Time Benjamin Tissoires
2012-10-25 14:09 ` [PATCH 10/10] HID: hid-multitouch: get rid of usbhid depedency for general path Benjamin Tissoires
2012-10-25 14:14 ` [PATCH 0/10] Support for Win 8 digitizers Benjamin Tissoires

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.