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