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> 4629cc309dSNicolas Boichat #include <linux/jiffies.h> 4749a5a827SBenjamin Tissoires #include <linux/string.h> 484f4001bcSBenjamin Tissoires #include <linux/timer.h> 495519cab4SBenjamin Tissoires 505519cab4SBenjamin Tissoires 515519cab4SBenjamin Tissoires MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); 52ef2fafb3SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 535519cab4SBenjamin Tissoires MODULE_DESCRIPTION("HID multitouch panels"); 545519cab4SBenjamin Tissoires MODULE_LICENSE("GPL"); 555519cab4SBenjamin Tissoires 565519cab4SBenjamin Tissoires #include "hid-ids.h" 575519cab4SBenjamin Tissoires 585519cab4SBenjamin Tissoires /* quirks to control the device */ 59fd911896SBenjamin Tissoires #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) 60fd911896SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTID BIT(1) 61fd911896SBenjamin Tissoires #define MT_QUIRK_CYPRESS BIT(2) 62fd911896SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTNUMBER BIT(3) 63fd911896SBenjamin Tissoires #define MT_QUIRK_ALWAYS_VALID BIT(4) 64fd911896SBenjamin Tissoires #define MT_QUIRK_VALID_IS_INRANGE BIT(5) 65fd911896SBenjamin Tissoires #define MT_QUIRK_VALID_IS_CONFIDENCE BIT(6) 66fd911896SBenjamin Tissoires #define MT_QUIRK_CONFIDENCE BIT(7) 67fd911896SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE BIT(8) 68fd911896SBenjamin Tissoires #define MT_QUIRK_NO_AREA BIT(9) 69fd911896SBenjamin Tissoires #define MT_QUIRK_IGNORE_DUPLICATES BIT(10) 70fd911896SBenjamin Tissoires #define MT_QUIRK_HOVERING BIT(11) 71fd911896SBenjamin Tissoires #define MT_QUIRK_CONTACT_CNT_ACCURATE BIT(12) 72fd911896SBenjamin Tissoires #define MT_QUIRK_FORCE_GET_FEATURE BIT(13) 73fd911896SBenjamin Tissoires #define MT_QUIRK_FIX_CONST_CONTACT_ID BIT(14) 74fd911896SBenjamin Tissoires #define MT_QUIRK_TOUCH_SIZE_SCALING BIT(15) 754f4001bcSBenjamin Tissoires #define MT_QUIRK_STICKY_FINGERS BIT(16) 76957b8dffSJoão Paulo Rechi Vita #define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) 775519cab4SBenjamin Tissoires 789abebedbSAndrew Duggan #define MT_INPUTMODE_TOUCHSCREEN 0x02 799abebedbSAndrew Duggan #define MT_INPUTMODE_TOUCHPAD 0x03 809abebedbSAndrew Duggan 812c6e0277SSeth Forshee #define MT_BUTTONTYPE_CLICKPAD 0 822c6e0277SSeth Forshee 834f4001bcSBenjamin Tissoires #define MT_IO_FLAGS_RUNNING 0 8496098274SBenjamin Tissoires #define MT_IO_FLAGS_ACTIVE_SLOTS 1 8596098274SBenjamin Tissoires #define MT_IO_FLAGS_PENDING_SLOTS 2 864f4001bcSBenjamin Tissoires 875519cab4SBenjamin Tissoires struct mt_slot { 88349fd670SBenjamin Tissoires __s32 x, y, cx, cy, p, w, h; 895519cab4SBenjamin Tissoires __s32 contactid; /* the device ContactID assigned to this slot */ 905519cab4SBenjamin Tissoires bool touch_state; /* is the touch valid? */ 919b3bb9b8SBenjamin Tissoires bool inrange_state; /* is the finger in proximity of the sensor? */ 926dd2e27aSAllen Hung bool confidence_state; /* is the touch made by a finger? */ 935519cab4SBenjamin Tissoires }; 945519cab4SBenjamin Tissoires 955519cab4SBenjamin Tissoires struct mt_class { 962d93666eSBenjamin Tissoires __s32 name; /* MT_CLS */ 975519cab4SBenjamin Tissoires __s32 quirks; 985519cab4SBenjamin Tissoires __s32 sn_move; /* Signal/noise ratio for move events */ 99f786bba4SBenjamin Tissoires __s32 sn_width; /* Signal/noise ratio for width events */ 100f786bba4SBenjamin Tissoires __s32 sn_height; /* Signal/noise ratio for height events */ 1015519cab4SBenjamin Tissoires __s32 sn_pressure; /* Signal/noise ratio for pressure events */ 1025519cab4SBenjamin Tissoires __u8 maxcontacts; 103c2ef8f21SBenjamin Tissoires bool is_indirect; /* true for touchpads */ 1046aef704eSBenjamin Tissoires bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */ 1055519cab4SBenjamin Tissoires }; 1065519cab4SBenjamin Tissoires 1073ac36d15SBenjamin Tissoires struct mt_fields { 1083ac36d15SBenjamin Tissoires unsigned usages[HID_MAX_FIELDS]; 1093ac36d15SBenjamin Tissoires unsigned int length; 1103ac36d15SBenjamin Tissoires }; 1113ac36d15SBenjamin Tissoires 1125519cab4SBenjamin Tissoires struct mt_device { 1135519cab4SBenjamin Tissoires struct mt_slot curdata; /* placeholder of incoming data */ 114eec29e3dSBenjamin Tissoires struct mt_class mtclass; /* our mt device class */ 1154f4001bcSBenjamin Tissoires struct timer_list release_timer; /* to release sticky fingers */ 1160ee32774SKees Cook struct hid_device *hdev; /* hid_device we're attached to */ 1173ac36d15SBenjamin Tissoires struct mt_fields *fields; /* temporary placeholder for storing the 1183ac36d15SBenjamin Tissoires multitouch fields */ 1194f4001bcSBenjamin Tissoires unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ 1207e3cc447SBenjamin Tissoires int cc_index; /* contact count field index in the report */ 1217e3cc447SBenjamin Tissoires int cc_value_index; /* contact count value index in the field */ 1225519cab4SBenjamin Tissoires unsigned last_slot_field; /* the last field of a slot */ 12355978fa9SBenjamin Tissoires unsigned mt_report_id; /* the report ID of the multitouch device */ 124b897f6dbSBenjamin Tissoires unsigned long initial_quirks; /* initial quirks state */ 1258821f5dcSBenjamin Tissoires __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ 1268821f5dcSBenjamin Tissoires __s16 inputmode_index; /* InputMode HID feature index in the report */ 1278821f5dcSBenjamin Tissoires __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, 12831ae9bddSBenjamin Tissoires -1 if non-existent */ 1299abebedbSAndrew Duggan __u8 inputmode_value; /* InputMode HID feature value */ 1305519cab4SBenjamin Tissoires __u8 num_received; /* how many contacts we received */ 1315519cab4SBenjamin Tissoires __u8 num_expected; /* expected last contact index */ 1325519cab4SBenjamin Tissoires __u8 maxcontacts; 1339e87f22aSBenjamin Tissoires __u8 touches_by_report; /* how many touches are present in one report: 1349e87f22aSBenjamin Tissoires * 1 means we should use a serial protocol 1359e87f22aSBenjamin Tissoires * > 1 means hybrid (multitouch) protocol */ 136015fdaa9SBenjamin Tissoires __u8 buttons_count; /* number of physical buttons per touchpad */ 1372c6e0277SSeth Forshee bool is_buttonpad; /* is this device a button pad? */ 13876f5902aSHenrik Rydberg bool serial_maybe; /* need to check for serial protocol */ 1395519cab4SBenjamin Tissoires bool curvalid; /* is the current contact valid? */ 14076f5902aSHenrik Rydberg unsigned mt_flags; /* flags to pass to input-mt */ 14129cc309dSNicolas Boichat __s32 dev_time; /* the scan time provided by the device */ 14229cc309dSNicolas Boichat unsigned long jiffies; /* the frame's jiffies */ 14329cc309dSNicolas Boichat int timestamp; /* the timestamp to be sent */ 1445519cab4SBenjamin Tissoires }; 1455519cab4SBenjamin Tissoires 146a69c5f8bSBenjamin Tissoires static void mt_post_parse_default_settings(struct mt_device *td); 147a69c5f8bSBenjamin Tissoires static void mt_post_parse(struct mt_device *td); 148a69c5f8bSBenjamin Tissoires 1495519cab4SBenjamin Tissoires /* classes of device behavior */ 15022408283SBenjamin Tissoires #define MT_CLS_DEFAULT 0x0001 15122408283SBenjamin Tissoires 152a062cc5aSStephane Chatty #define MT_CLS_SERIAL 0x0002 153a062cc5aSStephane Chatty #define MT_CLS_CONFIDENCE 0x0003 1545e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_CONTACT_ID 0x0004 1555e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 1565e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 1575e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 1580fa9c616SBenjamin Tissoires /* reserved 0x0008 */ 159b7ea95ffSAaron Tian #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 160dc3e1d80SBenjamin Tissoires #define MT_CLS_NSMU 0x000a 1610fa9c616SBenjamin Tissoires /* reserved 0x0010 */ 1620fa9c616SBenjamin Tissoires /* reserved 0x0011 */ 163f961bd35SBenjamin Tissoires #define MT_CLS_WIN_8 0x0012 1646aef704eSBenjamin Tissoires #define MT_CLS_EXPORT_ALL_INPUTS 0x0013 165504c932cSMasaki Ota #define MT_CLS_WIN_8_DUAL 0x0014 16622408283SBenjamin Tissoires 16722408283SBenjamin Tissoires /* vendor specific classes */ 16822408283SBenjamin Tissoires #define MT_CLS_3M 0x0101 1690fa9c616SBenjamin Tissoires /* reserved 0x0102 */ 17022408283SBenjamin Tissoires #define MT_CLS_EGALAX 0x0103 1711b723e8dSBenjamin Tissoires #define MT_CLS_EGALAX_SERIAL 0x0104 172847672cdSBenjamin Tissoires #define MT_CLS_TOPSEED 0x0105 1732258e863SDenis Kovalev #define MT_CLS_PANASONIC 0x0106 17477723e3bSHenrik Rydberg #define MT_CLS_FLATFROG 0x0107 175cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 176cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 177f3287a99SBenjamin Tissoires #define MT_CLS_LG 0x010a 178957b8dffSJoão Paulo Rechi Vita #define MT_CLS_ASUS 0x010b 179da10bc25SMathieu Magnaudet #define MT_CLS_VTL 0x0110 1800e82232cSWei-Ning Huang #define MT_CLS_GOOGLE 0x0111 1815519cab4SBenjamin Tissoires 1829498f954SBenjamin Tissoires #define MT_DEFAULT_MAXCONTACT 10 183afbcb04cSBenjamin Tissoires #define MT_MAX_MAXCONTACT 250 1849498f954SBenjamin Tissoires 18529cc309dSNicolas Boichat /* 18629cc309dSNicolas Boichat * Resync device and local timestamps after that many microseconds without 18729cc309dSNicolas Boichat * receiving data. 18829cc309dSNicolas Boichat */ 18929cc309dSNicolas Boichat #define MAX_TIMESTAMP_INTERVAL 1000000 19029cc309dSNicolas Boichat 1912c2110e9SHenrik Rydberg #define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) 1922c2110e9SHenrik Rydberg #define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) 1932c2110e9SHenrik Rydberg 1945519cab4SBenjamin Tissoires /* 1955519cab4SBenjamin Tissoires * these device-dependent functions determine what slot corresponds 1965519cab4SBenjamin Tissoires * to a valid contact that was just read. 1975519cab4SBenjamin Tissoires */ 1985519cab4SBenjamin Tissoires 199a3b5e577SBenjamin Tissoires static int cypress_compute_slot(struct mt_device *td) 200a3b5e577SBenjamin Tissoires { 201a3b5e577SBenjamin Tissoires if (td->curdata.contactid != 0 || td->num_received == 0) 202a3b5e577SBenjamin Tissoires return td->curdata.contactid; 203a3b5e577SBenjamin Tissoires else 204a3b5e577SBenjamin Tissoires return -1; 205a3b5e577SBenjamin Tissoires } 206a3b5e577SBenjamin Tissoires 207b3c21d2cSJiri Kosina static struct mt_class mt_classes[] = { 2082d93666eSBenjamin Tissoires { .name = MT_CLS_DEFAULT, 209dc3e1d80SBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 210dc3e1d80SBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE }, 211dc3e1d80SBenjamin Tissoires { .name = MT_CLS_NSMU, 2129498f954SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, 213a062cc5aSStephane Chatty { .name = MT_CLS_SERIAL, 214a062cc5aSStephane Chatty .quirks = MT_QUIRK_ALWAYS_VALID}, 21522408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE, 21622408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, 2175e7ea11fSBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_CONTACT_ID, 2185e7ea11fSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 2195e7ea11fSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID }, 22022408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_MINUS_ONE, 22122408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 22222408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, 2231e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTID, 2242d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 2252d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 2262d93666eSBenjamin Tissoires .maxcontacts = 2 }, 2271e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 2282d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 2292d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTNUMBER, 2302d93666eSBenjamin Tissoires .maxcontacts = 2 }, 231b7ea95ffSAaron Tian { .name = MT_CLS_INRANGE_CONTACTNUMBER, 232b7ea95ffSAaron Tian .quirks = MT_QUIRK_VALID_IS_INRANGE | 233b7ea95ffSAaron Tian MT_QUIRK_SLOT_IS_CONTACTNUMBER }, 234f961bd35SBenjamin Tissoires { .name = MT_CLS_WIN_8, 235f961bd35SBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 236f961bd35SBenjamin Tissoires MT_QUIRK_IGNORE_DUPLICATES | 237f961bd35SBenjamin Tissoires MT_QUIRK_HOVERING | 2384f4001bcSBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE | 2394f4001bcSBenjamin Tissoires MT_QUIRK_STICKY_FINGERS }, 2406aef704eSBenjamin Tissoires { .name = MT_CLS_EXPORT_ALL_INPUTS, 2416aef704eSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 2426aef704eSBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE, 2436aef704eSBenjamin Tissoires .export_all_inputs = true }, 244504c932cSMasaki Ota { .name = MT_CLS_WIN_8_DUAL, 245504c932cSMasaki Ota .quirks = MT_QUIRK_ALWAYS_VALID | 246504c932cSMasaki Ota MT_QUIRK_IGNORE_DUPLICATES | 247504c932cSMasaki Ota MT_QUIRK_HOVERING | 248504c932cSMasaki Ota MT_QUIRK_CONTACT_CNT_ACCURATE, 249504c932cSMasaki Ota .export_all_inputs = true }, 25022408283SBenjamin Tissoires 25122408283SBenjamin Tissoires /* 25222408283SBenjamin Tissoires * vendor specific classes 25322408283SBenjamin Tissoires */ 25422408283SBenjamin Tissoires { .name = MT_CLS_3M, 25522408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 256e9d0a26dSHungNien Chen MT_QUIRK_SLOT_IS_CONTACTID | 257e9d0a26dSHungNien Chen MT_QUIRK_TOUCH_SIZE_SCALING, 25822408283SBenjamin Tissoires .sn_move = 2048, 25922408283SBenjamin Tissoires .sn_width = 128, 260c5d40be5SHenrik Rydberg .sn_height = 128, 261c5d40be5SHenrik Rydberg .maxcontacts = 60, 262c5d40be5SHenrik Rydberg }, 2634875ac11SRichard Nauber { .name = MT_CLS_EGALAX, 2644875ac11SRichard Nauber .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 2652261bb9fSBenjamin Tissoires MT_QUIRK_VALID_IS_INRANGE, 2664875ac11SRichard Nauber .sn_move = 4096, 2674875ac11SRichard Nauber .sn_pressure = 32, 2684875ac11SRichard Nauber }, 2691b723e8dSBenjamin Tissoires { .name = MT_CLS_EGALAX_SERIAL, 2701b723e8dSBenjamin Tissoires .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 2711b723e8dSBenjamin Tissoires MT_QUIRK_ALWAYS_VALID, 2722d93666eSBenjamin Tissoires .sn_move = 4096, 2732d93666eSBenjamin Tissoires .sn_pressure = 32, 2742d93666eSBenjamin Tissoires }, 275847672cdSBenjamin Tissoires { .name = MT_CLS_TOPSEED, 276847672cdSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID, 277847672cdSBenjamin Tissoires .is_indirect = true, 278847672cdSBenjamin Tissoires .maxcontacts = 2, 279847672cdSBenjamin Tissoires }, 2802258e863SDenis Kovalev { .name = MT_CLS_PANASONIC, 2812258e863SDenis Kovalev .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, 2822258e863SDenis Kovalev .maxcontacts = 4 }, 283f5ff4e1eSXianhan Yu { .name = MT_CLS_GENERALTOUCH_TWOFINGERS, 284f5ff4e1eSXianhan Yu .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 285f5ff4e1eSXianhan Yu MT_QUIRK_VALID_IS_INRANGE | 2867b226292SLuosong MT_QUIRK_SLOT_IS_CONTACTID, 287f5ff4e1eSXianhan Yu .maxcontacts = 2 288f5ff4e1eSXianhan Yu }, 289f5ff4e1eSXianhan Yu { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 290f5ff4e1eSXianhan Yu .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 2917b226292SLuosong MT_QUIRK_SLOT_IS_CONTACTID 292f5ff4e1eSXianhan Yu }, 293043b403aSBenjamin Tissoires 29477723e3bSHenrik Rydberg { .name = MT_CLS_FLATFROG, 29577723e3bSHenrik Rydberg .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 29677723e3bSHenrik Rydberg MT_QUIRK_NO_AREA, 29777723e3bSHenrik Rydberg .sn_move = 2048, 29877723e3bSHenrik Rydberg .maxcontacts = 40, 29977723e3bSHenrik Rydberg }, 300f3287a99SBenjamin Tissoires { .name = MT_CLS_LG, 301f3287a99SBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 302f3287a99SBenjamin Tissoires MT_QUIRK_FIX_CONST_CONTACT_ID | 303f3287a99SBenjamin Tissoires MT_QUIRK_IGNORE_DUPLICATES | 304f3287a99SBenjamin Tissoires MT_QUIRK_HOVERING | 305f3287a99SBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE }, 306957b8dffSJoão Paulo Rechi Vita { .name = MT_CLS_ASUS, 307957b8dffSJoão Paulo Rechi Vita .quirks = MT_QUIRK_ALWAYS_VALID | 308957b8dffSJoão Paulo Rechi Vita MT_QUIRK_CONTACT_CNT_ACCURATE | 309957b8dffSJoão Paulo Rechi Vita MT_QUIRK_ASUS_CUSTOM_UP }, 310da10bc25SMathieu Magnaudet { .name = MT_CLS_VTL, 311da10bc25SMathieu Magnaudet .quirks = MT_QUIRK_ALWAYS_VALID | 312da10bc25SMathieu Magnaudet MT_QUIRK_CONTACT_CNT_ACCURATE | 313da10bc25SMathieu Magnaudet MT_QUIRK_FORCE_GET_FEATURE, 314da10bc25SMathieu Magnaudet }, 3150e82232cSWei-Ning Huang { .name = MT_CLS_GOOGLE, 3160e82232cSWei-Ning Huang .quirks = MT_QUIRK_ALWAYS_VALID | 3170e82232cSWei-Ning Huang MT_QUIRK_CONTACT_CNT_ACCURATE | 3180e82232cSWei-Ning Huang MT_QUIRK_SLOT_IS_CONTACTID | 3190e82232cSWei-Ning Huang MT_QUIRK_HOVERING 3200e82232cSWei-Ning Huang }, 3212d93666eSBenjamin Tissoires { } 3225519cab4SBenjamin Tissoires }; 3235519cab4SBenjamin Tissoires 324eec29e3dSBenjamin Tissoires static ssize_t mt_show_quirks(struct device *dev, 325eec29e3dSBenjamin Tissoires struct device_attribute *attr, 326eec29e3dSBenjamin Tissoires char *buf) 327eec29e3dSBenjamin Tissoires { 328ee79a8f8SGeliang Tang struct hid_device *hdev = to_hid_device(dev); 329eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 330eec29e3dSBenjamin Tissoires 331eec29e3dSBenjamin Tissoires return sprintf(buf, "%u\n", td->mtclass.quirks); 332eec29e3dSBenjamin Tissoires } 333eec29e3dSBenjamin Tissoires 334eec29e3dSBenjamin Tissoires static ssize_t mt_set_quirks(struct device *dev, 335eec29e3dSBenjamin Tissoires struct device_attribute *attr, 336eec29e3dSBenjamin Tissoires const char *buf, size_t count) 337eec29e3dSBenjamin Tissoires { 338ee79a8f8SGeliang Tang struct hid_device *hdev = to_hid_device(dev); 339eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 340eec29e3dSBenjamin Tissoires 341eec29e3dSBenjamin Tissoires unsigned long val; 342eec29e3dSBenjamin Tissoires 343eec29e3dSBenjamin Tissoires if (kstrtoul(buf, 0, &val)) 344eec29e3dSBenjamin Tissoires return -EINVAL; 345eec29e3dSBenjamin Tissoires 346eec29e3dSBenjamin Tissoires td->mtclass.quirks = val; 347eec29e3dSBenjamin Tissoires 3487e3cc447SBenjamin Tissoires if (td->cc_index < 0) 349c2517f62SBenjamin Tissoires td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 350c2517f62SBenjamin Tissoires 351eec29e3dSBenjamin Tissoires return count; 352eec29e3dSBenjamin Tissoires } 353eec29e3dSBenjamin Tissoires 354eec29e3dSBenjamin Tissoires static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); 355eec29e3dSBenjamin Tissoires 356eec29e3dSBenjamin Tissoires static struct attribute *sysfs_attrs[] = { 357eec29e3dSBenjamin Tissoires &dev_attr_quirks.attr, 358eec29e3dSBenjamin Tissoires NULL 359eec29e3dSBenjamin Tissoires }; 360eec29e3dSBenjamin Tissoires 3619182fb98SArvind Yadav static const struct attribute_group mt_attribute_group = { 362eec29e3dSBenjamin Tissoires .attrs = sysfs_attrs 363eec29e3dSBenjamin Tissoires }; 364eec29e3dSBenjamin Tissoires 3656d4f5440SMika Westerberg static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) 3666d4f5440SMika Westerberg { 3676d4f5440SMika Westerberg struct mt_device *td = hid_get_drvdata(hdev); 3686d4f5440SMika Westerberg int ret, size = hid_report_len(report); 3696d4f5440SMika Westerberg u8 *buf; 3706d4f5440SMika Westerberg 3716d4f5440SMika Westerberg /* 372b897f6dbSBenjamin Tissoires * Do not fetch the feature report if the device has been explicitly 373b897f6dbSBenjamin Tissoires * marked as non-capable. 3746d4f5440SMika Westerberg */ 375b897f6dbSBenjamin Tissoires if (td->initial_quirks & HID_QUIRK_NO_INIT_REPORTS) 3766d4f5440SMika Westerberg return; 3776d4f5440SMika Westerberg 3786d4f5440SMika Westerberg buf = hid_alloc_report_buf(report, GFP_KERNEL); 3796d4f5440SMika Westerberg if (!buf) 3806d4f5440SMika Westerberg return; 3816d4f5440SMika Westerberg 3826d4f5440SMika Westerberg ret = hid_hw_raw_request(hdev, report->id, buf, size, 3836d4f5440SMika Westerberg HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 3846d4f5440SMika Westerberg if (ret < 0) { 3856d4f5440SMika Westerberg dev_warn(&hdev->dev, "failed to fetch feature %d\n", 3866d4f5440SMika Westerberg report->id); 3876d4f5440SMika Westerberg } else { 3886d4f5440SMika Westerberg ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, 3896d4f5440SMika Westerberg size, 0); 3906d4f5440SMika Westerberg if (ret) 3916d4f5440SMika Westerberg dev_warn(&hdev->dev, "failed to report feature\n"); 3926d4f5440SMika Westerberg } 3936d4f5440SMika Westerberg 3946d4f5440SMika Westerberg kfree(buf); 3956d4f5440SMika Westerberg } 3966d4f5440SMika Westerberg 397f635bd11SHenrik Rydberg static void mt_feature_mapping(struct hid_device *hdev, 3985519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage) 3995519cab4SBenjamin Tissoires { 4005519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 4019498f954SBenjamin Tissoires 4029498f954SBenjamin Tissoires switch (usage->hid) { 4039498f954SBenjamin Tissoires case HID_DG_INPUTMODE: 4048821f5dcSBenjamin Tissoires /* Ignore if value index is out of bounds. */ 4058821f5dcSBenjamin Tissoires if (usage->usage_index >= field->report_count) { 4068821f5dcSBenjamin Tissoires dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n"); 4074aceed37SBenjamin Tissoires break; 4084aceed37SBenjamin Tissoires } 4098821f5dcSBenjamin Tissoires 41073e7d63eSBenjamin Tissoires if (td->inputmode < 0) { 4118821f5dcSBenjamin Tissoires td->inputmode = field->report->id; 4128821f5dcSBenjamin Tissoires td->inputmode_index = usage->usage_index; 41373e7d63eSBenjamin Tissoires } else { 41473e7d63eSBenjamin Tissoires /* 41573e7d63eSBenjamin Tissoires * Some elan panels wrongly declare 2 input mode 41673e7d63eSBenjamin Tissoires * features, and silently ignore when we set the 41773e7d63eSBenjamin Tissoires * value in the second field. Skip the second feature 41873e7d63eSBenjamin Tissoires * and hope for the best. 41973e7d63eSBenjamin Tissoires */ 42073e7d63eSBenjamin Tissoires dev_info(&hdev->dev, 42173e7d63eSBenjamin Tissoires "Ignoring the extra HID_DG_INPUTMODE\n"); 42273e7d63eSBenjamin Tissoires } 4234aceed37SBenjamin Tissoires 4249498f954SBenjamin Tissoires break; 4259498f954SBenjamin Tissoires case HID_DG_CONTACTMAX: 4266d4f5440SMika Westerberg mt_get_feature(hdev, field->report); 4276d4f5440SMika Westerberg 42831ae9bddSBenjamin Tissoires td->maxcontact_report_id = field->report->id; 4299498f954SBenjamin Tissoires td->maxcontacts = field->value[0]; 430afbcb04cSBenjamin Tissoires if (!td->maxcontacts && 431afbcb04cSBenjamin Tissoires field->logical_maximum <= MT_MAX_MAXCONTACT) 432afbcb04cSBenjamin Tissoires td->maxcontacts = field->logical_maximum; 433eec29e3dSBenjamin Tissoires if (td->mtclass.maxcontacts) 4349498f954SBenjamin Tissoires /* check if the maxcontacts is given by the class */ 435eec29e3dSBenjamin Tissoires td->maxcontacts = td->mtclass.maxcontacts; 4369498f954SBenjamin Tissoires 4379498f954SBenjamin Tissoires break; 4382c6e0277SSeth Forshee case HID_DG_BUTTONTYPE: 4392c6e0277SSeth Forshee if (usage->usage_index >= field->report_count) { 4402c6e0277SSeth Forshee dev_err(&hdev->dev, "HID_DG_BUTTONTYPE out of range\n"); 4412c6e0277SSeth Forshee break; 4422c6e0277SSeth Forshee } 4432c6e0277SSeth Forshee 4446d4f5440SMika Westerberg mt_get_feature(hdev, field->report); 4452c6e0277SSeth Forshee if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD) 4462c6e0277SSeth Forshee td->is_buttonpad = true; 4472c6e0277SSeth Forshee 4482c6e0277SSeth Forshee break; 44945c5c682SBenjamin Tissoires case 0xff0000c5: 45045c5c682SBenjamin Tissoires /* Retrieve the Win8 blob once to enable some devices */ 45145c5c682SBenjamin Tissoires if (usage->usage_index == 0) 45245c5c682SBenjamin Tissoires mt_get_feature(hdev, field->report); 45345c5c682SBenjamin Tissoires break; 4545519cab4SBenjamin Tissoires } 4555519cab4SBenjamin Tissoires } 4565519cab4SBenjamin Tissoires 4575519cab4SBenjamin Tissoires static void set_abs(struct input_dev *input, unsigned int code, 4585519cab4SBenjamin Tissoires struct hid_field *field, int snratio) 4595519cab4SBenjamin Tissoires { 4605519cab4SBenjamin Tissoires int fmin = field->logical_minimum; 4615519cab4SBenjamin Tissoires int fmax = field->logical_maximum; 4625519cab4SBenjamin Tissoires int fuzz = snratio ? (fmax - fmin) / snratio : 0; 4635519cab4SBenjamin Tissoires input_set_abs_params(input, code, fmin, fmax, fuzz, 0); 46437cf6e6fSBenjamin Tissoires input_abs_set_res(input, code, hidinput_calc_abs_res(field, code)); 4655519cab4SBenjamin Tissoires } 4665519cab4SBenjamin Tissoires 4673ac36d15SBenjamin Tissoires static void mt_store_field(struct hid_usage *usage, struct mt_device *td, 468ed9d5c96SBenjamin Tissoires struct hid_input *hi) 469ed9d5c96SBenjamin Tissoires { 4703ac36d15SBenjamin Tissoires struct mt_fields *f = td->fields; 4713ac36d15SBenjamin Tissoires 4723ac36d15SBenjamin Tissoires if (f->length >= HID_MAX_FIELDS) 4733ac36d15SBenjamin Tissoires return; 4743ac36d15SBenjamin Tissoires 4753ac36d15SBenjamin Tissoires f->usages[f->length++] = usage->hid; 476ed9d5c96SBenjamin Tissoires } 477ed9d5c96SBenjamin Tissoires 478a69c5f8bSBenjamin Tissoires static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, 4795519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 4805519cab4SBenjamin Tissoires unsigned long **bit, int *max) 4815519cab4SBenjamin Tissoires { 4825519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 483eec29e3dSBenjamin Tissoires struct mt_class *cls = &td->mtclass; 484c2ef8f21SBenjamin Tissoires int code; 485349fd670SBenjamin Tissoires struct hid_usage *prev_usage = NULL; 4864875ac11SRichard Nauber 487658d4aedSJeff Brown if (field->application == HID_DG_TOUCHSCREEN) 48876f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_DIRECT; 489658d4aedSJeff Brown 49076f5902aSHenrik Rydberg /* 49176f5902aSHenrik Rydberg * Model touchscreens providing buttons as touchpads. 492c2ef8f21SBenjamin Tissoires */ 493c2ef8f21SBenjamin Tissoires if (field->application == HID_DG_TOUCHPAD || 4949abebedbSAndrew Duggan (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { 49576f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_POINTER; 4969abebedbSAndrew Duggan td->inputmode_value = MT_INPUTMODE_TOUCHPAD; 4979abebedbSAndrew Duggan } 498c2ef8f21SBenjamin Tissoires 499015fdaa9SBenjamin Tissoires /* count the buttons on touchpads */ 500015fdaa9SBenjamin Tissoires if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) 501015fdaa9SBenjamin Tissoires td->buttons_count++; 502015fdaa9SBenjamin Tissoires 503349fd670SBenjamin Tissoires if (usage->usage_index) 504349fd670SBenjamin Tissoires prev_usage = &field->usage[usage->usage_index - 1]; 505349fd670SBenjamin Tissoires 5065519cab4SBenjamin Tissoires switch (usage->hid & HID_USAGE_PAGE) { 5075519cab4SBenjamin Tissoires 5085519cab4SBenjamin Tissoires case HID_UP_GENDESK: 5095519cab4SBenjamin Tissoires switch (usage->hid) { 5105519cab4SBenjamin Tissoires case HID_GD_X: 511349fd670SBenjamin Tissoires if (prev_usage && (prev_usage->hid == usage->hid)) { 512349fd670SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 513349fd670SBenjamin Tissoires EV_ABS, ABS_MT_TOOL_X); 514349fd670SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOOL_X, field, 515349fd670SBenjamin Tissoires cls->sn_move); 516349fd670SBenjamin Tissoires } else { 5175519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 5185519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_X); 5195519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_X, field, 5205519cab4SBenjamin Tissoires cls->sn_move); 521349fd670SBenjamin Tissoires } 522349fd670SBenjamin Tissoires 5233ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5245519cab4SBenjamin Tissoires return 1; 5255519cab4SBenjamin Tissoires case HID_GD_Y: 526349fd670SBenjamin Tissoires if (prev_usage && (prev_usage->hid == usage->hid)) { 527349fd670SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 528349fd670SBenjamin Tissoires EV_ABS, ABS_MT_TOOL_Y); 529349fd670SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOOL_Y, field, 530349fd670SBenjamin Tissoires cls->sn_move); 531349fd670SBenjamin Tissoires } else { 5325519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 5335519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_Y); 5345519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_Y, field, 5355519cab4SBenjamin Tissoires cls->sn_move); 536349fd670SBenjamin Tissoires } 537349fd670SBenjamin Tissoires 5383ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5395519cab4SBenjamin Tissoires return 1; 5405519cab4SBenjamin Tissoires } 5415519cab4SBenjamin Tissoires return 0; 5425519cab4SBenjamin Tissoires 5435519cab4SBenjamin Tissoires case HID_UP_DIGITIZER: 5445519cab4SBenjamin Tissoires switch (usage->hid) { 5455519cab4SBenjamin Tissoires case HID_DG_INRANGE: 5469b3bb9b8SBenjamin Tissoires if (cls->quirks & MT_QUIRK_HOVERING) { 5479b3bb9b8SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 5489b3bb9b8SBenjamin Tissoires EV_ABS, ABS_MT_DISTANCE); 5499b3bb9b8SBenjamin Tissoires input_set_abs_params(hi->input, 5509b3bb9b8SBenjamin Tissoires ABS_MT_DISTANCE, 0, 1, 0, 0); 5519b3bb9b8SBenjamin Tissoires } 5523ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5535519cab4SBenjamin Tissoires return 1; 5545519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 555504c932cSMasaki Ota if ((cls->name == MT_CLS_WIN_8 || 556504c932cSMasaki Ota cls->name == MT_CLS_WIN_8_DUAL) && 5576dd2e27aSAllen Hung field->application == HID_DG_TOUCHPAD) 5586dd2e27aSAllen Hung cls->quirks |= MT_QUIRK_CONFIDENCE; 5593ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5605519cab4SBenjamin Tissoires return 1; 5615519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 5625519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); 5635519cab4SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, BTN_TOUCH); 5643ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5655519cab4SBenjamin Tissoires return 1; 5665519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 5673ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5689e87f22aSBenjamin Tissoires td->touches_by_report++; 56955978fa9SBenjamin Tissoires td->mt_report_id = field->report->id; 5705519cab4SBenjamin Tissoires return 1; 5715519cab4SBenjamin Tissoires case HID_DG_WIDTH: 5725519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 5735519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MAJOR); 57477723e3bSHenrik Rydberg if (!(cls->quirks & MT_QUIRK_NO_AREA)) 575f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, 576f786bba4SBenjamin Tissoires cls->sn_width); 5773ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5785519cab4SBenjamin Tissoires return 1; 5795519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 5805519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 5815519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MINOR); 58277723e3bSHenrik Rydberg if (!(cls->quirks & MT_QUIRK_NO_AREA)) { 583f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, 584f786bba4SBenjamin Tissoires cls->sn_height); 5851e648a13SBenjamin Tissoires input_set_abs_params(hi->input, 5861e648a13SBenjamin Tissoires ABS_MT_ORIENTATION, 0, 1, 0, 0); 58777723e3bSHenrik Rydberg } 5883ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5895519cab4SBenjamin Tissoires return 1; 5905519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 5915519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 5925519cab4SBenjamin Tissoires EV_ABS, ABS_MT_PRESSURE); 5935519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_PRESSURE, field, 5945519cab4SBenjamin Tissoires cls->sn_pressure); 5953ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 5965519cab4SBenjamin Tissoires return 1; 59729cc309dSNicolas Boichat case HID_DG_SCANTIME: 59829cc309dSNicolas Boichat hid_map_usage(hi, usage, bit, max, 59929cc309dSNicolas Boichat EV_MSC, MSC_TIMESTAMP); 60029cc309dSNicolas Boichat input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); 60129cc309dSNicolas Boichat mt_store_field(usage, td, hi); 60229cc309dSNicolas Boichat return 1; 6035519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 6048821f5dcSBenjamin Tissoires /* Ignore if indexes are out of bounds. */ 6058821f5dcSBenjamin Tissoires if (field->index >= field->report->maxfield || 6068821f5dcSBenjamin Tissoires usage->usage_index >= field->report_count) 6078821f5dcSBenjamin Tissoires return 1; 6087e3cc447SBenjamin Tissoires td->cc_index = field->index; 6097e3cc447SBenjamin Tissoires td->cc_value_index = usage->usage_index; 6105519cab4SBenjamin Tissoires return 1; 6115519cab4SBenjamin Tissoires case HID_DG_CONTACTMAX: 6125519cab4SBenjamin Tissoires /* we don't set td->last_slot_field as contactcount and 6135519cab4SBenjamin Tissoires * contact max are global to the report */ 6145519cab4SBenjamin Tissoires return -1; 615c2ef8f21SBenjamin Tissoires case HID_DG_TOUCH: 616c2ef8f21SBenjamin Tissoires /* Legacy devices use TIPSWITCH and not TOUCH. 617c2ef8f21SBenjamin Tissoires * Let's just ignore this field. */ 618c2ef8f21SBenjamin Tissoires return -1; 61965b258e9SAlan Cox } 6205519cab4SBenjamin Tissoires /* let hid-input decide for the others */ 6215519cab4SBenjamin Tissoires return 0; 6225519cab4SBenjamin Tissoires 623c2ef8f21SBenjamin Tissoires case HID_UP_BUTTON: 624c2ef8f21SBenjamin Tissoires code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); 625594312b8SBenjamin Tissoires /* 626594312b8SBenjamin Tissoires * MS PTP spec says that external buttons left and right have 627594312b8SBenjamin Tissoires * usages 2 and 3. 628594312b8SBenjamin Tissoires */ 629504c932cSMasaki Ota if ((cls->name == MT_CLS_WIN_8 || 630504c932cSMasaki Ota cls->name == MT_CLS_WIN_8_DUAL) && 631594312b8SBenjamin Tissoires field->application == HID_DG_TOUCHPAD && 632594312b8SBenjamin Tissoires (usage->hid & HID_USAGE) > 1) 633594312b8SBenjamin Tissoires code--; 634c2ef8f21SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, code); 635c2ef8f21SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, code); 636c2ef8f21SBenjamin Tissoires return 1; 637c2ef8f21SBenjamin Tissoires 6385519cab4SBenjamin Tissoires case 0xff000000: 6395519cab4SBenjamin Tissoires /* we do not want to map these: no input-oriented meaning */ 6405519cab4SBenjamin Tissoires return -1; 6415519cab4SBenjamin Tissoires } 6425519cab4SBenjamin Tissoires 6435519cab4SBenjamin Tissoires return 0; 6445519cab4SBenjamin Tissoires } 6455519cab4SBenjamin Tissoires 6463e1b5015SHenrik Rydberg static int mt_compute_slot(struct mt_device *td, struct input_dev *input) 6475519cab4SBenjamin Tissoires { 648eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 6495519cab4SBenjamin Tissoires 6502d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) 6512d93666eSBenjamin Tissoires return td->curdata.contactid; 6525519cab4SBenjamin Tissoires 6532d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_CYPRESS) 654a3b5e577SBenjamin Tissoires return cypress_compute_slot(td); 655a3b5e577SBenjamin Tissoires 6562d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) 6572d93666eSBenjamin Tissoires return td->num_received; 6585572da08SBenjamin Tissoires 6594a6ee685SBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) 6604a6ee685SBenjamin Tissoires return td->curdata.contactid - 1; 6614a6ee685SBenjamin Tissoires 6623e1b5015SHenrik Rydberg return input_mt_get_slot_by_key(input, td->curdata.contactid); 6635519cab4SBenjamin Tissoires } 6645519cab4SBenjamin Tissoires 6655519cab4SBenjamin Tissoires /* 6665519cab4SBenjamin Tissoires * this function is called when a whole contact has been processed, 6675519cab4SBenjamin Tissoires * so that it can assign it to a slot and store the data there 6685519cab4SBenjamin Tissoires */ 6693e1b5015SHenrik Rydberg static void mt_complete_slot(struct mt_device *td, struct input_dev *input) 6705519cab4SBenjamin Tissoires { 671c2517f62SBenjamin Tissoires if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) && 672c2517f62SBenjamin Tissoires td->num_received >= td->num_expected) 673c2517f62SBenjamin Tissoires return; 674c2517f62SBenjamin Tissoires 67520b60e6dSBenjamin Tissoires if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) { 6766dd2e27aSAllen Hung int active; 6773e1b5015SHenrik Rydberg int slotnum = mt_compute_slot(td, input); 6783e1b5015SHenrik Rydberg struct mt_slot *s = &td->curdata; 67928728399SBenjamin Tissoires struct input_mt *mt = input->mt; 6805519cab4SBenjamin Tissoires 6813e1b5015SHenrik Rydberg if (slotnum < 0 || slotnum >= td->maxcontacts) 6823e1b5015SHenrik Rydberg return; 6835519cab4SBenjamin Tissoires 68428728399SBenjamin Tissoires if ((td->mtclass.quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) { 68528728399SBenjamin Tissoires struct input_mt_slot *slot = &mt->slots[slotnum]; 68628728399SBenjamin Tissoires if (input_mt_is_active(slot) && 68728728399SBenjamin Tissoires input_mt_is_used(mt, slot)) 68828728399SBenjamin Tissoires return; 68928728399SBenjamin Tissoires } 69028728399SBenjamin Tissoires 6916dd2e27aSAllen Hung if (!(td->mtclass.quirks & MT_QUIRK_CONFIDENCE)) 6926dd2e27aSAllen Hung s->confidence_state = 1; 6936dd2e27aSAllen Hung active = (s->touch_state || s->inrange_state) && 6946dd2e27aSAllen Hung s->confidence_state; 6956dd2e27aSAllen Hung 6963e1b5015SHenrik Rydberg input_mt_slot(input, slotnum); 6976dd2e27aSAllen Hung input_mt_report_slot_state(input, MT_TOOL_FINGER, active); 6986dd2e27aSAllen Hung if (active) { 6999b3bb9b8SBenjamin Tissoires /* this finger is in proximity of the sensor */ 700f786bba4SBenjamin Tissoires int wide = (s->w > s->h); 701e9d0a26dSHungNien Chen int major = max(s->w, s->h); 702e9d0a26dSHungNien Chen int minor = min(s->w, s->h); 703e9d0a26dSHungNien Chen 704e9d0a26dSHungNien Chen /* 705e9d0a26dSHungNien Chen * divided by two to match visual scale of touch 706e9d0a26dSHungNien Chen * for devices with this quirk 707e9d0a26dSHungNien Chen */ 708e9d0a26dSHungNien Chen if (td->mtclass.quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { 709e9d0a26dSHungNien Chen major = major >> 1; 710e9d0a26dSHungNien Chen minor = minor >> 1; 711e9d0a26dSHungNien Chen } 712f786bba4SBenjamin Tissoires 7135519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); 7145519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); 715349fd670SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx); 716349fd670SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy); 7179b3bb9b8SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_DISTANCE, 7189b3bb9b8SBenjamin Tissoires !s->touch_state); 719f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); 7205519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); 721f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 722f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 72396098274SBenjamin Tissoires 72496098274SBenjamin Tissoires set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 7252d93666eSBenjamin Tissoires } 7265519cab4SBenjamin Tissoires } 7275519cab4SBenjamin Tissoires 7283e1b5015SHenrik Rydberg td->num_received++; 7293e1b5015SHenrik Rydberg } 7303e1b5015SHenrik Rydberg 7313e1b5015SHenrik Rydberg /* 7323e1b5015SHenrik Rydberg * this function is called when a whole packet has been received and processed, 7333e1b5015SHenrik Rydberg * so that it can decide what to send to the input layer. 7343e1b5015SHenrik Rydberg */ 7353e1b5015SHenrik Rydberg static void mt_sync_frame(struct mt_device *td, struct input_dev *input) 7363e1b5015SHenrik Rydberg { 73776f5902aSHenrik Rydberg input_mt_sync_frame(input); 73829cc309dSNicolas Boichat input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp); 7395519cab4SBenjamin Tissoires input_sync(input); 7405519cab4SBenjamin Tissoires td->num_received = 0; 74196098274SBenjamin Tissoires if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) 74296098274SBenjamin Tissoires set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 74396098274SBenjamin Tissoires else 74496098274SBenjamin Tissoires clear_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 74596098274SBenjamin Tissoires clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 7465519cab4SBenjamin Tissoires } 7475519cab4SBenjamin Tissoires 74829cc309dSNicolas Boichat static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field, 74929cc309dSNicolas Boichat __s32 value) 75029cc309dSNicolas Boichat { 75129cc309dSNicolas Boichat long delta = value - td->dev_time; 75229cc309dSNicolas Boichat unsigned long jdelta = jiffies_to_usecs(jiffies - td->jiffies); 75329cc309dSNicolas Boichat 75429cc309dSNicolas Boichat td->jiffies = jiffies; 75529cc309dSNicolas Boichat td->dev_time = value; 75629cc309dSNicolas Boichat 75729cc309dSNicolas Boichat if (delta < 0) 75829cc309dSNicolas Boichat delta += field->logical_maximum; 75929cc309dSNicolas Boichat 76029cc309dSNicolas Boichat /* HID_DG_SCANTIME is expressed in 100us, we want it in us. */ 76129cc309dSNicolas Boichat delta *= 100; 76229cc309dSNicolas Boichat 76329cc309dSNicolas Boichat if (jdelta > MAX_TIMESTAMP_INTERVAL) 76429cc309dSNicolas Boichat /* No data received for a while, resync the timestamp. */ 76529cc309dSNicolas Boichat return 0; 76629cc309dSNicolas Boichat else 76729cc309dSNicolas Boichat return td->timestamp + delta; 76829cc309dSNicolas Boichat } 76929cc309dSNicolas Boichat 770a69c5f8bSBenjamin Tissoires static int mt_touch_event(struct hid_device *hid, struct hid_field *field, 7715519cab4SBenjamin Tissoires struct hid_usage *usage, __s32 value) 7725519cab4SBenjamin Tissoires { 77355978fa9SBenjamin Tissoires /* we will handle the hidinput part later, now remains hiddev */ 77455978fa9SBenjamin Tissoires if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 77555978fa9SBenjamin Tissoires hid->hiddev_hid_event(hid, field, usage, value); 77655978fa9SBenjamin Tissoires 77755978fa9SBenjamin Tissoires return 1; 77855978fa9SBenjamin Tissoires } 77955978fa9SBenjamin Tissoires 78055978fa9SBenjamin Tissoires static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, 78155978fa9SBenjamin Tissoires struct hid_usage *usage, __s32 value) 78255978fa9SBenjamin Tissoires { 7835519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 784eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 7854c437555SBenjamin Tissoires struct input_dev *input = field->hidinput->input; 7865519cab4SBenjamin Tissoires 7873e1b5015SHenrik Rydberg if (hid->claimed & HID_CLAIMED_INPUT) { 7885519cab4SBenjamin Tissoires switch (usage->hid) { 7895519cab4SBenjamin Tissoires case HID_DG_INRANGE: 79020b60e6dSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_INRANGE) 7912d93666eSBenjamin Tissoires td->curvalid = value; 7929b3bb9b8SBenjamin Tissoires if (quirks & MT_QUIRK_HOVERING) 7939b3bb9b8SBenjamin Tissoires td->curdata.inrange_state = value; 7945519cab4SBenjamin Tissoires break; 7955519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 7962d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 7975519cab4SBenjamin Tissoires td->curvalid = value; 7985519cab4SBenjamin Tissoires td->curdata.touch_state = value; 7995519cab4SBenjamin Tissoires break; 8005519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 8016dd2e27aSAllen Hung if (quirks & MT_QUIRK_CONFIDENCE) 8026dd2e27aSAllen Hung td->curdata.confidence_state = value; 8032d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) 8042d93666eSBenjamin Tissoires td->curvalid = value; 8055519cab4SBenjamin Tissoires break; 8065519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 8075519cab4SBenjamin Tissoires td->curdata.contactid = value; 8085519cab4SBenjamin Tissoires break; 8095519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 8105519cab4SBenjamin Tissoires td->curdata.p = value; 8115519cab4SBenjamin Tissoires break; 8125519cab4SBenjamin Tissoires case HID_GD_X: 813349fd670SBenjamin Tissoires if (usage->code == ABS_MT_TOOL_X) 814349fd670SBenjamin Tissoires td->curdata.cx = value; 815349fd670SBenjamin Tissoires else 8165519cab4SBenjamin Tissoires td->curdata.x = value; 8175519cab4SBenjamin Tissoires break; 8185519cab4SBenjamin Tissoires case HID_GD_Y: 819349fd670SBenjamin Tissoires if (usage->code == ABS_MT_TOOL_Y) 820349fd670SBenjamin Tissoires td->curdata.cy = value; 821349fd670SBenjamin Tissoires else 8225519cab4SBenjamin Tissoires td->curdata.y = value; 8235519cab4SBenjamin Tissoires break; 8245519cab4SBenjamin Tissoires case HID_DG_WIDTH: 8255519cab4SBenjamin Tissoires td->curdata.w = value; 8265519cab4SBenjamin Tissoires break; 8275519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 8285519cab4SBenjamin Tissoires td->curdata.h = value; 8295519cab4SBenjamin Tissoires break; 83029cc309dSNicolas Boichat case HID_DG_SCANTIME: 83129cc309dSNicolas Boichat td->timestamp = mt_compute_timestamp(td, field, value); 83229cc309dSNicolas Boichat break; 8335519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 8345519cab4SBenjamin Tissoires break; 835c2ef8f21SBenjamin Tissoires case HID_DG_TOUCH: 836c2ef8f21SBenjamin Tissoires /* do nothing */ 837c2ef8f21SBenjamin Tissoires break; 8385519cab4SBenjamin Tissoires 8395519cab4SBenjamin Tissoires default: 8404c437555SBenjamin Tissoires if (usage->type) 8414c437555SBenjamin Tissoires input_event(input, usage->type, usage->code, 8424c437555SBenjamin Tissoires value); 84355978fa9SBenjamin Tissoires return; 8445519cab4SBenjamin Tissoires } 8455519cab4SBenjamin Tissoires 84654f4c0c3SBenjamin Tissoires if (usage->usage_index + 1 == field->report_count) { 84754f4c0c3SBenjamin Tissoires /* we only take into account the last report. */ 8482258e863SDenis Kovalev if (usage->hid == td->last_slot_field) 8493e1b5015SHenrik Rydberg mt_complete_slot(td, field->hidinput->input); 85054f4c0c3SBenjamin Tissoires } 8515519cab4SBenjamin Tissoires 8522d93666eSBenjamin Tissoires } 85355978fa9SBenjamin Tissoires } 8542d93666eSBenjamin Tissoires 855a69c5f8bSBenjamin Tissoires static void mt_touch_report(struct hid_device *hid, struct hid_report *report) 85655978fa9SBenjamin Tissoires { 85755978fa9SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 85855978fa9SBenjamin Tissoires struct hid_field *field; 85955978fa9SBenjamin Tissoires unsigned count; 86055978fa9SBenjamin Tissoires int r, n; 8615519cab4SBenjamin Tissoires 8624f4001bcSBenjamin Tissoires /* sticky fingers release in progress, abort */ 8634f4001bcSBenjamin Tissoires if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 8644f4001bcSBenjamin Tissoires return; 8654f4001bcSBenjamin Tissoires 866c2517f62SBenjamin Tissoires /* 867c2517f62SBenjamin Tissoires * Includes multi-packet support where subsequent 868c2517f62SBenjamin Tissoires * packets are sent with zero contactcount. 869c2517f62SBenjamin Tissoires */ 8707e3cc447SBenjamin Tissoires if (td->cc_index >= 0) { 8717e3cc447SBenjamin Tissoires struct hid_field *field = report->field[td->cc_index]; 8727e3cc447SBenjamin Tissoires int value = field->value[td->cc_value_index]; 8737e3cc447SBenjamin Tissoires if (value) 8747e3cc447SBenjamin Tissoires td->num_expected = value; 8757e3cc447SBenjamin Tissoires } 876c2517f62SBenjamin Tissoires 87755978fa9SBenjamin Tissoires for (r = 0; r < report->maxfield; r++) { 87855978fa9SBenjamin Tissoires field = report->field[r]; 87955978fa9SBenjamin Tissoires count = field->report_count; 88055978fa9SBenjamin Tissoires 88155978fa9SBenjamin Tissoires if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) 88255978fa9SBenjamin Tissoires continue; 88355978fa9SBenjamin Tissoires 88455978fa9SBenjamin Tissoires for (n = 0; n < count; n++) 88555978fa9SBenjamin Tissoires mt_process_mt_event(hid, field, &field->usage[n], 88655978fa9SBenjamin Tissoires field->value[n]); 88755978fa9SBenjamin Tissoires } 8885b62efd8SBenjamin Tissoires 8895b62efd8SBenjamin Tissoires if (td->num_received >= td->num_expected) 8905b62efd8SBenjamin Tissoires mt_sync_frame(td, report->field[0]->hidinput->input); 8914f4001bcSBenjamin Tissoires 8924f4001bcSBenjamin Tissoires /* 8934f4001bcSBenjamin Tissoires * Windows 8 specs says 2 things: 8944f4001bcSBenjamin Tissoires * - once a contact has been reported, it has to be reported in each 8954f4001bcSBenjamin Tissoires * subsequent report 8964f4001bcSBenjamin Tissoires * - the report rate when fingers are present has to be at least 8974f4001bcSBenjamin Tissoires * the refresh rate of the screen, 60 or 120 Hz 8984f4001bcSBenjamin Tissoires * 8994f4001bcSBenjamin Tissoires * I interprete this that the specification forces a report rate of 9004f4001bcSBenjamin Tissoires * at least 60 Hz for a touchscreen to be certified. 9014f4001bcSBenjamin Tissoires * Which means that if we do not get a report whithin 16 ms, either 9024f4001bcSBenjamin Tissoires * something wrong happens, either the touchscreen forgets to send 9034f4001bcSBenjamin Tissoires * a release. Taking a reasonable margin allows to remove issues 9044f4001bcSBenjamin Tissoires * with USB communication or the load of the machine. 9054f4001bcSBenjamin Tissoires * 9064f4001bcSBenjamin Tissoires * Given that Win 8 devices are forced to send a release, this will 9074f4001bcSBenjamin Tissoires * only affect laggish machines and the ones that have a firmware 9084f4001bcSBenjamin Tissoires * defect. 9094f4001bcSBenjamin Tissoires */ 91096098274SBenjamin Tissoires if (td->mtclass.quirks & MT_QUIRK_STICKY_FINGERS) { 91196098274SBenjamin Tissoires if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 91296098274SBenjamin Tissoires mod_timer(&td->release_timer, 91396098274SBenjamin Tissoires jiffies + msecs_to_jiffies(100)); 91496098274SBenjamin Tissoires else 91596098274SBenjamin Tissoires del_timer(&td->release_timer); 91696098274SBenjamin Tissoires } 9174f4001bcSBenjamin Tissoires 9184f4001bcSBenjamin Tissoires clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 9195519cab4SBenjamin Tissoires } 9205519cab4SBenjamin Tissoires 921b2c68a2fSDmitry Torokhov static int mt_touch_input_configured(struct hid_device *hdev, 922a69c5f8bSBenjamin Tissoires struct hid_input *hi) 923a69c5f8bSBenjamin Tissoires { 924a69c5f8bSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 925a69c5f8bSBenjamin Tissoires struct mt_class *cls = &td->mtclass; 926a69c5f8bSBenjamin Tissoires struct input_dev *input = hi->input; 927b2c68a2fSDmitry Torokhov int ret; 928a69c5f8bSBenjamin Tissoires 929a69c5f8bSBenjamin Tissoires if (!td->maxcontacts) 930a69c5f8bSBenjamin Tissoires td->maxcontacts = MT_DEFAULT_MAXCONTACT; 931a69c5f8bSBenjamin Tissoires 932a69c5f8bSBenjamin Tissoires mt_post_parse(td); 933a69c5f8bSBenjamin Tissoires if (td->serial_maybe) 934a69c5f8bSBenjamin Tissoires mt_post_parse_default_settings(td); 935a69c5f8bSBenjamin Tissoires 936a69c5f8bSBenjamin Tissoires if (cls->is_indirect) 937a69c5f8bSBenjamin Tissoires td->mt_flags |= INPUT_MT_POINTER; 938a69c5f8bSBenjamin Tissoires 939a69c5f8bSBenjamin Tissoires if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 940a69c5f8bSBenjamin Tissoires td->mt_flags |= INPUT_MT_DROP_UNUSED; 941a69c5f8bSBenjamin Tissoires 942015fdaa9SBenjamin Tissoires /* check for clickpads */ 943015fdaa9SBenjamin Tissoires if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1)) 9442c6e0277SSeth Forshee td->is_buttonpad = true; 9452c6e0277SSeth Forshee 9462c6e0277SSeth Forshee if (td->is_buttonpad) 947015fdaa9SBenjamin Tissoires __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 948015fdaa9SBenjamin Tissoires 949b2c68a2fSDmitry Torokhov ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags); 950b2c68a2fSDmitry Torokhov if (ret) 951b2c68a2fSDmitry Torokhov return ret; 952a69c5f8bSBenjamin Tissoires 953a69c5f8bSBenjamin Tissoires td->mt_flags = 0; 954b2c68a2fSDmitry Torokhov return 0; 955a69c5f8bSBenjamin Tissoires } 956a69c5f8bSBenjamin Tissoires 957957b8dffSJoão Paulo Rechi Vita #define mt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \ 958957b8dffSJoão Paulo Rechi Vita max, EV_KEY, (c)) 959a69c5f8bSBenjamin Tissoires static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 960a69c5f8bSBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 961a69c5f8bSBenjamin Tissoires unsigned long **bit, int *max) 962a69c5f8bSBenjamin Tissoires { 9636aef704eSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 9646aef704eSBenjamin Tissoires 9656aef704eSBenjamin Tissoires /* 9666aef704eSBenjamin Tissoires * If mtclass.export_all_inputs is not set, only map fields from 9676aef704eSBenjamin Tissoires * TouchScreen or TouchPad collections. We need to ignore fields 9686aef704eSBenjamin Tissoires * that belong to other collections such as Mouse that might have 9696aef704eSBenjamin Tissoires * the same GenericDesktop usages. 9706aef704eSBenjamin Tissoires */ 9716aef704eSBenjamin Tissoires if (!td->mtclass.export_all_inputs && 9726aef704eSBenjamin Tissoires field->application != HID_DG_TOUCHSCREEN && 973fa11aa72SBenjamin Tissoires field->application != HID_DG_PEN && 9748fe89ef0SBenjamin Tissoires field->application != HID_DG_TOUCHPAD && 9758fe89ef0SBenjamin Tissoires field->application != HID_GD_KEYBOARD && 976e57f4e67SHans de Goede field->application != HID_GD_SYSTEM_CONTROL && 9771fbf74efSJoão Paulo Rechi Vita field->application != HID_CP_CONSUMER_CONTROL && 978957b8dffSJoão Paulo Rechi Vita field->application != HID_GD_WIRELESS_RADIO_CTLS && 979957b8dffSJoão Paulo Rechi Vita !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 980957b8dffSJoão Paulo Rechi Vita td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP)) 9816f492f28SBenjamin Tissoires return -1; 982a69c5f8bSBenjamin Tissoires 9836aef704eSBenjamin Tissoires /* 984957b8dffSJoão Paulo Rechi Vita * Some Asus keyboard+touchpad devices have the hotkeys defined in the 985957b8dffSJoão Paulo Rechi Vita * touchpad report descriptor. We need to treat these as an array to 986957b8dffSJoão Paulo Rechi Vita * map usages to input keys. 987957b8dffSJoão Paulo Rechi Vita */ 98839bbf402SJiri Kosina if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 989957b8dffSJoão Paulo Rechi Vita td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP && 990957b8dffSJoão Paulo Rechi Vita (usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) { 991957b8dffSJoão Paulo Rechi Vita set_bit(EV_REP, hi->input->evbit); 992957b8dffSJoão Paulo Rechi Vita if (field->flags & HID_MAIN_ITEM_VARIABLE) 993957b8dffSJoão Paulo Rechi Vita field->flags &= ~HID_MAIN_ITEM_VARIABLE; 994957b8dffSJoão Paulo Rechi Vita switch (usage->hid & HID_USAGE) { 995957b8dffSJoão Paulo Rechi Vita case 0x10: mt_map_key_clear(KEY_BRIGHTNESSDOWN); break; 996957b8dffSJoão Paulo Rechi Vita case 0x20: mt_map_key_clear(KEY_BRIGHTNESSUP); break; 997957b8dffSJoão Paulo Rechi Vita case 0x35: mt_map_key_clear(KEY_DISPLAY_OFF); break; 998957b8dffSJoão Paulo Rechi Vita case 0x6b: mt_map_key_clear(KEY_F21); break; 999957b8dffSJoão Paulo Rechi Vita case 0x6c: mt_map_key_clear(KEY_SLEEP); break; 1000957b8dffSJoão Paulo Rechi Vita default: 1001957b8dffSJoão Paulo Rechi Vita return -1; 1002957b8dffSJoão Paulo Rechi Vita } 1003957b8dffSJoão Paulo Rechi Vita return 1; 1004957b8dffSJoão Paulo Rechi Vita } 1005957b8dffSJoão Paulo Rechi Vita 1006957b8dffSJoão Paulo Rechi Vita /* 10076aef704eSBenjamin Tissoires * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" 10086aef704eSBenjamin Tissoires * for the stylus. 10091cc1cc92SBrent Adam * The check for mt_report_id ensures we don't process 10101cc1cc92SBrent Adam * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical 10111cc1cc92SBrent Adam * collection, but within the report ID. 10126aef704eSBenjamin Tissoires */ 1013a69c5f8bSBenjamin Tissoires if (field->physical == HID_DG_STYLUS) 1014e55f6200SBenjamin Tissoires return 0; 10151cc1cc92SBrent Adam else if ((field->physical == 0) && 10161cc1cc92SBrent Adam (field->report->id != td->mt_report_id) && 10171cc1cc92SBrent Adam (td->mt_report_id != -1)) 10181cc1cc92SBrent Adam return 0; 1019a69c5f8bSBenjamin Tissoires 10206aef704eSBenjamin Tissoires if (field->application == HID_DG_TOUCHSCREEN || 10216aef704eSBenjamin Tissoires field->application == HID_DG_TOUCHPAD) 1022a69c5f8bSBenjamin Tissoires return mt_touch_input_mapping(hdev, hi, field, usage, bit, max); 10236aef704eSBenjamin Tissoires 10246aef704eSBenjamin Tissoires /* let hid-core decide for the others */ 10256aef704eSBenjamin Tissoires return 0; 1026a69c5f8bSBenjamin Tissoires } 1027a69c5f8bSBenjamin Tissoires 1028a69c5f8bSBenjamin Tissoires static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, 1029a69c5f8bSBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 1030a69c5f8bSBenjamin Tissoires unsigned long **bit, int *max) 1031a69c5f8bSBenjamin Tissoires { 10326aef704eSBenjamin Tissoires /* 10336aef704eSBenjamin Tissoires * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" 10346aef704eSBenjamin Tissoires * for the stylus. 10356aef704eSBenjamin Tissoires */ 1036fa11aa72SBenjamin Tissoires if (field->physical == HID_DG_STYLUS) 1037e55f6200SBenjamin Tissoires return 0; 1038fa11aa72SBenjamin Tissoires 10396aef704eSBenjamin Tissoires if (field->application == HID_DG_TOUCHSCREEN || 10404cf56a89SDmitry Torokhov field->application == HID_DG_TOUCHPAD) { 10414cf56a89SDmitry Torokhov /* We own these mappings, tell hid-input to ignore them */ 10424cf56a89SDmitry Torokhov return -1; 10434cf56a89SDmitry Torokhov } 10446aef704eSBenjamin Tissoires 10456aef704eSBenjamin Tissoires /* let hid-core decide for the others */ 10466aef704eSBenjamin Tissoires return 0; 1047a69c5f8bSBenjamin Tissoires } 1048a69c5f8bSBenjamin Tissoires 1049a69c5f8bSBenjamin Tissoires static int mt_event(struct hid_device *hid, struct hid_field *field, 1050a69c5f8bSBenjamin Tissoires struct hid_usage *usage, __s32 value) 1051a69c5f8bSBenjamin Tissoires { 1052a69c5f8bSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 1053a69c5f8bSBenjamin Tissoires 1054a69c5f8bSBenjamin Tissoires if (field->report->id == td->mt_report_id) 1055a69c5f8bSBenjamin Tissoires return mt_touch_event(hid, field, usage, value); 1056a69c5f8bSBenjamin Tissoires 1057e55f6200SBenjamin Tissoires return 0; 1058a69c5f8bSBenjamin Tissoires } 1059a69c5f8bSBenjamin Tissoires 1060a69c5f8bSBenjamin Tissoires static void mt_report(struct hid_device *hid, struct hid_report *report) 1061a69c5f8bSBenjamin Tissoires { 1062a69c5f8bSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 1063e55f6200SBenjamin Tissoires struct hid_field *field = report->field[0]; 1064a69c5f8bSBenjamin Tissoires 1065a69c5f8bSBenjamin Tissoires if (!(hid->claimed & HID_CLAIMED_INPUT)) 1066a69c5f8bSBenjamin Tissoires return; 1067a69c5f8bSBenjamin Tissoires 1068a69c5f8bSBenjamin Tissoires if (report->id == td->mt_report_id) 1069e55f6200SBenjamin Tissoires return mt_touch_report(hid, report); 1070fa11aa72SBenjamin Tissoires 1071e55f6200SBenjamin Tissoires if (field && field->hidinput && field->hidinput->input) 1072e55f6200SBenjamin Tissoires input_sync(field->hidinput->input); 10735519cab4SBenjamin Tissoires } 10745519cab4SBenjamin Tissoires 10755519cab4SBenjamin Tissoires static void mt_set_input_mode(struct hid_device *hdev) 10765519cab4SBenjamin Tissoires { 10775519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 10785519cab4SBenjamin Tissoires struct hid_report *r; 10795519cab4SBenjamin Tissoires struct hid_report_enum *re; 1080da10bc25SMathieu Magnaudet struct mt_class *cls = &td->mtclass; 1081da10bc25SMathieu Magnaudet char *buf; 1082da10bc25SMathieu Magnaudet int report_len; 10835519cab4SBenjamin Tissoires 10845519cab4SBenjamin Tissoires if (td->inputmode < 0) 10855519cab4SBenjamin Tissoires return; 10865519cab4SBenjamin Tissoires 10875519cab4SBenjamin Tissoires re = &(hdev->report_enum[HID_FEATURE_REPORT]); 10885519cab4SBenjamin Tissoires r = re->report_id_hash[td->inputmode]; 10895519cab4SBenjamin Tissoires if (r) { 1090da10bc25SMathieu Magnaudet if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) { 1091dabb05c6SMathieu Magnaudet report_len = hid_report_len(r); 1092da10bc25SMathieu Magnaudet buf = hid_alloc_report_buf(r, GFP_KERNEL); 1093da10bc25SMathieu Magnaudet if (!buf) { 1094da10bc25SMathieu Magnaudet hid_err(hdev, "failed to allocate buffer for report\n"); 1095da10bc25SMathieu Magnaudet return; 1096da10bc25SMathieu Magnaudet } 1097da10bc25SMathieu Magnaudet hid_hw_raw_request(hdev, r->id, buf, report_len, 1098da10bc25SMathieu Magnaudet HID_FEATURE_REPORT, 1099da10bc25SMathieu Magnaudet HID_REQ_GET_REPORT); 1100da10bc25SMathieu Magnaudet kfree(buf); 1101da10bc25SMathieu Magnaudet } 11029abebedbSAndrew Duggan r->field[0]->value[td->inputmode_index] = td->inputmode_value; 1103d8814272SBenjamin Tissoires hid_hw_request(hdev, r, HID_REQ_SET_REPORT); 11045519cab4SBenjamin Tissoires } 11055519cab4SBenjamin Tissoires } 11065519cab4SBenjamin Tissoires 110731ae9bddSBenjamin Tissoires static void mt_set_maxcontacts(struct hid_device *hdev) 110831ae9bddSBenjamin Tissoires { 110931ae9bddSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 111031ae9bddSBenjamin Tissoires struct hid_report *r; 111131ae9bddSBenjamin Tissoires struct hid_report_enum *re; 111231ae9bddSBenjamin Tissoires int fieldmax, max; 111331ae9bddSBenjamin Tissoires 111431ae9bddSBenjamin Tissoires if (td->maxcontact_report_id < 0) 111531ae9bddSBenjamin Tissoires return; 111631ae9bddSBenjamin Tissoires 111731ae9bddSBenjamin Tissoires if (!td->mtclass.maxcontacts) 111831ae9bddSBenjamin Tissoires return; 111931ae9bddSBenjamin Tissoires 112031ae9bddSBenjamin Tissoires re = &hdev->report_enum[HID_FEATURE_REPORT]; 112131ae9bddSBenjamin Tissoires r = re->report_id_hash[td->maxcontact_report_id]; 112231ae9bddSBenjamin Tissoires if (r) { 112331ae9bddSBenjamin Tissoires max = td->mtclass.maxcontacts; 112431ae9bddSBenjamin Tissoires fieldmax = r->field[0]->logical_maximum; 112531ae9bddSBenjamin Tissoires max = min(fieldmax, max); 112631ae9bddSBenjamin Tissoires if (r->field[0]->value[0] != max) { 112731ae9bddSBenjamin Tissoires r->field[0]->value[0] = max; 1128d8814272SBenjamin Tissoires hid_hw_request(hdev, r, HID_REQ_SET_REPORT); 112931ae9bddSBenjamin Tissoires } 113031ae9bddSBenjamin Tissoires } 113131ae9bddSBenjamin Tissoires } 113231ae9bddSBenjamin Tissoires 11334fa3a583SHenrik Rydberg static void mt_post_parse_default_settings(struct mt_device *td) 11344fa3a583SHenrik Rydberg { 11354fa3a583SHenrik Rydberg __s32 quirks = td->mtclass.quirks; 11364fa3a583SHenrik Rydberg 11374fa3a583SHenrik Rydberg /* unknown serial device needs special quirks */ 11384fa3a583SHenrik Rydberg if (td->touches_by_report == 1) { 11394fa3a583SHenrik Rydberg quirks |= MT_QUIRK_ALWAYS_VALID; 11404fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; 11414fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_INRANGE; 11424fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; 1143e0bb8f9aSBenjamin Tissoires quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 11444fa3a583SHenrik Rydberg } 11454fa3a583SHenrik Rydberg 11464fa3a583SHenrik Rydberg td->mtclass.quirks = quirks; 11474fa3a583SHenrik Rydberg } 11484fa3a583SHenrik Rydberg 11493ac36d15SBenjamin Tissoires static void mt_post_parse(struct mt_device *td) 11503ac36d15SBenjamin Tissoires { 11513ac36d15SBenjamin Tissoires struct mt_fields *f = td->fields; 1152c2517f62SBenjamin Tissoires struct mt_class *cls = &td->mtclass; 11533ac36d15SBenjamin Tissoires 11543ac36d15SBenjamin Tissoires if (td->touches_by_report > 0) { 11553ac36d15SBenjamin Tissoires int field_count_per_touch = f->length / td->touches_by_report; 11563ac36d15SBenjamin Tissoires td->last_slot_field = f->usages[field_count_per_touch - 1]; 11573ac36d15SBenjamin Tissoires } 1158c2517f62SBenjamin Tissoires 11597e3cc447SBenjamin Tissoires if (td->cc_index < 0) 1160c2517f62SBenjamin Tissoires cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 11613ac36d15SBenjamin Tissoires } 11623ac36d15SBenjamin Tissoires 1163b2c68a2fSDmitry Torokhov static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) 116476f5902aSHenrik Rydberg { 116576f5902aSHenrik Rydberg struct mt_device *td = hid_get_drvdata(hdev); 1166c08d46aaSBenjamin Tissoires char *name; 1167c08d46aaSBenjamin Tissoires const char *suffix = NULL; 11686aef704eSBenjamin Tissoires struct hid_field *field = hi->report->field[0]; 1169b2c68a2fSDmitry Torokhov int ret; 117076f5902aSHenrik Rydberg 1171b2c68a2fSDmitry Torokhov if (hi->report->id == td->mt_report_id) { 1172b2c68a2fSDmitry Torokhov ret = mt_touch_input_configured(hdev, hi); 1173b2c68a2fSDmitry Torokhov if (ret) 1174b2c68a2fSDmitry Torokhov return ret; 1175b2c68a2fSDmitry Torokhov } 117676f5902aSHenrik Rydberg 11776aef704eSBenjamin Tissoires /* 11786aef704eSBenjamin Tissoires * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" 11796aef704eSBenjamin Tissoires * for the stylus. Check this first, and then rely on the application 11806aef704eSBenjamin Tissoires * field. 11816aef704eSBenjamin Tissoires */ 1182c08d46aaSBenjamin Tissoires if (hi->report->field[0]->physical == HID_DG_STYLUS) { 1183c08d46aaSBenjamin Tissoires suffix = "Pen"; 1184e55f6200SBenjamin Tissoires /* force BTN_STYLUS to allow tablet matching in udev */ 1185e55f6200SBenjamin Tissoires __set_bit(BTN_STYLUS, hi->input->keybit); 11866aef704eSBenjamin Tissoires } else { 11876aef704eSBenjamin Tissoires switch (field->application) { 11886aef704eSBenjamin Tissoires case HID_GD_KEYBOARD: 11896aef704eSBenjamin Tissoires suffix = "Keyboard"; 11906aef704eSBenjamin Tissoires break; 11916aef704eSBenjamin Tissoires case HID_GD_KEYPAD: 11926aef704eSBenjamin Tissoires suffix = "Keypad"; 11936aef704eSBenjamin Tissoires break; 11946aef704eSBenjamin Tissoires case HID_GD_MOUSE: 11956aef704eSBenjamin Tissoires suffix = "Mouse"; 11966aef704eSBenjamin Tissoires break; 11976aef704eSBenjamin Tissoires case HID_DG_STYLUS: 11986aef704eSBenjamin Tissoires suffix = "Pen"; 11996aef704eSBenjamin Tissoires /* force BTN_STYLUS to allow tablet matching in udev */ 12006aef704eSBenjamin Tissoires __set_bit(BTN_STYLUS, hi->input->keybit); 12016aef704eSBenjamin Tissoires break; 12026aef704eSBenjamin Tissoires case HID_DG_TOUCHSCREEN: 12036aef704eSBenjamin Tissoires /* we do not set suffix = "Touchscreen" */ 12046aef704eSBenjamin Tissoires break; 1205dc425a1cSMika Westerberg case HID_DG_TOUCHPAD: 1206dc425a1cSMika Westerberg suffix = "Touchpad"; 1207dc425a1cSMika Westerberg break; 12086aef704eSBenjamin Tissoires case HID_GD_SYSTEM_CONTROL: 12096aef704eSBenjamin Tissoires suffix = "System Control"; 12106aef704eSBenjamin Tissoires break; 12116aef704eSBenjamin Tissoires case HID_CP_CONSUMER_CONTROL: 12126aef704eSBenjamin Tissoires suffix = "Consumer Control"; 12136aef704eSBenjamin Tissoires break; 12141fbf74efSJoão Paulo Rechi Vita case HID_GD_WIRELESS_RADIO_CTLS: 12151fbf74efSJoão Paulo Rechi Vita suffix = "Wireless Radio Control"; 12161fbf74efSJoão Paulo Rechi Vita break; 1217957b8dffSJoão Paulo Rechi Vita case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: 1218957b8dffSJoão Paulo Rechi Vita suffix = "Custom Media Keys"; 1219957b8dffSJoão Paulo Rechi Vita break; 12206aef704eSBenjamin Tissoires default: 12216aef704eSBenjamin Tissoires suffix = "UNKNOWN"; 12226aef704eSBenjamin Tissoires break; 12236aef704eSBenjamin Tissoires } 122476f5902aSHenrik Rydberg } 122576f5902aSHenrik Rydberg 1226c08d46aaSBenjamin Tissoires if (suffix) { 1227c08d46aaSBenjamin Tissoires name = devm_kzalloc(&hi->input->dev, 1228c08d46aaSBenjamin Tissoires strlen(hdev->name) + strlen(suffix) + 2, 1229c08d46aaSBenjamin Tissoires GFP_KERNEL); 1230c08d46aaSBenjamin Tissoires if (name) { 1231c08d46aaSBenjamin Tissoires sprintf(name, "%s %s", hdev->name, suffix); 1232c08d46aaSBenjamin Tissoires hi->input->name = name; 1233c08d46aaSBenjamin Tissoires } 1234c08d46aaSBenjamin Tissoires } 1235b2c68a2fSDmitry Torokhov 1236b2c68a2fSDmitry Torokhov return 0; 1237c08d46aaSBenjamin Tissoires } 1238c08d46aaSBenjamin Tissoires 1239f3287a99SBenjamin Tissoires static void mt_fix_const_field(struct hid_field *field, unsigned int usage) 1240f3287a99SBenjamin Tissoires { 1241f3287a99SBenjamin Tissoires if (field->usage[0].hid != usage || 1242f3287a99SBenjamin Tissoires !(field->flags & HID_MAIN_ITEM_CONSTANT)) 1243f3287a99SBenjamin Tissoires return; 1244f3287a99SBenjamin Tissoires 1245f3287a99SBenjamin Tissoires field->flags &= ~HID_MAIN_ITEM_CONSTANT; 1246f3287a99SBenjamin Tissoires field->flags |= HID_MAIN_ITEM_VARIABLE; 1247f3287a99SBenjamin Tissoires } 1248f3287a99SBenjamin Tissoires 1249f3287a99SBenjamin Tissoires static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage) 1250f3287a99SBenjamin Tissoires { 1251f3287a99SBenjamin Tissoires struct hid_report *report; 1252f3287a99SBenjamin Tissoires int i; 1253f3287a99SBenjamin Tissoires 1254f3287a99SBenjamin Tissoires list_for_each_entry(report, 1255f3287a99SBenjamin Tissoires &hdev->report_enum[HID_INPUT_REPORT].report_list, 1256f3287a99SBenjamin Tissoires list) { 1257f3287a99SBenjamin Tissoires 1258f3287a99SBenjamin Tissoires if (!report->maxfield) 1259f3287a99SBenjamin Tissoires continue; 1260f3287a99SBenjamin Tissoires 1261f3287a99SBenjamin Tissoires for (i = 0; i < report->maxfield; i++) 1262f3287a99SBenjamin Tissoires if (report->field[i]->maxusage >= 1) 1263f3287a99SBenjamin Tissoires mt_fix_const_field(report->field[i], usage); 1264f3287a99SBenjamin Tissoires } 1265f3287a99SBenjamin Tissoires } 1266f3287a99SBenjamin Tissoires 12674f4001bcSBenjamin Tissoires static void mt_release_contacts(struct hid_device *hid) 12684f4001bcSBenjamin Tissoires { 12694f4001bcSBenjamin Tissoires struct hid_input *hidinput; 12704f4001bcSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 12714f4001bcSBenjamin Tissoires 12724f4001bcSBenjamin Tissoires list_for_each_entry(hidinput, &hid->inputs, list) { 12734f4001bcSBenjamin Tissoires struct input_dev *input_dev = hidinput->input; 12744f4001bcSBenjamin Tissoires struct input_mt *mt = input_dev->mt; 12754f4001bcSBenjamin Tissoires int i; 12764f4001bcSBenjamin Tissoires 12774f4001bcSBenjamin Tissoires if (mt) { 12784f4001bcSBenjamin Tissoires for (i = 0; i < mt->num_slots; i++) { 12794f4001bcSBenjamin Tissoires input_mt_slot(input_dev, i); 12804f4001bcSBenjamin Tissoires input_mt_report_slot_state(input_dev, 12814f4001bcSBenjamin Tissoires MT_TOOL_FINGER, 12824f4001bcSBenjamin Tissoires false); 12834f4001bcSBenjamin Tissoires } 12844f4001bcSBenjamin Tissoires input_mt_sync_frame(input_dev); 12854f4001bcSBenjamin Tissoires input_sync(input_dev); 12864f4001bcSBenjamin Tissoires } 12874f4001bcSBenjamin Tissoires } 12884f4001bcSBenjamin Tissoires 12894f4001bcSBenjamin Tissoires td->num_received = 0; 12904f4001bcSBenjamin Tissoires } 12914f4001bcSBenjamin Tissoires 12920ee32774SKees Cook static void mt_expired_timeout(struct timer_list *t) 12934f4001bcSBenjamin Tissoires { 12940ee32774SKees Cook struct mt_device *td = from_timer(td, t, release_timer); 12950ee32774SKees Cook struct hid_device *hdev = td->hdev; 12964f4001bcSBenjamin Tissoires 12974f4001bcSBenjamin Tissoires /* 12984f4001bcSBenjamin Tissoires * An input report came in just before we release the sticky fingers, 12994f4001bcSBenjamin Tissoires * it will take care of the sticky fingers. 13004f4001bcSBenjamin Tissoires */ 13014f4001bcSBenjamin Tissoires if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 13024f4001bcSBenjamin Tissoires return; 130396098274SBenjamin Tissoires if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 13044f4001bcSBenjamin Tissoires mt_release_contacts(hdev); 13054f4001bcSBenjamin Tissoires clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 13064f4001bcSBenjamin Tissoires } 13074f4001bcSBenjamin Tissoires 13085519cab4SBenjamin Tissoires static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 13095519cab4SBenjamin Tissoires { 13102d93666eSBenjamin Tissoires int ret, i; 13115519cab4SBenjamin Tissoires struct mt_device *td; 13122d93666eSBenjamin Tissoires struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ 13132d93666eSBenjamin Tissoires 13142d93666eSBenjamin Tissoires for (i = 0; mt_classes[i].name ; i++) { 13152d93666eSBenjamin Tissoires if (id->driver_data == mt_classes[i].name) { 13162d93666eSBenjamin Tissoires mtclass = &(mt_classes[i]); 13172d93666eSBenjamin Tissoires break; 13182d93666eSBenjamin Tissoires } 13192d93666eSBenjamin Tissoires } 13205519cab4SBenjamin Tissoires 1321c08d46aaSBenjamin Tissoires td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); 13225519cab4SBenjamin Tissoires if (!td) { 13235519cab4SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch data\n"); 13245519cab4SBenjamin Tissoires return -ENOMEM; 13255519cab4SBenjamin Tissoires } 13260ee32774SKees Cook td->hdev = hdev; 1327eec29e3dSBenjamin Tissoires td->mtclass = *mtclass; 13285519cab4SBenjamin Tissoires td->inputmode = -1; 132931ae9bddSBenjamin Tissoires td->maxcontact_report_id = -1; 13309abebedbSAndrew Duggan td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; 13317e3cc447SBenjamin Tissoires td->cc_index = -1; 1332fa11aa72SBenjamin Tissoires td->mt_report_id = -1; 13335519cab4SBenjamin Tissoires hid_set_drvdata(hdev, td); 13345519cab4SBenjamin Tissoires 1335c08d46aaSBenjamin Tissoires td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields), 1336c08d46aaSBenjamin Tissoires GFP_KERNEL); 13373ac36d15SBenjamin Tissoires if (!td->fields) { 13383ac36d15SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch fields data\n"); 1339c08d46aaSBenjamin Tissoires return -ENOMEM; 13403ac36d15SBenjamin Tissoires } 13413ac36d15SBenjamin Tissoires 134276f5902aSHenrik Rydberg if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) 134376f5902aSHenrik Rydberg td->serial_maybe = true; 134476f5902aSHenrik Rydberg 1345b897f6dbSBenjamin Tissoires /* 1346b897f6dbSBenjamin Tissoires * Store the initial quirk state 1347b897f6dbSBenjamin Tissoires */ 1348b897f6dbSBenjamin Tissoires td->initial_quirks = hdev->quirks; 1349b897f6dbSBenjamin Tissoires 1350b897f6dbSBenjamin Tissoires /* This allows the driver to correctly support devices 1351b897f6dbSBenjamin Tissoires * that emit events over several HID messages. 1352b897f6dbSBenjamin Tissoires */ 1353b897f6dbSBenjamin Tissoires hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 1354b897f6dbSBenjamin Tissoires 1355b897f6dbSBenjamin Tissoires /* 1356b897f6dbSBenjamin Tissoires * This allows the driver to handle different input sensors 1357b897f6dbSBenjamin Tissoires * that emits events through different reports on the same HID 1358b897f6dbSBenjamin Tissoires * device. 1359b897f6dbSBenjamin Tissoires */ 1360b897f6dbSBenjamin Tissoires hdev->quirks |= HID_QUIRK_MULTI_INPUT; 1361b897f6dbSBenjamin Tissoires hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; 1362b897f6dbSBenjamin Tissoires 1363b897f6dbSBenjamin Tissoires /* 1364b897f6dbSBenjamin Tissoires * Some multitouch screens do not like to be polled for input 1365b897f6dbSBenjamin Tissoires * reports. Fortunately, the Win8 spec says that all touches 1366b897f6dbSBenjamin Tissoires * should be sent during each report, making the initialization 1367b897f6dbSBenjamin Tissoires * of input reports unnecessary. For Win7 devices, well, let's hope 1368b897f6dbSBenjamin Tissoires * they will still be happy (this is only be a problem if a touch 1369b897f6dbSBenjamin Tissoires * was already there while probing the device). 1370b897f6dbSBenjamin Tissoires * 1371b897f6dbSBenjamin Tissoires * In addition some touchpads do not behave well if we read 1372b897f6dbSBenjamin Tissoires * all feature reports from them. Instead we prevent 1373b897f6dbSBenjamin Tissoires * initial report fetching and then selectively fetch each 1374b897f6dbSBenjamin Tissoires * report we are interested in. 1375b897f6dbSBenjamin Tissoires */ 1376b897f6dbSBenjamin Tissoires hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; 1377b897f6dbSBenjamin Tissoires 13780ee32774SKees Cook timer_setup(&td->release_timer, mt_expired_timeout, 0); 13794f4001bcSBenjamin Tissoires 13805519cab4SBenjamin Tissoires ret = hid_parse(hdev); 13815519cab4SBenjamin Tissoires if (ret != 0) 1382c08d46aaSBenjamin Tissoires return ret; 13835519cab4SBenjamin Tissoires 1384f3287a99SBenjamin Tissoires if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) 1385f3287a99SBenjamin Tissoires mt_fix_const_fields(hdev, HID_DG_CONTACTID); 1386f3287a99SBenjamin Tissoires 13875519cab4SBenjamin Tissoires ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 13882d93666eSBenjamin Tissoires if (ret) 1389c08d46aaSBenjamin Tissoires return ret; 13905519cab4SBenjamin Tissoires 1391eec29e3dSBenjamin Tissoires ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); 13920c4b3c63SNicholas Krause if (ret) 13930c4b3c63SNicholas Krause dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n", 13940c4b3c63SNicholas Krause hdev->name); 1395eec29e3dSBenjamin Tissoires 139631ae9bddSBenjamin Tissoires mt_set_maxcontacts(hdev); 13975519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 13985519cab4SBenjamin Tissoires 1399c08d46aaSBenjamin Tissoires /* release .fields memory as it is not used anymore */ 1400c08d46aaSBenjamin Tissoires devm_kfree(&hdev->dev, td->fields); 14013ac36d15SBenjamin Tissoires td->fields = NULL; 14023ac36d15SBenjamin Tissoires 14035519cab4SBenjamin Tissoires return 0; 14045519cab4SBenjamin Tissoires } 14055519cab4SBenjamin Tissoires 14065519cab4SBenjamin Tissoires #ifdef CONFIG_PM 14075519cab4SBenjamin Tissoires static int mt_reset_resume(struct hid_device *hdev) 14085519cab4SBenjamin Tissoires { 1409d3e69b9aSBenson Leung mt_release_contacts(hdev); 141031ae9bddSBenjamin Tissoires mt_set_maxcontacts(hdev); 14115519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 14125519cab4SBenjamin Tissoires return 0; 14135519cab4SBenjamin Tissoires } 1414dfeefd10SScott Liu 1415dfeefd10SScott Liu static int mt_resume(struct hid_device *hdev) 1416dfeefd10SScott Liu { 1417dfeefd10SScott Liu /* Some Elan legacy devices require SET_IDLE to be set on resume. 1418dfeefd10SScott Liu * It should be safe to send it to other devices too. 1419dfeefd10SScott Liu * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ 1420dfeefd10SScott Liu 14214ba25d3fSBenjamin Tissoires hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE); 1422dfeefd10SScott Liu 1423dfeefd10SScott Liu return 0; 1424dfeefd10SScott Liu } 14255519cab4SBenjamin Tissoires #endif 14265519cab4SBenjamin Tissoires 14275519cab4SBenjamin Tissoires static void mt_remove(struct hid_device *hdev) 14285519cab4SBenjamin Tissoires { 1429b897f6dbSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 1430b897f6dbSBenjamin Tissoires 14314f4001bcSBenjamin Tissoires del_timer_sync(&td->release_timer); 14324f4001bcSBenjamin Tissoires 1433eec29e3dSBenjamin Tissoires sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); 14345939212dSBenjamin Tissoires hid_hw_stop(hdev); 1435b897f6dbSBenjamin Tissoires hdev->quirks = td->initial_quirks; 14365519cab4SBenjamin Tissoires } 14375519cab4SBenjamin Tissoires 14380fa9c616SBenjamin Tissoires /* 14390fa9c616SBenjamin Tissoires * This list contains only: 14400fa9c616SBenjamin Tissoires * - VID/PID of products not working with the default multitouch handling 14410fa9c616SBenjamin Tissoires * - 2 generic rules. 14420fa9c616SBenjamin Tissoires * So there is no point in adding here any device with MT_CLS_DEFAULT. 14430fa9c616SBenjamin Tissoires */ 14445519cab4SBenjamin Tissoires static const struct hid_device_id mt_devices[] = { 14455519cab4SBenjamin Tissoires 1446f786bba4SBenjamin Tissoires /* 3M panels */ 1447f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 14482c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 1449f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M1968) }, 1450f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 14512c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 1452f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M2256) }, 1453c4fad877SBenjamin Tissoires { .driver_data = MT_CLS_3M, 14542c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 1455c4fad877SBenjamin Tissoires USB_DEVICE_ID_3M3266) }, 1456f786bba4SBenjamin Tissoires 1457504c932cSMasaki Ota /* Alps devices */ 1458504c932cSMasaki Ota { .driver_data = MT_CLS_WIN_8_DUAL, 1459504c932cSMasaki Ota HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 1460504c932cSMasaki Ota USB_VENDOR_ID_ALPS_JP, 1461504c932cSMasaki Ota HID_DEVICE_ID_ALPS_U1_DUAL_PTP) }, 1462504c932cSMasaki Ota { .driver_data = MT_CLS_WIN_8_DUAL, 1463504c932cSMasaki Ota HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 1464504c932cSMasaki Ota USB_VENDOR_ID_ALPS_JP, 1465504c932cSMasaki Ota HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) }, 1466504c932cSMasaki Ota 146756d859e1SPavel Tatashin /* Lenovo X1 TAB Gen 2 */ 146856d859e1SPavel Tatashin { .driver_data = MT_CLS_WIN_8_DUAL, 146956d859e1SPavel Tatashin HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 147056d859e1SPavel Tatashin USB_VENDOR_ID_LENOVO, 147156d859e1SPavel Tatashin USB_DEVICE_ID_LENOVO_X1_TAB) }, 147256d859e1SPavel Tatashin 14736aef704eSBenjamin Tissoires /* Anton devices */ 14746aef704eSBenjamin Tissoires { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, 14756aef704eSBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_ANTON, 14766aef704eSBenjamin Tissoires USB_DEVICE_ID_ANTON_TOUCH_PAD) }, 1477e6aac342SBenjamin Tissoires 1478957b8dffSJoão Paulo Rechi Vita /* Asus T304UA */ 1479957b8dffSJoão Paulo Rechi Vita { .driver_data = MT_CLS_ASUS, 1480957b8dffSJoão Paulo Rechi Vita HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 1481957b8dffSJoão Paulo Rechi Vita USB_VENDOR_ID_ASUSTEK, 1482957b8dffSJoão Paulo Rechi Vita USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD) }, 1483957b8dffSJoão Paulo Rechi Vita 1484b1057124SBenjamin Tissoires /* Atmel panels */ 1485b1057124SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 14862c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 1487841cb157SBenjamin Tissoires USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, 1488b1057124SBenjamin Tissoires 14899ed32695SJiri Kosina /* Baanto multitouch devices */ 1490dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 149116b79bb8SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, 14929ed32695SJiri Kosina USB_DEVICE_ID_BAANTO_MT_190W2) }, 14930fa9c616SBenjamin Tissoires 1494a841b62cSBenjamin Tissoires /* Cando panels */ 1495a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 14962c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 1497a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, 1498a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 14992c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 1500a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, 1501a841b62cSBenjamin Tissoires 1502942fd422SAustin Zhang /* Chunghwa Telecom touch panels */ 1503dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 15042c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, 1505942fd422SAustin Zhang USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, 1506942fd422SAustin Zhang 1507070f63b4SYang Bo /* CJTouch panels */ 1508070f63b4SYang Bo { .driver_data = MT_CLS_NSMU, 1509070f63b4SYang Bo MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 1510070f63b4SYang Bo USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) }, 1511070f63b4SYang Bo { .driver_data = MT_CLS_NSMU, 1512070f63b4SYang Bo MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 1513070f63b4SYang Bo USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) }, 1514070f63b4SYang Bo 151579603dc9SBenjamin Tissoires /* CVTouch panels */ 1516dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 15172c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, 151879603dc9SBenjamin Tissoires USB_DEVICE_ID_CVTOUCH_SCREEN) }, 151979603dc9SBenjamin Tissoires 152022408283SBenjamin Tissoires /* eGalax devices (resistive) */ 152122408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 15222c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1523e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, 152422408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 15252c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1526e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, 152722408283SBenjamin Tissoires 152822408283SBenjamin Tissoires /* eGalax devices (capacitive) */ 1529fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15302c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1531fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) }, 153222408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 15332c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1534e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, 1535fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15362c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1537fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, 15382ce09df4SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15392c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 15402ce09df4SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) }, 154122408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15422c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 154322408283SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) }, 1544fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15452c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1546fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) }, 154722408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 15482c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 154922408283SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, 155022408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 155122408283SBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1552e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, 1553fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15542c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1555fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) }, 15561fd8f047SChris Bagwell { .driver_data = MT_CLS_EGALAX, 1557aa672da1SAndy Shevchenko HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 1558aa672da1SAndy Shevchenko USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) }, 1559aa672da1SAndy Shevchenko { .driver_data = MT_CLS_EGALAX, 1560aa672da1SAndy Shevchenko HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 1561aa672da1SAndy Shevchenko USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) }, 1562aa672da1SAndy Shevchenko { .driver_data = MT_CLS_EGALAX, 15632c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 156466f06127SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, 156566f06127SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 15662c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1567bb9ff210SMarek Vasut USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, 15681b723e8dSBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15692c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1570fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, 1571fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 15722c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1573ae01c9e5SThierry Reding USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) }, 1574ae01c9e5SThierry Reding { .driver_data = MT_CLS_EGALAX_SERIAL, 1575ae01c9e5SThierry Reding MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1576e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, 157722408283SBenjamin Tissoires 15787c7606a2STomas Sokorai /* Elitegroup panel */ 15797c7606a2STomas Sokorai { .driver_data = MT_CLS_SERIAL, 15807c7606a2STomas Sokorai MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP, 15817c7606a2STomas Sokorai USB_DEVICE_ID_ELITEGROUP_05D8) }, 15827c7606a2STomas Sokorai 158377723e3bSHenrik Rydberg /* Flatfrog Panels */ 158477723e3bSHenrik Rydberg { .driver_data = MT_CLS_FLATFROG, 158577723e3bSHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, 158677723e3bSHenrik Rydberg USB_DEVICE_ID_MULTITOUCH_3200) }, 158777723e3bSHenrik Rydberg 15883db187e7SBenjamin Tissoires /* FocalTech Panels */ 15893db187e7SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 15903db187e7SBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL, 15913db187e7SBenjamin Tissoires USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) }, 15923db187e7SBenjamin Tissoires 15935572da08SBenjamin Tissoires /* GeneralTouch panel */ 1594f5ff4e1eSXianhan Yu { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 15952c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 15965572da08SBenjamin Tissoires USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, 1597f5ff4e1eSXianhan Yu { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 1598f5ff4e1eSXianhan Yu MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 1599f5ff4e1eSXianhan Yu USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, 16007b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 16017b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 16027b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101) }, 16037b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 16047b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 16057b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102) }, 16067b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 16077b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 16087b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106) }, 16097b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 16107b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 16117b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A) }, 16127b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 16137b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 16147b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100) }, 16155572da08SBenjamin Tissoires 16164d5df5d1SAndreas Nielsen /* Gametel game controller */ 1617dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 16182c2110e9SHenrik Rydberg MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL, 16194d5df5d1SAndreas Nielsen USB_DEVICE_ID_GAMETEL_MT_MODE) }, 16204d5df5d1SAndreas Nielsen 1621ee0fbd14SBenjamin Tissoires /* GoodTouch panels */ 1622dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 16232c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, 1624ee0fbd14SBenjamin Tissoires USB_DEVICE_ID_GOODTOUCH_000f) }, 1625ee0fbd14SBenjamin Tissoires 162654580365SBenjamin Tissoires /* Hanvon panels */ 162754580365SBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 16282c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, 162954580365SBenjamin Tissoires USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, 163054580365SBenjamin Tissoires 16314e61f0d7SAustin Zhang /* Ilitek dual touch panel */ 1632dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 16332c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, 16344e61f0d7SAustin Zhang USB_DEVICE_ID_ILITEK_MULTITOUCH) }, 16354e61f0d7SAustin Zhang 1636f3287a99SBenjamin Tissoires /* LG Melfas panel */ 1637f3287a99SBenjamin Tissoires { .driver_data = MT_CLS_LG, 1638f3287a99SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_LG, 1639f3287a99SBenjamin Tissoires USB_DEVICE_ID_LG_MELFAS_MT) }, 1640f3287a99SBenjamin Tissoires 16414a6ee685SBenjamin Tissoires /* MosArt panels */ 16424a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 16432c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 16444a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUS_T91MT)}, 16454a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 16462c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 16474a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 16484a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 16492c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, 16504a6ee685SBenjamin Tissoires USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 16514a6ee685SBenjamin Tissoires 16524db703eaSAustin Hendrix /* Novatek Panel */ 1653dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 16544380d819SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, 16554db703eaSAustin Hendrix USB_DEVICE_ID_NOVATEK_PCT) }, 16564db703eaSAustin Hendrix 1657a80e803aSBenjamin Tissoires /* Ntrig Panel */ 1658a80e803aSBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 1659a80e803aSBenjamin Tissoires HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 1660a80e803aSBenjamin Tissoires USB_VENDOR_ID_NTRIG, 0x1b05) }, 1661a80e803aSBenjamin Tissoires 1662*fb55b402SHans de Goede /* Panasonic panels */ 1663*fb55b402SHans de Goede { .driver_data = MT_CLS_PANASONIC, 1664*fb55b402SHans de Goede MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 1665*fb55b402SHans de Goede USB_DEVICE_ID_PANABOARD_UBT780) }, 1666*fb55b402SHans de Goede { .driver_data = MT_CLS_PANASONIC, 1667*fb55b402SHans de Goede MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 1668*fb55b402SHans de Goede USB_DEVICE_ID_PANABOARD_UBT880) }, 1669*fb55b402SHans de Goede 1670b7ea95ffSAaron Tian /* PixArt optical touch screen */ 1671b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 16722c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 1673b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) }, 1674b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 16752c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 1676b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) }, 1677b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 16782c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 1679b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) }, 1680b7ea95ffSAaron Tian 16815519cab4SBenjamin Tissoires /* PixCir-based panels */ 16821e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 16832c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 16845519cab4SBenjamin Tissoires USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, 16855519cab4SBenjamin Tissoires 16865e7ea11fSBenjamin Tissoires /* Quanta-based panels */ 16875e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 16882c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 16895e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, 1690a6802e00SForest Bond 1691043b403aSBenjamin Tissoires /* Stantum panels */ 1692bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 16932c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, 1694043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_STM)}, 1695043b403aSBenjamin Tissoires 1696847672cdSBenjamin Tissoires /* TopSeed panels */ 1697847672cdSBenjamin Tissoires { .driver_data = MT_CLS_TOPSEED, 16982c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, 1699847672cdSBenjamin Tissoires USB_DEVICE_ID_TOPSEED2_PERIPAD_701) }, 1700847672cdSBenjamin Tissoires 17015e74e56dSBenjamin Tissoires /* Touch International panels */ 1702dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17032c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, 17045e74e56dSBenjamin Tissoires USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, 17055e74e56dSBenjamin Tissoires 1706617b64f9SBenjamin Tissoires /* Unitec panels */ 1707dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17082c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 1709617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, 1710dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17112c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 1712617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, 1713bf9d121eSKaiChung Cheng 1714da10bc25SMathieu Magnaudet /* VTL panels */ 1715da10bc25SMathieu Magnaudet { .driver_data = MT_CLS_VTL, 1716da10bc25SMathieu Magnaudet MT_USB_DEVICE(USB_VENDOR_ID_VTL, 1717da10bc25SMathieu Magnaudet USB_DEVICE_ID_VTL_MULTITOUCH_FF3F) }, 1718da10bc25SMathieu Magnaudet 1719bf9d121eSKaiChung Cheng /* Wistron panels */ 1720bf9d121eSKaiChung Cheng { .driver_data = MT_CLS_NSMU, 1721bf9d121eSKaiChung Cheng MT_USB_DEVICE(USB_VENDOR_ID_WISTRON, 1722bf9d121eSKaiChung Cheng USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH) }, 1723bf9d121eSKaiChung Cheng 1724bc8a2a9bSice chien /* XAT */ 1725dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17262c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XAT, 1727bc8a2a9bSice chien USB_DEVICE_ID_XAT_CSR) }, 1728617b64f9SBenjamin Tissoires 172911576c61SMasatoshi Hoshikawa /* Xiroku */ 1730dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17312c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 173211576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX) }, 1733dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17342c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 173511576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX) }, 1736dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17372c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 173811576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR) }, 1739dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17402c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 174111576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX1) }, 1742dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17432c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 174411576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX1) }, 1745dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17462c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 174711576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR1) }, 1748dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17492c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 175011576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX2) }, 1751dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17522c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 175311576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX2) }, 1754dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 17552c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 175611576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR2) }, 175711576c61SMasatoshi Hoshikawa 17580e82232cSWei-Ning Huang /* Google MT devices */ 17590e82232cSWei-Ning Huang { .driver_data = MT_CLS_GOOGLE, 17600e82232cSWei-Ning Huang HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, 17610e82232cSWei-Ning Huang USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) }, 17620e82232cSWei-Ning Huang 17634fa3a583SHenrik Rydberg /* Generic MT device */ 17644fa3a583SHenrik Rydberg { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, 1765f961bd35SBenjamin Tissoires 1766f961bd35SBenjamin Tissoires /* Generic Win 8 certified MT device */ 1767f961bd35SBenjamin Tissoires { .driver_data = MT_CLS_WIN_8, 1768f961bd35SBenjamin Tissoires HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8, 1769f961bd35SBenjamin Tissoires HID_ANY_ID, HID_ANY_ID) }, 17705519cab4SBenjamin Tissoires { } 17715519cab4SBenjamin Tissoires }; 17725519cab4SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, mt_devices); 17735519cab4SBenjamin Tissoires 17745519cab4SBenjamin Tissoires static const struct hid_usage_id mt_grabbed_usages[] = { 17755519cab4SBenjamin Tissoires { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 17765519cab4SBenjamin Tissoires { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 17775519cab4SBenjamin Tissoires }; 17785519cab4SBenjamin Tissoires 17795519cab4SBenjamin Tissoires static struct hid_driver mt_driver = { 17805519cab4SBenjamin Tissoires .name = "hid-multitouch", 17815519cab4SBenjamin Tissoires .id_table = mt_devices, 17825519cab4SBenjamin Tissoires .probe = mt_probe, 17835519cab4SBenjamin Tissoires .remove = mt_remove, 17845519cab4SBenjamin Tissoires .input_mapping = mt_input_mapping, 17855519cab4SBenjamin Tissoires .input_mapped = mt_input_mapped, 178676f5902aSHenrik Rydberg .input_configured = mt_input_configured, 17875519cab4SBenjamin Tissoires .feature_mapping = mt_feature_mapping, 17885519cab4SBenjamin Tissoires .usage_table = mt_grabbed_usages, 17895519cab4SBenjamin Tissoires .event = mt_event, 179055978fa9SBenjamin Tissoires .report = mt_report, 17915519cab4SBenjamin Tissoires #ifdef CONFIG_PM 17925519cab4SBenjamin Tissoires .reset_resume = mt_reset_resume, 1793dfeefd10SScott Liu .resume = mt_resume, 17945519cab4SBenjamin Tissoires #endif 17955519cab4SBenjamin Tissoires }; 1796f425458eSH Hartley Sweeten module_hid_driver(mt_driver); 1797