xref: /linux/drivers/hid/hid-multitouch.c (revision a80e803a)
15519cab4SBenjamin Tissoires /*
25519cab4SBenjamin Tissoires  *  HID driver for multitouch panels
35519cab4SBenjamin Tissoires  *
4c2ef8f21SBenjamin Tissoires  *  Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
5b0a78681SBenjamin Tissoires  *  Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
6c2ef8f21SBenjamin Tissoires  *  Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
7b0a78681SBenjamin Tissoires  *  Copyright (c) 2012-2013 Red Hat, Inc
85519cab4SBenjamin Tissoires  *
94875ac11SRichard Nauber  *  This code is partly based on hid-egalax.c:
104875ac11SRichard Nauber  *
114875ac11SRichard Nauber  *  Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
124875ac11SRichard Nauber  *  Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
134875ac11SRichard Nauber  *  Copyright (c) 2010 Canonical, Ltd.
144875ac11SRichard Nauber  *
15f786bba4SBenjamin Tissoires  *  This code is partly based on hid-3m-pct.c:
16f786bba4SBenjamin Tissoires  *
17f786bba4SBenjamin Tissoires  *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
18f786bba4SBenjamin Tissoires  *  Copyright (c) 2010      Henrik Rydberg <rydberg@euromail.se>
19f786bba4SBenjamin Tissoires  *  Copyright (c) 2010      Canonical, Ltd.
20f786bba4SBenjamin Tissoires  *
215519cab4SBenjamin Tissoires  */
225519cab4SBenjamin Tissoires 
235519cab4SBenjamin Tissoires /*
245519cab4SBenjamin Tissoires  * This program is free software; you can redistribute it and/or modify it
255519cab4SBenjamin Tissoires  * under the terms of the GNU General Public License as published by the Free
265519cab4SBenjamin Tissoires  * Software Foundation; either version 2 of the License, or (at your option)
275519cab4SBenjamin Tissoires  * any later version.
285519cab4SBenjamin Tissoires  */
295519cab4SBenjamin Tissoires 
30b0a78681SBenjamin Tissoires /*
31b0a78681SBenjamin Tissoires  * This driver is regularly tested thanks to the tool hid-test[1].
32b0a78681SBenjamin Tissoires  * This tool relies on hid-replay[2] and a database of hid devices[3].
33b0a78681SBenjamin Tissoires  * Please run these regression tests before patching this module so that
34b0a78681SBenjamin Tissoires  * your patch won't break existing known devices.
35b0a78681SBenjamin Tissoires  *
36b0a78681SBenjamin Tissoires  * [1] https://github.com/bentiss/hid-test
37b0a78681SBenjamin Tissoires  * [2] https://github.com/bentiss/hid-replay
38b0a78681SBenjamin Tissoires  * [3] https://github.com/bentiss/hid-devices
39b0a78681SBenjamin Tissoires  */
40b0a78681SBenjamin Tissoires 
415519cab4SBenjamin Tissoires #include <linux/device.h>
425519cab4SBenjamin Tissoires #include <linux/hid.h>
435519cab4SBenjamin Tissoires #include <linux/module.h>
445519cab4SBenjamin Tissoires #include <linux/slab.h>
455519cab4SBenjamin Tissoires #include <linux/input/mt.h>
4649a5a827SBenjamin Tissoires #include <linux/string.h>
475519cab4SBenjamin Tissoires 
485519cab4SBenjamin Tissoires 
495519cab4SBenjamin Tissoires MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
50ef2fafb3SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
515519cab4SBenjamin Tissoires MODULE_DESCRIPTION("HID multitouch panels");
525519cab4SBenjamin Tissoires MODULE_LICENSE("GPL");
535519cab4SBenjamin Tissoires 
545519cab4SBenjamin Tissoires #include "hid-ids.h"
555519cab4SBenjamin Tissoires 
565519cab4SBenjamin Tissoires /* quirks to control the device */
575519cab4SBenjamin Tissoires #define MT_QUIRK_NOT_SEEN_MEANS_UP	(1 << 0)
585519cab4SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTID	(1 << 1)
59a3b5e577SBenjamin Tissoires #define MT_QUIRK_CYPRESS		(1 << 2)
605572da08SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTNUMBER	(1 << 3)
61a062cc5aSStephane Chatty #define MT_QUIRK_ALWAYS_VALID		(1 << 4)
62a062cc5aSStephane Chatty #define MT_QUIRK_VALID_IS_INRANGE	(1 << 5)
63a062cc5aSStephane Chatty #define MT_QUIRK_VALID_IS_CONFIDENCE	(1 << 6)
64a062cc5aSStephane Chatty #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE	(1 << 8)
6577723e3bSHenrik Rydberg #define MT_QUIRK_NO_AREA		(1 << 9)
6628728399SBenjamin Tissoires #define MT_QUIRK_IGNORE_DUPLICATES	(1 << 10)
679b3bb9b8SBenjamin Tissoires #define MT_QUIRK_HOVERING		(1 << 11)
68c2517f62SBenjamin Tissoires #define MT_QUIRK_CONTACT_CNT_ACCURATE	(1 << 12)
69da10bc25SMathieu Magnaudet #define MT_QUIRK_FORCE_GET_FEATURE	(1 << 13)
705519cab4SBenjamin Tissoires 
719abebedbSAndrew Duggan #define MT_INPUTMODE_TOUCHSCREEN	0x02
729abebedbSAndrew Duggan #define MT_INPUTMODE_TOUCHPAD		0x03
739abebedbSAndrew Duggan 
742c6e0277SSeth Forshee #define MT_BUTTONTYPE_CLICKPAD		0
752c6e0277SSeth Forshee 
765519cab4SBenjamin Tissoires struct mt_slot {
77349fd670SBenjamin Tissoires 	__s32 x, y, cx, cy, p, w, h;
785519cab4SBenjamin Tissoires 	__s32 contactid;	/* the device ContactID assigned to this slot */
795519cab4SBenjamin Tissoires 	bool touch_state;	/* is the touch valid? */
809b3bb9b8SBenjamin Tissoires 	bool inrange_state;	/* is the finger in proximity of the sensor? */
815519cab4SBenjamin Tissoires };
825519cab4SBenjamin Tissoires 
835519cab4SBenjamin Tissoires struct mt_class {
842d93666eSBenjamin Tissoires 	__s32 name;	/* MT_CLS */
855519cab4SBenjamin Tissoires 	__s32 quirks;
865519cab4SBenjamin Tissoires 	__s32 sn_move;	/* Signal/noise ratio for move events */
87f786bba4SBenjamin Tissoires 	__s32 sn_width;	/* Signal/noise ratio for width events */
88f786bba4SBenjamin Tissoires 	__s32 sn_height;	/* Signal/noise ratio for height events */
895519cab4SBenjamin Tissoires 	__s32 sn_pressure;	/* Signal/noise ratio for pressure events */
905519cab4SBenjamin Tissoires 	__u8 maxcontacts;
91c2ef8f21SBenjamin Tissoires 	bool is_indirect;	/* true for touchpads */
926aef704eSBenjamin Tissoires 	bool export_all_inputs;	/* do not ignore mouse, keyboards, etc... */
935519cab4SBenjamin Tissoires };
945519cab4SBenjamin Tissoires 
953ac36d15SBenjamin Tissoires struct mt_fields {
963ac36d15SBenjamin Tissoires 	unsigned usages[HID_MAX_FIELDS];
973ac36d15SBenjamin Tissoires 	unsigned int length;
983ac36d15SBenjamin Tissoires };
993ac36d15SBenjamin Tissoires 
1005519cab4SBenjamin Tissoires struct mt_device {
1015519cab4SBenjamin Tissoires 	struct mt_slot curdata;	/* placeholder of incoming data */
102eec29e3dSBenjamin Tissoires 	struct mt_class mtclass;	/* our mt device class */
1033ac36d15SBenjamin Tissoires 	struct mt_fields *fields;	/* temporary placeholder for storing the
1043ac36d15SBenjamin Tissoires 					   multitouch fields */
1057e3cc447SBenjamin Tissoires 	int cc_index;	/* contact count field index in the report */
1067e3cc447SBenjamin Tissoires 	int cc_value_index;	/* contact count value index in the field */
1075519cab4SBenjamin Tissoires 	unsigned last_slot_field;	/* the last field of a slot */
10855978fa9SBenjamin Tissoires 	unsigned mt_report_id;	/* the report ID of the multitouch device */
1098821f5dcSBenjamin Tissoires 	__s16 inputmode;	/* InputMode HID feature, -1 if non-existent */
1108821f5dcSBenjamin Tissoires 	__s16 inputmode_index;	/* InputMode HID feature index in the report */
1118821f5dcSBenjamin Tissoires 	__s16 maxcontact_report_id;	/* Maximum Contact Number HID feature,
11231ae9bddSBenjamin Tissoires 				   -1 if non-existent */
1139abebedbSAndrew Duggan 	__u8 inputmode_value;  /* InputMode HID feature value */
1145519cab4SBenjamin Tissoires 	__u8 num_received;	/* how many contacts we received */
1155519cab4SBenjamin Tissoires 	__u8 num_expected;	/* expected last contact index */
1165519cab4SBenjamin Tissoires 	__u8 maxcontacts;
1179e87f22aSBenjamin Tissoires 	__u8 touches_by_report;	/* how many touches are present in one report:
1189e87f22aSBenjamin Tissoires 				* 1 means we should use a serial protocol
1199e87f22aSBenjamin Tissoires 				* > 1 means hybrid (multitouch) protocol */
120015fdaa9SBenjamin Tissoires 	__u8 buttons_count;	/* number of physical buttons per touchpad */
1212c6e0277SSeth Forshee 	bool is_buttonpad;	/* is this device a button pad? */
12276f5902aSHenrik Rydberg 	bool serial_maybe;	/* need to check for serial protocol */
1235519cab4SBenjamin Tissoires 	bool curvalid;		/* is the current contact valid? */
12476f5902aSHenrik Rydberg 	unsigned mt_flags;	/* flags to pass to input-mt */
1255519cab4SBenjamin Tissoires };
1265519cab4SBenjamin Tissoires 
127a69c5f8bSBenjamin Tissoires static void mt_post_parse_default_settings(struct mt_device *td);
128a69c5f8bSBenjamin Tissoires static void mt_post_parse(struct mt_device *td);
129a69c5f8bSBenjamin Tissoires 
1305519cab4SBenjamin Tissoires /* classes of device behavior */
13122408283SBenjamin Tissoires #define MT_CLS_DEFAULT				0x0001
13222408283SBenjamin Tissoires 
133a062cc5aSStephane Chatty #define MT_CLS_SERIAL				0x0002
134a062cc5aSStephane Chatty #define MT_CLS_CONFIDENCE			0x0003
1355e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_CONTACT_ID		0x0004
1365e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_MINUS_ONE		0x0005
1375e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTID		0x0006
1385e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER	0x0007
1390fa9c616SBenjamin Tissoires /* reserved					0x0008 */
140b7ea95ffSAaron Tian #define MT_CLS_INRANGE_CONTACTNUMBER		0x0009
141dc3e1d80SBenjamin Tissoires #define MT_CLS_NSMU				0x000a
1420fa9c616SBenjamin Tissoires /* reserved					0x0010 */
1430fa9c616SBenjamin Tissoires /* reserved					0x0011 */
144f961bd35SBenjamin Tissoires #define MT_CLS_WIN_8				0x0012
1456aef704eSBenjamin Tissoires #define MT_CLS_EXPORT_ALL_INPUTS		0x0013
14622408283SBenjamin Tissoires 
14722408283SBenjamin Tissoires /* vendor specific classes */
14822408283SBenjamin Tissoires #define MT_CLS_3M				0x0101
1490fa9c616SBenjamin Tissoires /* reserved					0x0102 */
15022408283SBenjamin Tissoires #define MT_CLS_EGALAX				0x0103
1511b723e8dSBenjamin Tissoires #define MT_CLS_EGALAX_SERIAL			0x0104
152847672cdSBenjamin Tissoires #define MT_CLS_TOPSEED				0x0105
1532258e863SDenis Kovalev #define MT_CLS_PANASONIC			0x0106
15477723e3bSHenrik Rydberg #define MT_CLS_FLATFROG				0x0107
155cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_TWOFINGERS		0x0108
156cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS	0x0109
157da10bc25SMathieu Magnaudet #define MT_CLS_VTL				0x0110
1585519cab4SBenjamin Tissoires 
1599498f954SBenjamin Tissoires #define MT_DEFAULT_MAXCONTACT	10
160afbcb04cSBenjamin Tissoires #define MT_MAX_MAXCONTACT	250
1619498f954SBenjamin Tissoires 
1622c2110e9SHenrik Rydberg #define MT_USB_DEVICE(v, p)	HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
1632c2110e9SHenrik Rydberg #define MT_BT_DEVICE(v, p)	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
1642c2110e9SHenrik Rydberg 
1655519cab4SBenjamin Tissoires /*
1665519cab4SBenjamin Tissoires  * these device-dependent functions determine what slot corresponds
1675519cab4SBenjamin Tissoires  * to a valid contact that was just read.
1685519cab4SBenjamin Tissoires  */
1695519cab4SBenjamin Tissoires 
170a3b5e577SBenjamin Tissoires static int cypress_compute_slot(struct mt_device *td)
171a3b5e577SBenjamin Tissoires {
172a3b5e577SBenjamin Tissoires 	if (td->curdata.contactid != 0 || td->num_received == 0)
173a3b5e577SBenjamin Tissoires 		return td->curdata.contactid;
174a3b5e577SBenjamin Tissoires 	else
175a3b5e577SBenjamin Tissoires 		return -1;
176a3b5e577SBenjamin Tissoires }
177a3b5e577SBenjamin Tissoires 
178b3c21d2cSJiri Kosina static struct mt_class mt_classes[] = {
1792d93666eSBenjamin Tissoires 	{ .name = MT_CLS_DEFAULT,
180dc3e1d80SBenjamin Tissoires 		.quirks = MT_QUIRK_ALWAYS_VALID |
181dc3e1d80SBenjamin Tissoires 			MT_QUIRK_CONTACT_CNT_ACCURATE },
182dc3e1d80SBenjamin Tissoires 	{ .name = MT_CLS_NSMU,
1839498f954SBenjamin Tissoires 		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
184a062cc5aSStephane Chatty 	{ .name = MT_CLS_SERIAL,
185a062cc5aSStephane Chatty 		.quirks = MT_QUIRK_ALWAYS_VALID},
18622408283SBenjamin Tissoires 	{ .name = MT_CLS_CONFIDENCE,
18722408283SBenjamin Tissoires 		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE },
1885e7ea11fSBenjamin Tissoires 	{ .name = MT_CLS_CONFIDENCE_CONTACT_ID,
1895e7ea11fSBenjamin Tissoires 		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
1905e7ea11fSBenjamin Tissoires 			MT_QUIRK_SLOT_IS_CONTACTID },
19122408283SBenjamin Tissoires 	{ .name = MT_CLS_CONFIDENCE_MINUS_ONE,
19222408283SBenjamin Tissoires 		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
19322408283SBenjamin Tissoires 			MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE },
1941e9cf35bSBenjamin Tissoires 	{ .name = MT_CLS_DUAL_INRANGE_CONTACTID,
1952d93666eSBenjamin Tissoires 		.quirks = MT_QUIRK_VALID_IS_INRANGE |
1962d93666eSBenjamin Tissoires 			MT_QUIRK_SLOT_IS_CONTACTID,
1972d93666eSBenjamin Tissoires 		.maxcontacts = 2 },
1981e9cf35bSBenjamin Tissoires 	{ .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
1992d93666eSBenjamin Tissoires 		.quirks = MT_QUIRK_VALID_IS_INRANGE |
2002d93666eSBenjamin Tissoires 			MT_QUIRK_SLOT_IS_CONTACTNUMBER,
2012d93666eSBenjamin Tissoires 		.maxcontacts = 2 },
202b7ea95ffSAaron Tian 	{ .name = MT_CLS_INRANGE_CONTACTNUMBER,
203b7ea95ffSAaron Tian 		.quirks = MT_QUIRK_VALID_IS_INRANGE |
204b7ea95ffSAaron Tian 			MT_QUIRK_SLOT_IS_CONTACTNUMBER },
205f961bd35SBenjamin Tissoires 	{ .name = MT_CLS_WIN_8,
206f961bd35SBenjamin Tissoires 		.quirks = MT_QUIRK_ALWAYS_VALID |
207f961bd35SBenjamin Tissoires 			MT_QUIRK_IGNORE_DUPLICATES |
208f961bd35SBenjamin Tissoires 			MT_QUIRK_HOVERING |
209f961bd35SBenjamin Tissoires 			MT_QUIRK_CONTACT_CNT_ACCURATE },
2106aef704eSBenjamin Tissoires 	{ .name = MT_CLS_EXPORT_ALL_INPUTS,
2116aef704eSBenjamin Tissoires 		.quirks = MT_QUIRK_ALWAYS_VALID |
2126aef704eSBenjamin Tissoires 			MT_QUIRK_CONTACT_CNT_ACCURATE,
2136aef704eSBenjamin Tissoires 		.export_all_inputs = true },
21422408283SBenjamin Tissoires 
21522408283SBenjamin Tissoires 	/*
21622408283SBenjamin Tissoires 	 * vendor specific classes
21722408283SBenjamin Tissoires 	 */
21822408283SBenjamin Tissoires 	{ .name = MT_CLS_3M,
21922408283SBenjamin Tissoires 		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
22022408283SBenjamin Tissoires 			MT_QUIRK_SLOT_IS_CONTACTID,
22122408283SBenjamin Tissoires 		.sn_move = 2048,
22222408283SBenjamin Tissoires 		.sn_width = 128,
223c5d40be5SHenrik Rydberg 		.sn_height = 128,
224c5d40be5SHenrik Rydberg 		.maxcontacts = 60,
225c5d40be5SHenrik Rydberg 	},
2264875ac11SRichard Nauber 	{ .name = MT_CLS_EGALAX,
2274875ac11SRichard Nauber 		.quirks =  MT_QUIRK_SLOT_IS_CONTACTID |
2282261bb9fSBenjamin Tissoires 			MT_QUIRK_VALID_IS_INRANGE,
2294875ac11SRichard Nauber 		.sn_move = 4096,
2304875ac11SRichard Nauber 		.sn_pressure = 32,
2314875ac11SRichard Nauber 	},
2321b723e8dSBenjamin Tissoires 	{ .name = MT_CLS_EGALAX_SERIAL,
2331b723e8dSBenjamin Tissoires 		.quirks =  MT_QUIRK_SLOT_IS_CONTACTID |
2341b723e8dSBenjamin Tissoires 			MT_QUIRK_ALWAYS_VALID,
2352d93666eSBenjamin Tissoires 		.sn_move = 4096,
2362d93666eSBenjamin Tissoires 		.sn_pressure = 32,
2372d93666eSBenjamin Tissoires 	},
238847672cdSBenjamin Tissoires 	{ .name = MT_CLS_TOPSEED,
239847672cdSBenjamin Tissoires 		.quirks = MT_QUIRK_ALWAYS_VALID,
240847672cdSBenjamin Tissoires 		.is_indirect = true,
241847672cdSBenjamin Tissoires 		.maxcontacts = 2,
242847672cdSBenjamin Tissoires 	},
2432258e863SDenis Kovalev 	{ .name = MT_CLS_PANASONIC,
2442258e863SDenis Kovalev 		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
2452258e863SDenis Kovalev 		.maxcontacts = 4 },
246f5ff4e1eSXianhan Yu 	{ .name	= MT_CLS_GENERALTOUCH_TWOFINGERS,
247f5ff4e1eSXianhan Yu 		.quirks	= MT_QUIRK_NOT_SEEN_MEANS_UP |
248f5ff4e1eSXianhan Yu 			MT_QUIRK_VALID_IS_INRANGE |
2497b226292SLuosong 			MT_QUIRK_SLOT_IS_CONTACTID,
250f5ff4e1eSXianhan Yu 		.maxcontacts = 2
251f5ff4e1eSXianhan Yu 	},
252f5ff4e1eSXianhan Yu 	{ .name	= MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
253f5ff4e1eSXianhan Yu 		.quirks	= MT_QUIRK_NOT_SEEN_MEANS_UP |
2547b226292SLuosong 			MT_QUIRK_SLOT_IS_CONTACTID
255f5ff4e1eSXianhan Yu 	},
256043b403aSBenjamin Tissoires 
25777723e3bSHenrik Rydberg 	{ .name = MT_CLS_FLATFROG,
25877723e3bSHenrik Rydberg 		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
25977723e3bSHenrik Rydberg 			MT_QUIRK_NO_AREA,
26077723e3bSHenrik Rydberg 		.sn_move = 2048,
26177723e3bSHenrik Rydberg 		.maxcontacts = 40,
26277723e3bSHenrik Rydberg 	},
263da10bc25SMathieu Magnaudet 	{ .name = MT_CLS_VTL,
264da10bc25SMathieu Magnaudet 		.quirks = MT_QUIRK_ALWAYS_VALID |
265da10bc25SMathieu Magnaudet 			MT_QUIRK_CONTACT_CNT_ACCURATE |
266da10bc25SMathieu Magnaudet 			MT_QUIRK_FORCE_GET_FEATURE,
267da10bc25SMathieu Magnaudet 	},
2682d93666eSBenjamin Tissoires 	{ }
2695519cab4SBenjamin Tissoires };
2705519cab4SBenjamin Tissoires 
271eec29e3dSBenjamin Tissoires static ssize_t mt_show_quirks(struct device *dev,
272eec29e3dSBenjamin Tissoires 			   struct device_attribute *attr,
273eec29e3dSBenjamin Tissoires 			   char *buf)
274eec29e3dSBenjamin Tissoires {
275ee79a8f8SGeliang Tang 	struct hid_device *hdev = to_hid_device(dev);
276eec29e3dSBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
277eec29e3dSBenjamin Tissoires 
278eec29e3dSBenjamin Tissoires 	return sprintf(buf, "%u\n", td->mtclass.quirks);
279eec29e3dSBenjamin Tissoires }
280eec29e3dSBenjamin Tissoires 
281eec29e3dSBenjamin Tissoires static ssize_t mt_set_quirks(struct device *dev,
282eec29e3dSBenjamin Tissoires 			  struct device_attribute *attr,
283eec29e3dSBenjamin Tissoires 			  const char *buf, size_t count)
284eec29e3dSBenjamin Tissoires {
285ee79a8f8SGeliang Tang 	struct hid_device *hdev = to_hid_device(dev);
286eec29e3dSBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
287eec29e3dSBenjamin Tissoires 
288eec29e3dSBenjamin Tissoires 	unsigned long val;
289eec29e3dSBenjamin Tissoires 
290eec29e3dSBenjamin Tissoires 	if (kstrtoul(buf, 0, &val))
291eec29e3dSBenjamin Tissoires 		return -EINVAL;
292eec29e3dSBenjamin Tissoires 
293eec29e3dSBenjamin Tissoires 	td->mtclass.quirks = val;
294eec29e3dSBenjamin Tissoires 
2957e3cc447SBenjamin Tissoires 	if (td->cc_index < 0)
296c2517f62SBenjamin Tissoires 		td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
297c2517f62SBenjamin Tissoires 
298eec29e3dSBenjamin Tissoires 	return count;
299eec29e3dSBenjamin Tissoires }
300eec29e3dSBenjamin Tissoires 
301eec29e3dSBenjamin Tissoires static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks);
302eec29e3dSBenjamin Tissoires 
303eec29e3dSBenjamin Tissoires static struct attribute *sysfs_attrs[] = {
304eec29e3dSBenjamin Tissoires 	&dev_attr_quirks.attr,
305eec29e3dSBenjamin Tissoires 	NULL
306eec29e3dSBenjamin Tissoires };
307eec29e3dSBenjamin Tissoires 
308eec29e3dSBenjamin Tissoires static struct attribute_group mt_attribute_group = {
309eec29e3dSBenjamin Tissoires 	.attrs = sysfs_attrs
310eec29e3dSBenjamin Tissoires };
311eec29e3dSBenjamin Tissoires 
3126d4f5440SMika Westerberg static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
3136d4f5440SMika Westerberg {
3146d4f5440SMika Westerberg 	struct mt_device *td = hid_get_drvdata(hdev);
3156d4f5440SMika Westerberg 	int ret, size = hid_report_len(report);
3166d4f5440SMika Westerberg 	u8 *buf;
3176d4f5440SMika Westerberg 
3186d4f5440SMika Westerberg 	/*
3196d4f5440SMika Westerberg 	 * Only fetch the feature report if initial reports are not already
3206d4f5440SMika Westerberg 	 * been retrieved. Currently this is only done for Windows 8 touch
3216d4f5440SMika Westerberg 	 * devices.
3226d4f5440SMika Westerberg 	 */
3236d4f5440SMika Westerberg 	if (!(hdev->quirks & HID_QUIRK_NO_INIT_REPORTS))
3246d4f5440SMika Westerberg 		return;
3256d4f5440SMika Westerberg 	if (td->mtclass.name != MT_CLS_WIN_8)
3266d4f5440SMika Westerberg 		return;
3276d4f5440SMika Westerberg 
3286d4f5440SMika Westerberg 	buf = hid_alloc_report_buf(report, GFP_KERNEL);
3296d4f5440SMika Westerberg 	if (!buf)
3306d4f5440SMika Westerberg 		return;
3316d4f5440SMika Westerberg 
3326d4f5440SMika Westerberg 	ret = hid_hw_raw_request(hdev, report->id, buf, size,
3336d4f5440SMika Westerberg 				 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
3346d4f5440SMika Westerberg 	if (ret < 0) {
3356d4f5440SMika Westerberg 		dev_warn(&hdev->dev, "failed to fetch feature %d\n",
3366d4f5440SMika Westerberg 			 report->id);
3376d4f5440SMika Westerberg 	} else {
3386d4f5440SMika Westerberg 		ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
3396d4f5440SMika Westerberg 					   size, 0);
3406d4f5440SMika Westerberg 		if (ret)
3416d4f5440SMika Westerberg 			dev_warn(&hdev->dev, "failed to report feature\n");
3426d4f5440SMika Westerberg 	}
3436d4f5440SMika Westerberg 
3446d4f5440SMika Westerberg 	kfree(buf);
3456d4f5440SMika Westerberg }
3466d4f5440SMika Westerberg 
347f635bd11SHenrik Rydberg static void mt_feature_mapping(struct hid_device *hdev,
3485519cab4SBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage)
3495519cab4SBenjamin Tissoires {
3505519cab4SBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
3519498f954SBenjamin Tissoires 
3529498f954SBenjamin Tissoires 	switch (usage->hid) {
3539498f954SBenjamin Tissoires 	case HID_DG_INPUTMODE:
3548821f5dcSBenjamin Tissoires 		/* Ignore if value index is out of bounds. */
3558821f5dcSBenjamin Tissoires 		if (usage->usage_index >= field->report_count) {
3568821f5dcSBenjamin Tissoires 			dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
3574aceed37SBenjamin Tissoires 			break;
3584aceed37SBenjamin Tissoires 		}
3598821f5dcSBenjamin Tissoires 
36073e7d63eSBenjamin Tissoires 		if (td->inputmode < 0) {
3618821f5dcSBenjamin Tissoires 			td->inputmode = field->report->id;
3628821f5dcSBenjamin Tissoires 			td->inputmode_index = usage->usage_index;
36373e7d63eSBenjamin Tissoires 		} else {
36473e7d63eSBenjamin Tissoires 			/*
36573e7d63eSBenjamin Tissoires 			 * Some elan panels wrongly declare 2 input mode
36673e7d63eSBenjamin Tissoires 			 * features, and silently ignore when we set the
36773e7d63eSBenjamin Tissoires 			 * value in the second field. Skip the second feature
36873e7d63eSBenjamin Tissoires 			 * and hope for the best.
36973e7d63eSBenjamin Tissoires 			 */
37073e7d63eSBenjamin Tissoires 			dev_info(&hdev->dev,
37173e7d63eSBenjamin Tissoires 				 "Ignoring the extra HID_DG_INPUTMODE\n");
37273e7d63eSBenjamin Tissoires 		}
3734aceed37SBenjamin Tissoires 
3749498f954SBenjamin Tissoires 		break;
3759498f954SBenjamin Tissoires 	case HID_DG_CONTACTMAX:
3766d4f5440SMika Westerberg 		mt_get_feature(hdev, field->report);
3776d4f5440SMika Westerberg 
37831ae9bddSBenjamin Tissoires 		td->maxcontact_report_id = field->report->id;
3799498f954SBenjamin Tissoires 		td->maxcontacts = field->value[0];
380afbcb04cSBenjamin Tissoires 		if (!td->maxcontacts &&
381afbcb04cSBenjamin Tissoires 		    field->logical_maximum <= MT_MAX_MAXCONTACT)
382afbcb04cSBenjamin Tissoires 			td->maxcontacts = field->logical_maximum;
383eec29e3dSBenjamin Tissoires 		if (td->mtclass.maxcontacts)
3849498f954SBenjamin Tissoires 			/* check if the maxcontacts is given by the class */
385eec29e3dSBenjamin Tissoires 			td->maxcontacts = td->mtclass.maxcontacts;
3869498f954SBenjamin Tissoires 
3879498f954SBenjamin Tissoires 		break;
3882c6e0277SSeth Forshee 	case HID_DG_BUTTONTYPE:
3892c6e0277SSeth Forshee 		if (usage->usage_index >= field->report_count) {
3902c6e0277SSeth Forshee 			dev_err(&hdev->dev, "HID_DG_BUTTONTYPE out of range\n");
3912c6e0277SSeth Forshee 			break;
3922c6e0277SSeth Forshee 		}
3932c6e0277SSeth Forshee 
3946d4f5440SMika Westerberg 		mt_get_feature(hdev, field->report);
3952c6e0277SSeth Forshee 		if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD)
3962c6e0277SSeth Forshee 			td->is_buttonpad = true;
3972c6e0277SSeth Forshee 
3982c6e0277SSeth Forshee 		break;
39945c5c682SBenjamin Tissoires 	case 0xff0000c5:
40045c5c682SBenjamin Tissoires 		/* Retrieve the Win8 blob once to enable some devices */
40145c5c682SBenjamin Tissoires 		if (usage->usage_index == 0)
40245c5c682SBenjamin Tissoires 			mt_get_feature(hdev, field->report);
40345c5c682SBenjamin Tissoires 		break;
4045519cab4SBenjamin Tissoires 	}
4055519cab4SBenjamin Tissoires }
4065519cab4SBenjamin Tissoires 
4075519cab4SBenjamin Tissoires static void set_abs(struct input_dev *input, unsigned int code,
4085519cab4SBenjamin Tissoires 		struct hid_field *field, int snratio)
4095519cab4SBenjamin Tissoires {
4105519cab4SBenjamin Tissoires 	int fmin = field->logical_minimum;
4115519cab4SBenjamin Tissoires 	int fmax = field->logical_maximum;
4125519cab4SBenjamin Tissoires 	int fuzz = snratio ? (fmax - fmin) / snratio : 0;
4135519cab4SBenjamin Tissoires 	input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
41437cf6e6fSBenjamin Tissoires 	input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
4155519cab4SBenjamin Tissoires }
4165519cab4SBenjamin Tissoires 
4173ac36d15SBenjamin Tissoires static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
418ed9d5c96SBenjamin Tissoires 		struct hid_input *hi)
419ed9d5c96SBenjamin Tissoires {
4203ac36d15SBenjamin Tissoires 	struct mt_fields *f = td->fields;
4213ac36d15SBenjamin Tissoires 
4223ac36d15SBenjamin Tissoires 	if (f->length >= HID_MAX_FIELDS)
4233ac36d15SBenjamin Tissoires 		return;
4243ac36d15SBenjamin Tissoires 
4253ac36d15SBenjamin Tissoires 	f->usages[f->length++] = usage->hid;
426ed9d5c96SBenjamin Tissoires }
427ed9d5c96SBenjamin Tissoires 
428a69c5f8bSBenjamin Tissoires static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
4295519cab4SBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage,
4305519cab4SBenjamin Tissoires 		unsigned long **bit, int *max)
4315519cab4SBenjamin Tissoires {
4325519cab4SBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
433eec29e3dSBenjamin Tissoires 	struct mt_class *cls = &td->mtclass;
434c2ef8f21SBenjamin Tissoires 	int code;
435349fd670SBenjamin Tissoires 	struct hid_usage *prev_usage = NULL;
4364875ac11SRichard Nauber 
437658d4aedSJeff Brown 	if (field->application == HID_DG_TOUCHSCREEN)
43876f5902aSHenrik Rydberg 		td->mt_flags |= INPUT_MT_DIRECT;
439658d4aedSJeff Brown 
44076f5902aSHenrik Rydberg 	/*
44176f5902aSHenrik Rydberg 	 * Model touchscreens providing buttons as touchpads.
442c2ef8f21SBenjamin Tissoires 	 */
443c2ef8f21SBenjamin Tissoires 	if (field->application == HID_DG_TOUCHPAD ||
4449abebedbSAndrew Duggan 	    (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
44576f5902aSHenrik Rydberg 		td->mt_flags |= INPUT_MT_POINTER;
4469abebedbSAndrew Duggan 		td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
4479abebedbSAndrew Duggan 	}
448c2ef8f21SBenjamin Tissoires 
449015fdaa9SBenjamin Tissoires 	/* count the buttons on touchpads */
450015fdaa9SBenjamin Tissoires 	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
451015fdaa9SBenjamin Tissoires 		td->buttons_count++;
452015fdaa9SBenjamin Tissoires 
453349fd670SBenjamin Tissoires 	if (usage->usage_index)
454349fd670SBenjamin Tissoires 		prev_usage = &field->usage[usage->usage_index - 1];
455349fd670SBenjamin Tissoires 
4565519cab4SBenjamin Tissoires 	switch (usage->hid & HID_USAGE_PAGE) {
4575519cab4SBenjamin Tissoires 
4585519cab4SBenjamin Tissoires 	case HID_UP_GENDESK:
4595519cab4SBenjamin Tissoires 		switch (usage->hid) {
4605519cab4SBenjamin Tissoires 		case HID_GD_X:
461349fd670SBenjamin Tissoires 			if (prev_usage && (prev_usage->hid == usage->hid)) {
462349fd670SBenjamin Tissoires 				hid_map_usage(hi, usage, bit, max,
463349fd670SBenjamin Tissoires 					EV_ABS, ABS_MT_TOOL_X);
464349fd670SBenjamin Tissoires 				set_abs(hi->input, ABS_MT_TOOL_X, field,
465349fd670SBenjamin Tissoires 					cls->sn_move);
466349fd670SBenjamin Tissoires 			} else {
4675519cab4SBenjamin Tissoires 				hid_map_usage(hi, usage, bit, max,
4685519cab4SBenjamin Tissoires 					EV_ABS, ABS_MT_POSITION_X);
4695519cab4SBenjamin Tissoires 				set_abs(hi->input, ABS_MT_POSITION_X, field,
4705519cab4SBenjamin Tissoires 					cls->sn_move);
471349fd670SBenjamin Tissoires 			}
472349fd670SBenjamin Tissoires 
4733ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
4745519cab4SBenjamin Tissoires 			return 1;
4755519cab4SBenjamin Tissoires 		case HID_GD_Y:
476349fd670SBenjamin Tissoires 			if (prev_usage && (prev_usage->hid == usage->hid)) {
477349fd670SBenjamin Tissoires 				hid_map_usage(hi, usage, bit, max,
478349fd670SBenjamin Tissoires 					EV_ABS, ABS_MT_TOOL_Y);
479349fd670SBenjamin Tissoires 				set_abs(hi->input, ABS_MT_TOOL_Y, field,
480349fd670SBenjamin Tissoires 					cls->sn_move);
481349fd670SBenjamin Tissoires 			} else {
4825519cab4SBenjamin Tissoires 				hid_map_usage(hi, usage, bit, max,
4835519cab4SBenjamin Tissoires 					EV_ABS, ABS_MT_POSITION_Y);
4845519cab4SBenjamin Tissoires 				set_abs(hi->input, ABS_MT_POSITION_Y, field,
4855519cab4SBenjamin Tissoires 					cls->sn_move);
486349fd670SBenjamin Tissoires 			}
487349fd670SBenjamin Tissoires 
4883ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
4895519cab4SBenjamin Tissoires 			return 1;
4905519cab4SBenjamin Tissoires 		}
4915519cab4SBenjamin Tissoires 		return 0;
4925519cab4SBenjamin Tissoires 
4935519cab4SBenjamin Tissoires 	case HID_UP_DIGITIZER:
4945519cab4SBenjamin Tissoires 		switch (usage->hid) {
4955519cab4SBenjamin Tissoires 		case HID_DG_INRANGE:
4969b3bb9b8SBenjamin Tissoires 			if (cls->quirks & MT_QUIRK_HOVERING) {
4979b3bb9b8SBenjamin Tissoires 				hid_map_usage(hi, usage, bit, max,
4989b3bb9b8SBenjamin Tissoires 					EV_ABS, ABS_MT_DISTANCE);
4999b3bb9b8SBenjamin Tissoires 				input_set_abs_params(hi->input,
5009b3bb9b8SBenjamin Tissoires 					ABS_MT_DISTANCE, 0, 1, 0, 0);
5019b3bb9b8SBenjamin Tissoires 			}
5023ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
5035519cab4SBenjamin Tissoires 			return 1;
5045519cab4SBenjamin Tissoires 		case HID_DG_CONFIDENCE:
50525a84db1SAllen Hung 			if (cls->name == MT_CLS_WIN_8 &&
50625a84db1SAllen Hung 				field->application == HID_DG_TOUCHPAD) {
50725a84db1SAllen Hung 				cls->quirks &= ~MT_QUIRK_ALWAYS_VALID;
50825a84db1SAllen Hung 				cls->quirks |= MT_QUIRK_VALID_IS_CONFIDENCE;
50925a84db1SAllen Hung 			}
5103ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
5115519cab4SBenjamin Tissoires 			return 1;
5125519cab4SBenjamin Tissoires 		case HID_DG_TIPSWITCH:
5135519cab4SBenjamin Tissoires 			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
5145519cab4SBenjamin Tissoires 			input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
5153ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
5165519cab4SBenjamin Tissoires 			return 1;
5175519cab4SBenjamin Tissoires 		case HID_DG_CONTACTID:
5183ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
5199e87f22aSBenjamin Tissoires 			td->touches_by_report++;
52055978fa9SBenjamin Tissoires 			td->mt_report_id = field->report->id;
5215519cab4SBenjamin Tissoires 			return 1;
5225519cab4SBenjamin Tissoires 		case HID_DG_WIDTH:
5235519cab4SBenjamin Tissoires 			hid_map_usage(hi, usage, bit, max,
5245519cab4SBenjamin Tissoires 					EV_ABS, ABS_MT_TOUCH_MAJOR);
52577723e3bSHenrik Rydberg 			if (!(cls->quirks & MT_QUIRK_NO_AREA))
526f786bba4SBenjamin Tissoires 				set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
527f786bba4SBenjamin Tissoires 					cls->sn_width);
5283ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
5295519cab4SBenjamin Tissoires 			return 1;
5305519cab4SBenjamin Tissoires 		case HID_DG_HEIGHT:
5315519cab4SBenjamin Tissoires 			hid_map_usage(hi, usage, bit, max,
5325519cab4SBenjamin Tissoires 					EV_ABS, ABS_MT_TOUCH_MINOR);
53377723e3bSHenrik Rydberg 			if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
534f786bba4SBenjamin Tissoires 				set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
535f786bba4SBenjamin Tissoires 					cls->sn_height);
5361e648a13SBenjamin Tissoires 				input_set_abs_params(hi->input,
5371e648a13SBenjamin Tissoires 					ABS_MT_ORIENTATION, 0, 1, 0, 0);
53877723e3bSHenrik Rydberg 			}
5393ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
5405519cab4SBenjamin Tissoires 			return 1;
5415519cab4SBenjamin Tissoires 		case HID_DG_TIPPRESSURE:
5425519cab4SBenjamin Tissoires 			hid_map_usage(hi, usage, bit, max,
5435519cab4SBenjamin Tissoires 					EV_ABS, ABS_MT_PRESSURE);
5445519cab4SBenjamin Tissoires 			set_abs(hi->input, ABS_MT_PRESSURE, field,
5455519cab4SBenjamin Tissoires 				cls->sn_pressure);
5463ac36d15SBenjamin Tissoires 			mt_store_field(usage, td, hi);
5475519cab4SBenjamin Tissoires 			return 1;
5485519cab4SBenjamin Tissoires 		case HID_DG_CONTACTCOUNT:
5498821f5dcSBenjamin Tissoires 			/* Ignore if indexes are out of bounds. */
5508821f5dcSBenjamin Tissoires 			if (field->index >= field->report->maxfield ||
5518821f5dcSBenjamin Tissoires 			    usage->usage_index >= field->report_count)
5528821f5dcSBenjamin Tissoires 				return 1;
5537e3cc447SBenjamin Tissoires 			td->cc_index = field->index;
5547e3cc447SBenjamin Tissoires 			td->cc_value_index = usage->usage_index;
5555519cab4SBenjamin Tissoires 			return 1;
5565519cab4SBenjamin Tissoires 		case HID_DG_CONTACTMAX:
5575519cab4SBenjamin Tissoires 			/* we don't set td->last_slot_field as contactcount and
5585519cab4SBenjamin Tissoires 			 * contact max are global to the report */
5595519cab4SBenjamin Tissoires 			return -1;
560c2ef8f21SBenjamin Tissoires 		case HID_DG_TOUCH:
561c2ef8f21SBenjamin Tissoires 			/* Legacy devices use TIPSWITCH and not TOUCH.
562c2ef8f21SBenjamin Tissoires 			 * Let's just ignore this field. */
563c2ef8f21SBenjamin Tissoires 			return -1;
56465b258e9SAlan Cox 		}
5655519cab4SBenjamin Tissoires 		/* let hid-input decide for the others */
5665519cab4SBenjamin Tissoires 		return 0;
5675519cab4SBenjamin Tissoires 
568c2ef8f21SBenjamin Tissoires 	case HID_UP_BUTTON:
569c2ef8f21SBenjamin Tissoires 		code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE);
570c2ef8f21SBenjamin Tissoires 		hid_map_usage(hi, usage, bit, max, EV_KEY, code);
571c2ef8f21SBenjamin Tissoires 		input_set_capability(hi->input, EV_KEY, code);
572c2ef8f21SBenjamin Tissoires 		return 1;
573c2ef8f21SBenjamin Tissoires 
5745519cab4SBenjamin Tissoires 	case 0xff000000:
5755519cab4SBenjamin Tissoires 		/* we do not want to map these: no input-oriented meaning */
5765519cab4SBenjamin Tissoires 		return -1;
5775519cab4SBenjamin Tissoires 	}
5785519cab4SBenjamin Tissoires 
5795519cab4SBenjamin Tissoires 	return 0;
5805519cab4SBenjamin Tissoires }
5815519cab4SBenjamin Tissoires 
582a69c5f8bSBenjamin Tissoires static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi,
5835519cab4SBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage,
5845519cab4SBenjamin Tissoires 		unsigned long **bit, int *max)
5855519cab4SBenjamin Tissoires {
5865519cab4SBenjamin Tissoires 	if (usage->type == EV_KEY || usage->type == EV_ABS)
5875519cab4SBenjamin Tissoires 		set_bit(usage->type, hi->input->evbit);
5885519cab4SBenjamin Tissoires 
5895519cab4SBenjamin Tissoires 	return -1;
5905519cab4SBenjamin Tissoires }
5915519cab4SBenjamin Tissoires 
5923e1b5015SHenrik Rydberg static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
5935519cab4SBenjamin Tissoires {
594eec29e3dSBenjamin Tissoires 	__s32 quirks = td->mtclass.quirks;
5955519cab4SBenjamin Tissoires 
5962d93666eSBenjamin Tissoires 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
5972d93666eSBenjamin Tissoires 		return td->curdata.contactid;
5985519cab4SBenjamin Tissoires 
5992d93666eSBenjamin Tissoires 	if (quirks & MT_QUIRK_CYPRESS)
600a3b5e577SBenjamin Tissoires 		return cypress_compute_slot(td);
601a3b5e577SBenjamin Tissoires 
6022d93666eSBenjamin Tissoires 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
6032d93666eSBenjamin Tissoires 		return td->num_received;
6045572da08SBenjamin Tissoires 
6054a6ee685SBenjamin Tissoires 	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
6064a6ee685SBenjamin Tissoires 		return td->curdata.contactid - 1;
6074a6ee685SBenjamin Tissoires 
6083e1b5015SHenrik Rydberg 	return input_mt_get_slot_by_key(input, td->curdata.contactid);
6095519cab4SBenjamin Tissoires }
6105519cab4SBenjamin Tissoires 
6115519cab4SBenjamin Tissoires /*
6125519cab4SBenjamin Tissoires  * this function is called when a whole contact has been processed,
6135519cab4SBenjamin Tissoires  * so that it can assign it to a slot and store the data there
6145519cab4SBenjamin Tissoires  */
6153e1b5015SHenrik Rydberg static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
6165519cab4SBenjamin Tissoires {
617c2517f62SBenjamin Tissoires 	if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
618c2517f62SBenjamin Tissoires 	    td->num_received >= td->num_expected)
619c2517f62SBenjamin Tissoires 		return;
620c2517f62SBenjamin Tissoires 
62120b60e6dSBenjamin Tissoires 	if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
6223e1b5015SHenrik Rydberg 		int slotnum = mt_compute_slot(td, input);
6233e1b5015SHenrik Rydberg 		struct mt_slot *s = &td->curdata;
62428728399SBenjamin Tissoires 		struct input_mt *mt = input->mt;
6255519cab4SBenjamin Tissoires 
6263e1b5015SHenrik Rydberg 		if (slotnum < 0 || slotnum >= td->maxcontacts)
6273e1b5015SHenrik Rydberg 			return;
6285519cab4SBenjamin Tissoires 
62928728399SBenjamin Tissoires 		if ((td->mtclass.quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
63028728399SBenjamin Tissoires 			struct input_mt_slot *slot = &mt->slots[slotnum];
63128728399SBenjamin Tissoires 			if (input_mt_is_active(slot) &&
63228728399SBenjamin Tissoires 			    input_mt_is_used(mt, slot))
63328728399SBenjamin Tissoires 				return;
63428728399SBenjamin Tissoires 		}
63528728399SBenjamin Tissoires 
6363e1b5015SHenrik Rydberg 		input_mt_slot(input, slotnum);
6375519cab4SBenjamin Tissoires 		input_mt_report_slot_state(input, MT_TOOL_FINGER,
6389b3bb9b8SBenjamin Tissoires 			s->touch_state || s->inrange_state);
6399b3bb9b8SBenjamin Tissoires 		if (s->touch_state || s->inrange_state) {
6409b3bb9b8SBenjamin Tissoires 			/* this finger is in proximity of the sensor */
641f786bba4SBenjamin Tissoires 			int wide = (s->w > s->h);
642f786bba4SBenjamin Tissoires 			/* divided by two to match visual scale of touch */
643f786bba4SBenjamin Tissoires 			int major = max(s->w, s->h) >> 1;
644f786bba4SBenjamin Tissoires 			int minor = min(s->w, s->h) >> 1;
645f786bba4SBenjamin Tissoires 
6465519cab4SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
6475519cab4SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
648349fd670SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx);
649349fd670SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
6509b3bb9b8SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_DISTANCE,
6519b3bb9b8SBenjamin Tissoires 				!s->touch_state);
652f786bba4SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
6535519cab4SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
654f786bba4SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
655f786bba4SBenjamin Tissoires 			input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
6562d93666eSBenjamin Tissoires 		}
6575519cab4SBenjamin Tissoires 	}
6585519cab4SBenjamin Tissoires 
6593e1b5015SHenrik Rydberg 	td->num_received++;
6603e1b5015SHenrik Rydberg }
6613e1b5015SHenrik Rydberg 
6623e1b5015SHenrik Rydberg /*
6633e1b5015SHenrik Rydberg  * this function is called when a whole packet has been received and processed,
6643e1b5015SHenrik Rydberg  * so that it can decide what to send to the input layer.
6653e1b5015SHenrik Rydberg  */
6663e1b5015SHenrik Rydberg static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
6673e1b5015SHenrik Rydberg {
66876f5902aSHenrik Rydberg 	input_mt_sync_frame(input);
6695519cab4SBenjamin Tissoires 	input_sync(input);
6705519cab4SBenjamin Tissoires 	td->num_received = 0;
6715519cab4SBenjamin Tissoires }
6725519cab4SBenjamin Tissoires 
673a69c5f8bSBenjamin Tissoires static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
6745519cab4SBenjamin Tissoires 				struct hid_usage *usage, __s32 value)
6755519cab4SBenjamin Tissoires {
67655978fa9SBenjamin Tissoires 	/* we will handle the hidinput part later, now remains hiddev */
67755978fa9SBenjamin Tissoires 	if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
67855978fa9SBenjamin Tissoires 		hid->hiddev_hid_event(hid, field, usage, value);
67955978fa9SBenjamin Tissoires 
68055978fa9SBenjamin Tissoires 	return 1;
68155978fa9SBenjamin Tissoires }
68255978fa9SBenjamin Tissoires 
68355978fa9SBenjamin Tissoires static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
68455978fa9SBenjamin Tissoires 				struct hid_usage *usage, __s32 value)
68555978fa9SBenjamin Tissoires {
6865519cab4SBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hid);
687eec29e3dSBenjamin Tissoires 	__s32 quirks = td->mtclass.quirks;
6884c437555SBenjamin Tissoires 	struct input_dev *input = field->hidinput->input;
6895519cab4SBenjamin Tissoires 
6903e1b5015SHenrik Rydberg 	if (hid->claimed & HID_CLAIMED_INPUT) {
6915519cab4SBenjamin Tissoires 		switch (usage->hid) {
6925519cab4SBenjamin Tissoires 		case HID_DG_INRANGE:
69320b60e6dSBenjamin Tissoires 			if (quirks & MT_QUIRK_VALID_IS_INRANGE)
6942d93666eSBenjamin Tissoires 				td->curvalid = value;
6959b3bb9b8SBenjamin Tissoires 			if (quirks & MT_QUIRK_HOVERING)
6969b3bb9b8SBenjamin Tissoires 				td->curdata.inrange_state = value;
6975519cab4SBenjamin Tissoires 			break;
6985519cab4SBenjamin Tissoires 		case HID_DG_TIPSWITCH:
6992d93666eSBenjamin Tissoires 			if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
7005519cab4SBenjamin Tissoires 				td->curvalid = value;
7015519cab4SBenjamin Tissoires 			td->curdata.touch_state = value;
7025519cab4SBenjamin Tissoires 			break;
7035519cab4SBenjamin Tissoires 		case HID_DG_CONFIDENCE:
7042d93666eSBenjamin Tissoires 			if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
7052d93666eSBenjamin Tissoires 				td->curvalid = value;
7065519cab4SBenjamin Tissoires 			break;
7075519cab4SBenjamin Tissoires 		case HID_DG_CONTACTID:
7085519cab4SBenjamin Tissoires 			td->curdata.contactid = value;
7095519cab4SBenjamin Tissoires 			break;
7105519cab4SBenjamin Tissoires 		case HID_DG_TIPPRESSURE:
7115519cab4SBenjamin Tissoires 			td->curdata.p = value;
7125519cab4SBenjamin Tissoires 			break;
7135519cab4SBenjamin Tissoires 		case HID_GD_X:
714349fd670SBenjamin Tissoires 			if (usage->code == ABS_MT_TOOL_X)
715349fd670SBenjamin Tissoires 				td->curdata.cx = value;
716349fd670SBenjamin Tissoires 			else
7175519cab4SBenjamin Tissoires 				td->curdata.x = value;
7185519cab4SBenjamin Tissoires 			break;
7195519cab4SBenjamin Tissoires 		case HID_GD_Y:
720349fd670SBenjamin Tissoires 			if (usage->code == ABS_MT_TOOL_Y)
721349fd670SBenjamin Tissoires 				td->curdata.cy = value;
722349fd670SBenjamin Tissoires 			else
7235519cab4SBenjamin Tissoires 				td->curdata.y = value;
7245519cab4SBenjamin Tissoires 			break;
7255519cab4SBenjamin Tissoires 		case HID_DG_WIDTH:
7265519cab4SBenjamin Tissoires 			td->curdata.w = value;
7275519cab4SBenjamin Tissoires 			break;
7285519cab4SBenjamin Tissoires 		case HID_DG_HEIGHT:
7295519cab4SBenjamin Tissoires 			td->curdata.h = value;
7305519cab4SBenjamin Tissoires 			break;
7315519cab4SBenjamin Tissoires 		case HID_DG_CONTACTCOUNT:
7325519cab4SBenjamin Tissoires 			break;
733c2ef8f21SBenjamin Tissoires 		case HID_DG_TOUCH:
734c2ef8f21SBenjamin Tissoires 			/* do nothing */
735c2ef8f21SBenjamin Tissoires 			break;
7365519cab4SBenjamin Tissoires 
7375519cab4SBenjamin Tissoires 		default:
7384c437555SBenjamin Tissoires 			if (usage->type)
7394c437555SBenjamin Tissoires 				input_event(input, usage->type, usage->code,
7404c437555SBenjamin Tissoires 						value);
74155978fa9SBenjamin Tissoires 			return;
7425519cab4SBenjamin Tissoires 		}
7435519cab4SBenjamin Tissoires 
74454f4c0c3SBenjamin Tissoires 		if (usage->usage_index + 1 == field->report_count) {
74554f4c0c3SBenjamin Tissoires 			/* we only take into account the last report. */
7462258e863SDenis Kovalev 			if (usage->hid == td->last_slot_field)
7473e1b5015SHenrik Rydberg 				mt_complete_slot(td, field->hidinput->input);
74854f4c0c3SBenjamin Tissoires 		}
7495519cab4SBenjamin Tissoires 
7502d93666eSBenjamin Tissoires 	}
75155978fa9SBenjamin Tissoires }
7522d93666eSBenjamin Tissoires 
753a69c5f8bSBenjamin Tissoires static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
75455978fa9SBenjamin Tissoires {
75555978fa9SBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hid);
75655978fa9SBenjamin Tissoires 	struct hid_field *field;
75755978fa9SBenjamin Tissoires 	unsigned count;
75855978fa9SBenjamin Tissoires 	int r, n;
7595519cab4SBenjamin Tissoires 
760c2517f62SBenjamin Tissoires 	/*
761c2517f62SBenjamin Tissoires 	 * Includes multi-packet support where subsequent
762c2517f62SBenjamin Tissoires 	 * packets are sent with zero contactcount.
763c2517f62SBenjamin Tissoires 	 */
7647e3cc447SBenjamin Tissoires 	if (td->cc_index >= 0) {
7657e3cc447SBenjamin Tissoires 		struct hid_field *field = report->field[td->cc_index];
7667e3cc447SBenjamin Tissoires 		int value = field->value[td->cc_value_index];
7677e3cc447SBenjamin Tissoires 		if (value)
7687e3cc447SBenjamin Tissoires 			td->num_expected = value;
7697e3cc447SBenjamin Tissoires 	}
770c2517f62SBenjamin Tissoires 
77155978fa9SBenjamin Tissoires 	for (r = 0; r < report->maxfield; r++) {
77255978fa9SBenjamin Tissoires 		field = report->field[r];
77355978fa9SBenjamin Tissoires 		count = field->report_count;
77455978fa9SBenjamin Tissoires 
77555978fa9SBenjamin Tissoires 		if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
77655978fa9SBenjamin Tissoires 			continue;
77755978fa9SBenjamin Tissoires 
77855978fa9SBenjamin Tissoires 		for (n = 0; n < count; n++)
77955978fa9SBenjamin Tissoires 			mt_process_mt_event(hid, field, &field->usage[n],
78055978fa9SBenjamin Tissoires 					field->value[n]);
78155978fa9SBenjamin Tissoires 	}
7825b62efd8SBenjamin Tissoires 
7835b62efd8SBenjamin Tissoires 	if (td->num_received >= td->num_expected)
7845b62efd8SBenjamin Tissoires 		mt_sync_frame(td, report->field[0]->hidinput->input);
7855519cab4SBenjamin Tissoires }
7865519cab4SBenjamin Tissoires 
787b2c68a2fSDmitry Torokhov static int mt_touch_input_configured(struct hid_device *hdev,
788a69c5f8bSBenjamin Tissoires 					struct hid_input *hi)
789a69c5f8bSBenjamin Tissoires {
790a69c5f8bSBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
791a69c5f8bSBenjamin Tissoires 	struct mt_class *cls = &td->mtclass;
792a69c5f8bSBenjamin Tissoires 	struct input_dev *input = hi->input;
793b2c68a2fSDmitry Torokhov 	int ret;
794a69c5f8bSBenjamin Tissoires 
795a69c5f8bSBenjamin Tissoires 	if (!td->maxcontacts)
796a69c5f8bSBenjamin Tissoires 		td->maxcontacts = MT_DEFAULT_MAXCONTACT;
797a69c5f8bSBenjamin Tissoires 
798a69c5f8bSBenjamin Tissoires 	mt_post_parse(td);
799a69c5f8bSBenjamin Tissoires 	if (td->serial_maybe)
800a69c5f8bSBenjamin Tissoires 		mt_post_parse_default_settings(td);
801a69c5f8bSBenjamin Tissoires 
802a69c5f8bSBenjamin Tissoires 	if (cls->is_indirect)
803a69c5f8bSBenjamin Tissoires 		td->mt_flags |= INPUT_MT_POINTER;
804a69c5f8bSBenjamin Tissoires 
805a69c5f8bSBenjamin Tissoires 	if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
806a69c5f8bSBenjamin Tissoires 		td->mt_flags |= INPUT_MT_DROP_UNUSED;
807a69c5f8bSBenjamin Tissoires 
808015fdaa9SBenjamin Tissoires 	/* check for clickpads */
809015fdaa9SBenjamin Tissoires 	if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1))
8102c6e0277SSeth Forshee 		td->is_buttonpad = true;
8112c6e0277SSeth Forshee 
8122c6e0277SSeth Forshee 	if (td->is_buttonpad)
813015fdaa9SBenjamin Tissoires 		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
814015fdaa9SBenjamin Tissoires 
815b2c68a2fSDmitry Torokhov 	ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
816b2c68a2fSDmitry Torokhov 	if (ret)
817b2c68a2fSDmitry Torokhov 		return ret;
818a69c5f8bSBenjamin Tissoires 
819a69c5f8bSBenjamin Tissoires 	td->mt_flags = 0;
820b2c68a2fSDmitry Torokhov 	return 0;
821a69c5f8bSBenjamin Tissoires }
822a69c5f8bSBenjamin Tissoires 
823a69c5f8bSBenjamin Tissoires static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
824a69c5f8bSBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage,
825a69c5f8bSBenjamin Tissoires 		unsigned long **bit, int *max)
826a69c5f8bSBenjamin Tissoires {
8276aef704eSBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
8286aef704eSBenjamin Tissoires 
8296aef704eSBenjamin Tissoires 	/*
8306aef704eSBenjamin Tissoires 	 * If mtclass.export_all_inputs is not set, only map fields from
8316aef704eSBenjamin Tissoires 	 * TouchScreen or TouchPad collections. We need to ignore fields
8326aef704eSBenjamin Tissoires 	 * that belong to other collections such as Mouse that might have
8336aef704eSBenjamin Tissoires 	 * the same GenericDesktop usages.
8346aef704eSBenjamin Tissoires 	 */
8356aef704eSBenjamin Tissoires 	if (!td->mtclass.export_all_inputs &&
8366aef704eSBenjamin Tissoires 	    field->application != HID_DG_TOUCHSCREEN &&
837fa11aa72SBenjamin Tissoires 	    field->application != HID_DG_PEN &&
838a69c5f8bSBenjamin Tissoires 	    field->application != HID_DG_TOUCHPAD)
8396f492f28SBenjamin Tissoires 		return -1;
840a69c5f8bSBenjamin Tissoires 
8416aef704eSBenjamin Tissoires 	/*
8426aef704eSBenjamin Tissoires 	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
8436aef704eSBenjamin Tissoires 	 * for the stylus.
8441cc1cc92SBrent Adam 	 * The check for mt_report_id ensures we don't process
8451cc1cc92SBrent Adam 	 * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical
8461cc1cc92SBrent Adam 	 * collection, but within the report ID.
8476aef704eSBenjamin Tissoires 	 */
848a69c5f8bSBenjamin Tissoires 	if (field->physical == HID_DG_STYLUS)
849e55f6200SBenjamin Tissoires 		return 0;
8501cc1cc92SBrent Adam 	else if ((field->physical == 0) &&
8511cc1cc92SBrent Adam 		 (field->report->id != td->mt_report_id) &&
8521cc1cc92SBrent Adam 		 (td->mt_report_id != -1))
8531cc1cc92SBrent Adam 		return 0;
854a69c5f8bSBenjamin Tissoires 
8556aef704eSBenjamin Tissoires 	if (field->application == HID_DG_TOUCHSCREEN ||
8566aef704eSBenjamin Tissoires 	    field->application == HID_DG_TOUCHPAD)
857a69c5f8bSBenjamin Tissoires 		return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
8586aef704eSBenjamin Tissoires 
8596aef704eSBenjamin Tissoires 	/* let hid-core decide for the others */
8606aef704eSBenjamin Tissoires 	return 0;
861a69c5f8bSBenjamin Tissoires }
862a69c5f8bSBenjamin Tissoires 
863a69c5f8bSBenjamin Tissoires static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
864a69c5f8bSBenjamin Tissoires 		struct hid_field *field, struct hid_usage *usage,
865a69c5f8bSBenjamin Tissoires 		unsigned long **bit, int *max)
866a69c5f8bSBenjamin Tissoires {
8676aef704eSBenjamin Tissoires 	/*
8686aef704eSBenjamin Tissoires 	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
8696aef704eSBenjamin Tissoires 	 * for the stylus.
8706aef704eSBenjamin Tissoires 	 */
871fa11aa72SBenjamin Tissoires 	if (field->physical == HID_DG_STYLUS)
872e55f6200SBenjamin Tissoires 		return 0;
873fa11aa72SBenjamin Tissoires 
8746aef704eSBenjamin Tissoires 	if (field->application == HID_DG_TOUCHSCREEN ||
8756aef704eSBenjamin Tissoires 	    field->application == HID_DG_TOUCHPAD)
876a69c5f8bSBenjamin Tissoires 		return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
8776aef704eSBenjamin Tissoires 
8786aef704eSBenjamin Tissoires 	/* let hid-core decide for the others */
8796aef704eSBenjamin Tissoires 	return 0;
880a69c5f8bSBenjamin Tissoires }
881a69c5f8bSBenjamin Tissoires 
882a69c5f8bSBenjamin Tissoires static int mt_event(struct hid_device *hid, struct hid_field *field,
883a69c5f8bSBenjamin Tissoires 				struct hid_usage *usage, __s32 value)
884a69c5f8bSBenjamin Tissoires {
885a69c5f8bSBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hid);
886a69c5f8bSBenjamin Tissoires 
887a69c5f8bSBenjamin Tissoires 	if (field->report->id == td->mt_report_id)
888a69c5f8bSBenjamin Tissoires 		return mt_touch_event(hid, field, usage, value);
889a69c5f8bSBenjamin Tissoires 
890e55f6200SBenjamin Tissoires 	return 0;
891a69c5f8bSBenjamin Tissoires }
892a69c5f8bSBenjamin Tissoires 
893a69c5f8bSBenjamin Tissoires static void mt_report(struct hid_device *hid, struct hid_report *report)
894a69c5f8bSBenjamin Tissoires {
895a69c5f8bSBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hid);
896e55f6200SBenjamin Tissoires 	struct hid_field *field = report->field[0];
897a69c5f8bSBenjamin Tissoires 
898a69c5f8bSBenjamin Tissoires 	if (!(hid->claimed & HID_CLAIMED_INPUT))
899a69c5f8bSBenjamin Tissoires 		return;
900a69c5f8bSBenjamin Tissoires 
901a69c5f8bSBenjamin Tissoires 	if (report->id == td->mt_report_id)
902e55f6200SBenjamin Tissoires 		return mt_touch_report(hid, report);
903fa11aa72SBenjamin Tissoires 
904e55f6200SBenjamin Tissoires 	if (field && field->hidinput && field->hidinput->input)
905e55f6200SBenjamin Tissoires 		input_sync(field->hidinput->input);
9065519cab4SBenjamin Tissoires }
9075519cab4SBenjamin Tissoires 
9085519cab4SBenjamin Tissoires static void mt_set_input_mode(struct hid_device *hdev)
9095519cab4SBenjamin Tissoires {
9105519cab4SBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
9115519cab4SBenjamin Tissoires 	struct hid_report *r;
9125519cab4SBenjamin Tissoires 	struct hid_report_enum *re;
913da10bc25SMathieu Magnaudet 	struct mt_class *cls = &td->mtclass;
914da10bc25SMathieu Magnaudet 	char *buf;
915da10bc25SMathieu Magnaudet 	int report_len;
9165519cab4SBenjamin Tissoires 
9175519cab4SBenjamin Tissoires 	if (td->inputmode < 0)
9185519cab4SBenjamin Tissoires 		return;
9195519cab4SBenjamin Tissoires 
9205519cab4SBenjamin Tissoires 	re = &(hdev->report_enum[HID_FEATURE_REPORT]);
9215519cab4SBenjamin Tissoires 	r = re->report_id_hash[td->inputmode];
9225519cab4SBenjamin Tissoires 	if (r) {
923da10bc25SMathieu Magnaudet 		if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) {
924dabb05c6SMathieu Magnaudet 			report_len = hid_report_len(r);
925da10bc25SMathieu Magnaudet 			buf = hid_alloc_report_buf(r, GFP_KERNEL);
926da10bc25SMathieu Magnaudet 			if (!buf) {
927da10bc25SMathieu Magnaudet 				hid_err(hdev, "failed to allocate buffer for report\n");
928da10bc25SMathieu Magnaudet 				return;
929da10bc25SMathieu Magnaudet 			}
930da10bc25SMathieu Magnaudet 			hid_hw_raw_request(hdev, r->id, buf, report_len,
931da10bc25SMathieu Magnaudet 					   HID_FEATURE_REPORT,
932da10bc25SMathieu Magnaudet 					   HID_REQ_GET_REPORT);
933da10bc25SMathieu Magnaudet 			kfree(buf);
934da10bc25SMathieu Magnaudet 		}
9359abebedbSAndrew Duggan 		r->field[0]->value[td->inputmode_index] = td->inputmode_value;
936d8814272SBenjamin Tissoires 		hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
9375519cab4SBenjamin Tissoires 	}
9385519cab4SBenjamin Tissoires }
9395519cab4SBenjamin Tissoires 
94031ae9bddSBenjamin Tissoires static void mt_set_maxcontacts(struct hid_device *hdev)
94131ae9bddSBenjamin Tissoires {
94231ae9bddSBenjamin Tissoires 	struct mt_device *td = hid_get_drvdata(hdev);
94331ae9bddSBenjamin Tissoires 	struct hid_report *r;
94431ae9bddSBenjamin Tissoires 	struct hid_report_enum *re;
94531ae9bddSBenjamin Tissoires 	int fieldmax, max;
94631ae9bddSBenjamin Tissoires 
94731ae9bddSBenjamin Tissoires 	if (td->maxcontact_report_id < 0)
94831ae9bddSBenjamin Tissoires 		return;
94931ae9bddSBenjamin Tissoires 
95031ae9bddSBenjamin Tissoires 	if (!td->mtclass.maxcontacts)
95131ae9bddSBenjamin Tissoires 		return;
95231ae9bddSBenjamin Tissoires 
95331ae9bddSBenjamin Tissoires 	re = &hdev->report_enum[HID_FEATURE_REPORT];
95431ae9bddSBenjamin Tissoires 	r = re->report_id_hash[td->maxcontact_report_id];
95531ae9bddSBenjamin Tissoires 	if (r) {
95631ae9bddSBenjamin Tissoires 		max = td->mtclass.maxcontacts;
95731ae9bddSBenjamin Tissoires 		fieldmax = r->field[0]->logical_maximum;
95831ae9bddSBenjamin Tissoires 		max = min(fieldmax, max);
95931ae9bddSBenjamin Tissoires 		if (r->field[0]->value[0] != max) {
96031ae9bddSBenjamin Tissoires 			r->field[0]->value[0] = max;
961d8814272SBenjamin Tissoires 			hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
96231ae9bddSBenjamin Tissoires 		}
96331ae9bddSBenjamin Tissoires 	}
96431ae9bddSBenjamin Tissoires }
96531ae9bddSBenjamin Tissoires 
9664fa3a583SHenrik Rydberg static void mt_post_parse_default_settings(struct mt_device *td)
9674fa3a583SHenrik Rydberg {
9684fa3a583SHenrik Rydberg 	__s32 quirks = td->mtclass.quirks;
9694fa3a583SHenrik Rydberg 
9704fa3a583SHenrik Rydberg 	/* unknown serial device needs special quirks */
9714fa3a583SHenrik Rydberg 	if (td->touches_by_report == 1) {
9724fa3a583SHenrik Rydberg 		quirks |= MT_QUIRK_ALWAYS_VALID;
9734fa3a583SHenrik Rydberg 		quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
9744fa3a583SHenrik Rydberg 		quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
9754fa3a583SHenrik Rydberg 		quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
976e0bb8f9aSBenjamin Tissoires 		quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
9774fa3a583SHenrik Rydberg 	}
9784fa3a583SHenrik Rydberg 
9794fa3a583SHenrik Rydberg 	td->mtclass.quirks = quirks;
9804fa3a583SHenrik Rydberg }
9814fa3a583SHenrik Rydberg 
9823ac36d15SBenjamin Tissoires static void mt_post_parse(struct mt_device *td)
9833ac36d15SBenjamin Tissoires {
9843ac36d15SBenjamin Tissoires 	struct mt_fields *f = td->fields;
985c2517f62SBenjamin Tissoires 	struct mt_class *cls = &td->mtclass;
9863ac36d15SBenjamin Tissoires 
9873ac36d15SBenjamin Tissoires 	if (td->touches_by_report > 0) {
9883ac36d15SBenjamin Tissoires 		int field_count_per_touch = f->length / td->touches_by_report;
9893ac36d15SBenjamin Tissoires 		td->last_slot_field = f->usages[field_count_per_touch - 1];
9903ac36d15SBenjamin Tissoires 	}
991c2517f62SBenjamin Tissoires 
9927e3cc447SBenjamin Tissoires 	if (td->cc_index < 0)
993c2517f62SBenjamin Tissoires 		cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
9943ac36d15SBenjamin Tissoires }
9953ac36d15SBenjamin Tissoires 
996b2c68a2fSDmitry Torokhov static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
99776f5902aSHenrik Rydberg {
99876f5902aSHenrik Rydberg 	struct mt_device *td = hid_get_drvdata(hdev);
999c08d46aaSBenjamin Tissoires 	char *name;
1000c08d46aaSBenjamin Tissoires 	const char *suffix = NULL;
10016aef704eSBenjamin Tissoires 	struct hid_field *field = hi->report->field[0];
1002b2c68a2fSDmitry Torokhov 	int ret;
100376f5902aSHenrik Rydberg 
1004b2c68a2fSDmitry Torokhov 	if (hi->report->id == td->mt_report_id) {
1005b2c68a2fSDmitry Torokhov 		ret = mt_touch_input_configured(hdev, hi);
1006b2c68a2fSDmitry Torokhov 		if (ret)
1007b2c68a2fSDmitry Torokhov 			return ret;
1008b2c68a2fSDmitry Torokhov 	}
100976f5902aSHenrik Rydberg 
10106aef704eSBenjamin Tissoires 	/*
10116aef704eSBenjamin Tissoires 	 * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
10126aef704eSBenjamin Tissoires 	 * for the stylus. Check this first, and then rely on the application
10136aef704eSBenjamin Tissoires 	 * field.
10146aef704eSBenjamin Tissoires 	 */
1015c08d46aaSBenjamin Tissoires 	if (hi->report->field[0]->physical == HID_DG_STYLUS) {
1016c08d46aaSBenjamin Tissoires 		suffix = "Pen";
1017e55f6200SBenjamin Tissoires 		/* force BTN_STYLUS to allow tablet matching in udev */
1018e55f6200SBenjamin Tissoires 		__set_bit(BTN_STYLUS, hi->input->keybit);
10196aef704eSBenjamin Tissoires 	} else {
10206aef704eSBenjamin Tissoires 		switch (field->application) {
10216aef704eSBenjamin Tissoires 		case HID_GD_KEYBOARD:
10226aef704eSBenjamin Tissoires 			suffix = "Keyboard";
10236aef704eSBenjamin Tissoires 			break;
10246aef704eSBenjamin Tissoires 		case HID_GD_KEYPAD:
10256aef704eSBenjamin Tissoires 			suffix = "Keypad";
10266aef704eSBenjamin Tissoires 			break;
10276aef704eSBenjamin Tissoires 		case HID_GD_MOUSE:
10286aef704eSBenjamin Tissoires 			suffix = "Mouse";
10296aef704eSBenjamin Tissoires 			break;
10306aef704eSBenjamin Tissoires 		case HID_DG_STYLUS:
10316aef704eSBenjamin Tissoires 			suffix = "Pen";
10326aef704eSBenjamin Tissoires 			/* force BTN_STYLUS to allow tablet matching in udev */
10336aef704eSBenjamin Tissoires 			__set_bit(BTN_STYLUS, hi->input->keybit);
10346aef704eSBenjamin Tissoires 			break;
10356aef704eSBenjamin Tissoires 		case HID_DG_TOUCHSCREEN:
10366aef704eSBenjamin Tissoires 			/* we do not set suffix = "Touchscreen" */
10376aef704eSBenjamin Tissoires 			break;
1038dc425a1cSMika Westerberg 		case HID_DG_TOUCHPAD:
1039dc425a1cSMika Westerberg 			suffix = "Touchpad";
1040dc425a1cSMika Westerberg 			break;
10416aef704eSBenjamin Tissoires 		case HID_GD_SYSTEM_CONTROL:
10426aef704eSBenjamin Tissoires 			suffix = "System Control";
10436aef704eSBenjamin Tissoires 			break;
10446aef704eSBenjamin Tissoires 		case HID_CP_CONSUMER_CONTROL:
10456aef704eSBenjamin Tissoires 			suffix = "Consumer Control";
10466aef704eSBenjamin Tissoires 			break;
10476aef704eSBenjamin Tissoires 		default:
10486aef704eSBenjamin Tissoires 			suffix = "UNKNOWN";
10496aef704eSBenjamin Tissoires 			break;
10506aef704eSBenjamin Tissoires 		}
105176f5902aSHenrik Rydberg 	}
105276f5902aSHenrik Rydberg 
1053c08d46aaSBenjamin Tissoires 	if (suffix) {
1054c08d46aaSBenjamin Tissoires 		name = devm_kzalloc(&hi->input->dev,
1055c08d46aaSBenjamin Tissoires 				    strlen(hdev->name) + strlen(suffix) + 2,
1056c08d46aaSBenjamin Tissoires 				    GFP_KERNEL);
1057c08d46aaSBenjamin Tissoires 		if (name) {
1058c08d46aaSBenjamin Tissoires 			sprintf(name, "%s %s", hdev->name, suffix);
1059c08d46aaSBenjamin Tissoires 			hi->input->name = name;
1060c08d46aaSBenjamin Tissoires 		}
1061c08d46aaSBenjamin Tissoires 	}
1062b2c68a2fSDmitry Torokhov 
1063b2c68a2fSDmitry Torokhov 	return 0;
1064c08d46aaSBenjamin Tissoires }
1065c08d46aaSBenjamin Tissoires 
10665519cab4SBenjamin Tissoires static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
10675519cab4SBenjamin Tissoires {
10682d93666eSBenjamin Tissoires 	int ret, i;
10695519cab4SBenjamin Tissoires 	struct mt_device *td;
10702d93666eSBenjamin Tissoires 	struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
10712d93666eSBenjamin Tissoires 
10722d93666eSBenjamin Tissoires 	for (i = 0; mt_classes[i].name ; i++) {
10732d93666eSBenjamin Tissoires 		if (id->driver_data == mt_classes[i].name) {
10742d93666eSBenjamin Tissoires 			mtclass = &(mt_classes[i]);
10752d93666eSBenjamin Tissoires 			break;
10762d93666eSBenjamin Tissoires 		}
10772d93666eSBenjamin Tissoires 	}
10785519cab4SBenjamin Tissoires 
1079d682bd7fSHenrik Rydberg 	/* This allows the driver to correctly support devices
1080d682bd7fSHenrik Rydberg 	 * that emit events over several HID messages.
1081d682bd7fSHenrik Rydberg 	 */
1082d682bd7fSHenrik Rydberg 	hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
10835519cab4SBenjamin Tissoires 
1084fa11aa72SBenjamin Tissoires 	/*
1085fa11aa72SBenjamin Tissoires 	 * This allows the driver to handle different input sensors
1086fa11aa72SBenjamin Tissoires 	 * that emits events through different reports on the same HID
1087fa11aa72SBenjamin Tissoires 	 * device.
1088fa11aa72SBenjamin Tissoires 	 */
1089fa11aa72SBenjamin Tissoires 	hdev->quirks |= HID_QUIRK_MULTI_INPUT;
1090fa11aa72SBenjamin Tissoires 	hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
1091fa11aa72SBenjamin Tissoires 
1092595e9276SBenjamin Tissoires 	/*
1093595e9276SBenjamin Tissoires 	 * Handle special quirks for Windows 8 certified devices.
1094595e9276SBenjamin Tissoires 	 */
1095595e9276SBenjamin Tissoires 	if (id->group == HID_GROUP_MULTITOUCH_WIN_8)
1096595e9276SBenjamin Tissoires 		/*
1097595e9276SBenjamin Tissoires 		 * Some multitouch screens do not like to be polled for input
1098595e9276SBenjamin Tissoires 		 * reports. Fortunately, the Win8 spec says that all touches
1099595e9276SBenjamin Tissoires 		 * should be sent during each report, making the initialization
1100595e9276SBenjamin Tissoires 		 * of input reports unnecessary.
11016d4f5440SMika Westerberg 		 *
11026d4f5440SMika Westerberg 		 * In addition some touchpads do not behave well if we read
11036d4f5440SMika Westerberg 		 * all feature reports from them. Instead we prevent
11046d4f5440SMika Westerberg 		 * initial report fetching and then selectively fetch each
11056d4f5440SMika Westerberg 		 * report we are interested in.
1106595e9276SBenjamin Tissoires 		 */
11076d4f5440SMika Westerberg 		hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
1108595e9276SBenjamin Tissoires 
1109c08d46aaSBenjamin Tissoires 	td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
11105519cab4SBenjamin Tissoires 	if (!td) {
11115519cab4SBenjamin Tissoires 		dev_err(&hdev->dev, "cannot allocate multitouch data\n");
11125519cab4SBenjamin Tissoires 		return -ENOMEM;
11135519cab4SBenjamin Tissoires 	}
1114eec29e3dSBenjamin Tissoires 	td->mtclass = *mtclass;
11155519cab4SBenjamin Tissoires 	td->inputmode = -1;
111631ae9bddSBenjamin Tissoires 	td->maxcontact_report_id = -1;
11179abebedbSAndrew Duggan 	td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
11187e3cc447SBenjamin Tissoires 	td->cc_index = -1;
1119fa11aa72SBenjamin Tissoires 	td->mt_report_id = -1;
11205519cab4SBenjamin Tissoires 	hid_set_drvdata(hdev, td);
11215519cab4SBenjamin Tissoires 
1122c08d46aaSBenjamin Tissoires 	td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
1123c08d46aaSBenjamin Tissoires 				  GFP_KERNEL);
11243ac36d15SBenjamin Tissoires 	if (!td->fields) {
11253ac36d15SBenjamin Tissoires 		dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
1126c08d46aaSBenjamin Tissoires 		return -ENOMEM;
11273ac36d15SBenjamin Tissoires 	}
11283ac36d15SBenjamin Tissoires 
112976f5902aSHenrik Rydberg 	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
113076f5902aSHenrik Rydberg 		td->serial_maybe = true;
113176f5902aSHenrik Rydberg 
11325519cab4SBenjamin Tissoires 	ret = hid_parse(hdev);
11335519cab4SBenjamin Tissoires 	if (ret != 0)
1134c08d46aaSBenjamin Tissoires 		return ret;
11355519cab4SBenjamin Tissoires 
11365519cab4SBenjamin Tissoires 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
11372d93666eSBenjamin Tissoires 	if (ret)
1138c08d46aaSBenjamin Tissoires 		return ret;
11395519cab4SBenjamin Tissoires 
1140eec29e3dSBenjamin Tissoires 	ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
11410c4b3c63SNicholas Krause 	if (ret)
11420c4b3c63SNicholas Krause 		dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n",
11430c4b3c63SNicholas Krause 				hdev->name);
1144eec29e3dSBenjamin Tissoires 
114531ae9bddSBenjamin Tissoires 	mt_set_maxcontacts(hdev);
11465519cab4SBenjamin Tissoires 	mt_set_input_mode(hdev);
11475519cab4SBenjamin Tissoires 
1148c08d46aaSBenjamin Tissoires 	/* release .fields memory as it is not used anymore */
1149c08d46aaSBenjamin Tissoires 	devm_kfree(&hdev->dev, td->fields);
11503ac36d15SBenjamin Tissoires 	td->fields = NULL;
11513ac36d15SBenjamin Tissoires 
11525519cab4SBenjamin Tissoires 	return 0;
11535519cab4SBenjamin Tissoires }
11545519cab4SBenjamin Tissoires 
11555519cab4SBenjamin Tissoires #ifdef CONFIG_PM
1156d3e69b9aSBenson Leung static void mt_release_contacts(struct hid_device *hid)
1157d3e69b9aSBenson Leung {
1158d3e69b9aSBenson Leung 	struct hid_input *hidinput;
1159d3e69b9aSBenson Leung 
1160d3e69b9aSBenson Leung 	list_for_each_entry(hidinput, &hid->inputs, list) {
1161d3e69b9aSBenson Leung 		struct input_dev *input_dev = hidinput->input;
1162d3e69b9aSBenson Leung 		struct input_mt *mt = input_dev->mt;
1163d3e69b9aSBenson Leung 		int i;
1164d3e69b9aSBenson Leung 
1165d3e69b9aSBenson Leung 		if (mt) {
1166d3e69b9aSBenson Leung 			for (i = 0; i < mt->num_slots; i++) {
1167d3e69b9aSBenson Leung 				input_mt_slot(input_dev, i);
1168d3e69b9aSBenson Leung 				input_mt_report_slot_state(input_dev,
1169d3e69b9aSBenson Leung 							   MT_TOOL_FINGER,
1170d3e69b9aSBenson Leung 							   false);
1171d3e69b9aSBenson Leung 			}
11720a0f5b7eSGabriele Mazzotta 			input_mt_sync_frame(input_dev);
1173d3e69b9aSBenson Leung 			input_sync(input_dev);
1174d3e69b9aSBenson Leung 		}
1175d3e69b9aSBenson Leung 	}
1176d3e69b9aSBenson Leung }
1177d3e69b9aSBenson Leung 
11785519cab4SBenjamin Tissoires static int mt_reset_resume(struct hid_device *hdev)
11795519cab4SBenjamin Tissoires {
1180d3e69b9aSBenson Leung 	mt_release_contacts(hdev);
118131ae9bddSBenjamin Tissoires 	mt_set_maxcontacts(hdev);
11825519cab4SBenjamin Tissoires 	mt_set_input_mode(hdev);
11835519cab4SBenjamin Tissoires 	return 0;
11845519cab4SBenjamin Tissoires }
1185dfeefd10SScott Liu 
1186dfeefd10SScott Liu static int mt_resume(struct hid_device *hdev)
1187dfeefd10SScott Liu {
1188dfeefd10SScott Liu 	/* Some Elan legacy devices require SET_IDLE to be set on resume.
1189dfeefd10SScott Liu 	 * It should be safe to send it to other devices too.
1190dfeefd10SScott Liu 	 * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
1191dfeefd10SScott Liu 
11924ba25d3fSBenjamin Tissoires 	hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE);
1193dfeefd10SScott Liu 
1194dfeefd10SScott Liu 	return 0;
1195dfeefd10SScott Liu }
11965519cab4SBenjamin Tissoires #endif
11975519cab4SBenjamin Tissoires 
11985519cab4SBenjamin Tissoires static void mt_remove(struct hid_device *hdev)
11995519cab4SBenjamin Tissoires {
1200eec29e3dSBenjamin Tissoires 	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
12015939212dSBenjamin Tissoires 	hid_hw_stop(hdev);
12025519cab4SBenjamin Tissoires }
12035519cab4SBenjamin Tissoires 
12040fa9c616SBenjamin Tissoires /*
12050fa9c616SBenjamin Tissoires  * This list contains only:
12060fa9c616SBenjamin Tissoires  * - VID/PID of products not working with the default multitouch handling
12070fa9c616SBenjamin Tissoires  * - 2 generic rules.
12080fa9c616SBenjamin Tissoires  * So there is no point in adding here any device with MT_CLS_DEFAULT.
12090fa9c616SBenjamin Tissoires  */
12105519cab4SBenjamin Tissoires static const struct hid_device_id mt_devices[] = {
12115519cab4SBenjamin Tissoires 
1212f786bba4SBenjamin Tissoires 	/* 3M panels */
1213f786bba4SBenjamin Tissoires 	{ .driver_data = MT_CLS_3M,
12142c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_3M,
1215f786bba4SBenjamin Tissoires 			USB_DEVICE_ID_3M1968) },
1216f786bba4SBenjamin Tissoires 	{ .driver_data = MT_CLS_3M,
12172c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_3M,
1218f786bba4SBenjamin Tissoires 			USB_DEVICE_ID_3M2256) },
1219c4fad877SBenjamin Tissoires 	{ .driver_data = MT_CLS_3M,
12202c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_3M,
1221c4fad877SBenjamin Tissoires 			USB_DEVICE_ID_3M3266) },
1222f786bba4SBenjamin Tissoires 
12236aef704eSBenjamin Tissoires 	/* Anton devices */
12246aef704eSBenjamin Tissoires 	{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
12256aef704eSBenjamin Tissoires 		MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
12266aef704eSBenjamin Tissoires 			USB_DEVICE_ID_ANTON_TOUCH_PAD) },
1227e6aac342SBenjamin Tissoires 
1228b1057124SBenjamin Tissoires 	/* Atmel panels */
1229b1057124SBenjamin Tissoires 	{ .driver_data = MT_CLS_SERIAL,
12302c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
1231841cb157SBenjamin Tissoires 			USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
1232b1057124SBenjamin Tissoires 
12339ed32695SJiri Kosina 	/* Baanto multitouch devices */
1234dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
123516b79bb8SJiri Kosina 		MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
12369ed32695SJiri Kosina 			USB_DEVICE_ID_BAANTO_MT_190W2) },
12370fa9c616SBenjamin Tissoires 
1238a841b62cSBenjamin Tissoires 	/* Cando panels */
1239a841b62cSBenjamin Tissoires 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
12402c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
1241a841b62cSBenjamin Tissoires 			USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
1242a841b62cSBenjamin Tissoires 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
12432c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
1244a841b62cSBenjamin Tissoires 			USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
1245a841b62cSBenjamin Tissoires 
1246942fd422SAustin Zhang 	/* Chunghwa Telecom touch panels */
1247dc3e1d80SBenjamin Tissoires 	{  .driver_data = MT_CLS_NSMU,
12482c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
1249942fd422SAustin Zhang 			USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
1250942fd422SAustin Zhang 
1251070f63b4SYang Bo 	/* CJTouch panels */
1252070f63b4SYang Bo 	{ .driver_data = MT_CLS_NSMU,
1253070f63b4SYang Bo 		MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
1254070f63b4SYang Bo 			USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) },
1255070f63b4SYang Bo 	{ .driver_data = MT_CLS_NSMU,
1256070f63b4SYang Bo 		MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
1257070f63b4SYang Bo 			USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) },
1258070f63b4SYang Bo 
125979603dc9SBenjamin Tissoires 	/* CVTouch panels */
1260dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
12612c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
126279603dc9SBenjamin Tissoires 			USB_DEVICE_ID_CVTOUCH_SCREEN) },
126379603dc9SBenjamin Tissoires 
126422408283SBenjamin Tissoires 	/* eGalax devices (resistive) */
126522408283SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX,
12662c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1267e36f690bSBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
126822408283SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX,
12692c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1270e36f690bSBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
127122408283SBenjamin Tissoires 
127222408283SBenjamin Tissoires 	/* eGalax devices (capacitive) */
1273fd1d1525SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
12742c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1275fd1d1525SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) },
127622408283SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX,
12772c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1278e36f690bSBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
1279fd1d1525SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
12802c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1281fd1d1525SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
12822ce09df4SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
12832c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
12842ce09df4SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) },
128522408283SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
12862c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
128722408283SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
1288fd1d1525SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
12892c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1290fd1d1525SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) },
129122408283SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX,
12922c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
129322408283SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
129422408283SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX,
129522408283SBenjamin Tissoires 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1296e36f690bSBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
1297fd1d1525SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
12982c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1299fd1d1525SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) },
13001fd8f047SChris Bagwell 	{ .driver_data = MT_CLS_EGALAX,
1301aa672da1SAndy Shevchenko 		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
1302aa672da1SAndy Shevchenko 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
1303aa672da1SAndy Shevchenko 	{ .driver_data = MT_CLS_EGALAX,
1304aa672da1SAndy Shevchenko 		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
1305aa672da1SAndy Shevchenko 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) },
1306aa672da1SAndy Shevchenko 	{ .driver_data = MT_CLS_EGALAX,
13072c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
130866f06127SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },
130966f06127SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX,
13102c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1311bb9ff210SMarek Vasut 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
13121b723e8dSBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
13132c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1314fd1d1525SBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
1315fd1d1525SBenjamin Tissoires 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
13162c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1317ae01c9e5SThierry Reding 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) },
1318ae01c9e5SThierry Reding 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
1319ae01c9e5SThierry Reding 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
1320e36f690bSBenjamin Tissoires 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
132122408283SBenjamin Tissoires 
13227c7606a2STomas Sokorai 	/* Elitegroup panel */
13237c7606a2STomas Sokorai 	{ .driver_data = MT_CLS_SERIAL,
13247c7606a2STomas Sokorai 		MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP,
13257c7606a2STomas Sokorai 			USB_DEVICE_ID_ELITEGROUP_05D8) },
13267c7606a2STomas Sokorai 
132777723e3bSHenrik Rydberg 	/* Flatfrog Panels */
132877723e3bSHenrik Rydberg 	{ .driver_data = MT_CLS_FLATFROG,
132977723e3bSHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
133077723e3bSHenrik Rydberg 			USB_DEVICE_ID_MULTITOUCH_3200) },
133177723e3bSHenrik Rydberg 
13323db187e7SBenjamin Tissoires 	/* FocalTech Panels */
13333db187e7SBenjamin Tissoires 	{ .driver_data = MT_CLS_SERIAL,
13343db187e7SBenjamin Tissoires 		MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL,
13353db187e7SBenjamin Tissoires 			USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) },
13363db187e7SBenjamin Tissoires 
13375572da08SBenjamin Tissoires 	/* GeneralTouch panel */
1338f5ff4e1eSXianhan Yu 	{ .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS,
13392c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
13405572da08SBenjamin Tissoires 			USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
1341f5ff4e1eSXianhan Yu 	{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
1342f5ff4e1eSXianhan Yu 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
1343f5ff4e1eSXianhan Yu 			USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) },
13447b226292SLuosong 	{ .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS,
13457b226292SLuosong 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
13467b226292SLuosong 			USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101) },
13477b226292SLuosong 	{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
13487b226292SLuosong 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
13497b226292SLuosong 			USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102) },
13507b226292SLuosong 	{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
13517b226292SLuosong 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
13527b226292SLuosong 			USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106) },
13537b226292SLuosong 	{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
13547b226292SLuosong 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
13557b226292SLuosong 			USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A) },
13567b226292SLuosong 	{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
13577b226292SLuosong 		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
13587b226292SLuosong 			USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100) },
13595572da08SBenjamin Tissoires 
13604d5df5d1SAndreas Nielsen 	/* Gametel game controller */
1361dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
13622c2110e9SHenrik Rydberg 		MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
13634d5df5d1SAndreas Nielsen 			USB_DEVICE_ID_GAMETEL_MT_MODE) },
13644d5df5d1SAndreas Nielsen 
1365ee0fbd14SBenjamin Tissoires 	/* GoodTouch panels */
1366dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
13672c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
1368ee0fbd14SBenjamin Tissoires 			USB_DEVICE_ID_GOODTOUCH_000f) },
1369ee0fbd14SBenjamin Tissoires 
137054580365SBenjamin Tissoires 	/* Hanvon panels */
137154580365SBenjamin Tissoires 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
13722c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
137354580365SBenjamin Tissoires 			USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
137454580365SBenjamin Tissoires 
13754e61f0d7SAustin Zhang 	/* Ilitek dual touch panel */
1376dc3e1d80SBenjamin Tissoires 	{  .driver_data = MT_CLS_NSMU,
13772c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
13784e61f0d7SAustin Zhang 			USB_DEVICE_ID_ILITEK_MULTITOUCH) },
13794e61f0d7SAustin Zhang 
13804a6ee685SBenjamin Tissoires 	/* MosArt panels */
13814a6ee685SBenjamin Tissoires 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
13822c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
13834a6ee685SBenjamin Tissoires 			USB_DEVICE_ID_ASUS_T91MT)},
13844a6ee685SBenjamin Tissoires 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
13852c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
13864a6ee685SBenjamin Tissoires 			USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
13874a6ee685SBenjamin Tissoires 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
13882c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
13894a6ee685SBenjamin Tissoires 			USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
13904a6ee685SBenjamin Tissoires 
13912258e863SDenis Kovalev 	/* Panasonic panels */
13922258e863SDenis Kovalev 	{ .driver_data = MT_CLS_PANASONIC,
13932c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
13942258e863SDenis Kovalev 			USB_DEVICE_ID_PANABOARD_UBT780) },
13952258e863SDenis Kovalev 	{ .driver_data = MT_CLS_PANASONIC,
13962c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
13972258e863SDenis Kovalev 			USB_DEVICE_ID_PANABOARD_UBT880) },
13982258e863SDenis Kovalev 
13994db703eaSAustin Hendrix 	/* Novatek Panel */
1400dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14014380d819SJiri Kosina 		MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
14024db703eaSAustin Hendrix 			USB_DEVICE_ID_NOVATEK_PCT) },
14034db703eaSAustin Hendrix 
1404*a80e803aSBenjamin Tissoires 	/* Ntrig Panel */
1405*a80e803aSBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
1406*a80e803aSBenjamin Tissoires 		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
1407*a80e803aSBenjamin Tissoires 			USB_VENDOR_ID_NTRIG, 0x1b05) },
1408*a80e803aSBenjamin Tissoires 
1409b7ea95ffSAaron Tian 	/* PixArt optical touch screen */
1410b7ea95ffSAaron Tian 	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
14112c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
1412b7ea95ffSAaron Tian 			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
1413b7ea95ffSAaron Tian 	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
14142c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
1415b7ea95ffSAaron Tian 			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
1416b7ea95ffSAaron Tian 	{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
14172c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
1418b7ea95ffSAaron Tian 			USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
1419b7ea95ffSAaron Tian 
14205519cab4SBenjamin Tissoires 	/* PixCir-based panels */
14211e9cf35bSBenjamin Tissoires 	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
14222c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
14235519cab4SBenjamin Tissoires 			USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
14245519cab4SBenjamin Tissoires 
14255e7ea11fSBenjamin Tissoires 	/* Quanta-based panels */
14265e7ea11fSBenjamin Tissoires 	{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
14272c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
14285e7ea11fSBenjamin Tissoires 			USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },
1429a6802e00SForest Bond 
1430043b403aSBenjamin Tissoires 	/* Stantum panels */
1431bf5af9b5SBenjamin Tissoires 	{ .driver_data = MT_CLS_CONFIDENCE,
14322c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
1433043b403aSBenjamin Tissoires 			USB_DEVICE_ID_MTP_STM)},
1434043b403aSBenjamin Tissoires 
1435847672cdSBenjamin Tissoires 	/* TopSeed panels */
1436847672cdSBenjamin Tissoires 	{ .driver_data = MT_CLS_TOPSEED,
14372c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
1438847672cdSBenjamin Tissoires 			USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
1439847672cdSBenjamin Tissoires 
14405e74e56dSBenjamin Tissoires 	/* Touch International panels */
1441dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14422c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
14435e74e56dSBenjamin Tissoires 			USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
14445e74e56dSBenjamin Tissoires 
1445617b64f9SBenjamin Tissoires 	/* Unitec panels */
1446dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14472c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
1448617b64f9SBenjamin Tissoires 			USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
1449dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14502c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
1451617b64f9SBenjamin Tissoires 			USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
1452bf9d121eSKaiChung Cheng 
1453da10bc25SMathieu Magnaudet 	/* VTL panels */
1454da10bc25SMathieu Magnaudet 	{ .driver_data = MT_CLS_VTL,
1455da10bc25SMathieu Magnaudet 		MT_USB_DEVICE(USB_VENDOR_ID_VTL,
1456da10bc25SMathieu Magnaudet 			USB_DEVICE_ID_VTL_MULTITOUCH_FF3F) },
1457da10bc25SMathieu Magnaudet 
1458bf9d121eSKaiChung Cheng 	/* Wistron panels */
1459bf9d121eSKaiChung Cheng 	{ .driver_data = MT_CLS_NSMU,
1460bf9d121eSKaiChung Cheng 		MT_USB_DEVICE(USB_VENDOR_ID_WISTRON,
1461bf9d121eSKaiChung Cheng 			USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH) },
1462bf9d121eSKaiChung Cheng 
1463bc8a2a9bSice chien 	/* XAT */
1464dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14652c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XAT,
1466bc8a2a9bSice chien 			USB_DEVICE_ID_XAT_CSR) },
1467617b64f9SBenjamin Tissoires 
146811576c61SMasatoshi Hoshikawa 	/* Xiroku */
1469dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14702c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
147111576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_SPX) },
1472dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14732c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
147411576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_MPX) },
1475dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14762c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
147711576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_CSR) },
1478dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14792c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
148011576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_SPX1) },
1481dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14822c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
148311576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_MPX1) },
1484dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14852c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
148611576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_CSR1) },
1487dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14882c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
148911576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_SPX2) },
1490dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14912c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
149211576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_MPX2) },
1493dc3e1d80SBenjamin Tissoires 	{ .driver_data = MT_CLS_NSMU,
14942c2110e9SHenrik Rydberg 		MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
149511576c61SMasatoshi Hoshikawa 			USB_DEVICE_ID_XIROKU_CSR2) },
149611576c61SMasatoshi Hoshikawa 
14974fa3a583SHenrik Rydberg 	/* Generic MT device */
14984fa3a583SHenrik Rydberg 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
1499f961bd35SBenjamin Tissoires 
1500f961bd35SBenjamin Tissoires 	/* Generic Win 8 certified MT device */
1501f961bd35SBenjamin Tissoires 	{  .driver_data = MT_CLS_WIN_8,
1502f961bd35SBenjamin Tissoires 		HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
1503f961bd35SBenjamin Tissoires 			HID_ANY_ID, HID_ANY_ID) },
15045519cab4SBenjamin Tissoires 	{ }
15055519cab4SBenjamin Tissoires };
15065519cab4SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, mt_devices);
15075519cab4SBenjamin Tissoires 
15085519cab4SBenjamin Tissoires static const struct hid_usage_id mt_grabbed_usages[] = {
15095519cab4SBenjamin Tissoires 	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
15105519cab4SBenjamin Tissoires 	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
15115519cab4SBenjamin Tissoires };
15125519cab4SBenjamin Tissoires 
15135519cab4SBenjamin Tissoires static struct hid_driver mt_driver = {
15145519cab4SBenjamin Tissoires 	.name = "hid-multitouch",
15155519cab4SBenjamin Tissoires 	.id_table = mt_devices,
15165519cab4SBenjamin Tissoires 	.probe = mt_probe,
15175519cab4SBenjamin Tissoires 	.remove = mt_remove,
15185519cab4SBenjamin Tissoires 	.input_mapping = mt_input_mapping,
15195519cab4SBenjamin Tissoires 	.input_mapped = mt_input_mapped,
152076f5902aSHenrik Rydberg 	.input_configured = mt_input_configured,
15215519cab4SBenjamin Tissoires 	.feature_mapping = mt_feature_mapping,
15225519cab4SBenjamin Tissoires 	.usage_table = mt_grabbed_usages,
15235519cab4SBenjamin Tissoires 	.event = mt_event,
152455978fa9SBenjamin Tissoires 	.report = mt_report,
15255519cab4SBenjamin Tissoires #ifdef CONFIG_PM
15265519cab4SBenjamin Tissoires 	.reset_resume = mt_reset_resume,
1527dfeefd10SScott Liu 	.resume = mt_resume,
15285519cab4SBenjamin Tissoires #endif
15295519cab4SBenjamin Tissoires };
1530f425458eSH Hartley Sweeten module_hid_driver(mt_driver);
1531