12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 25519cab4SBenjamin Tissoires /* 35519cab4SBenjamin Tissoires * HID driver for multitouch panels 45519cab4SBenjamin Tissoires * 5c2ef8f21SBenjamin Tissoires * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> 6b0a78681SBenjamin Tissoires * Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com> 7c2ef8f21SBenjamin Tissoires * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France 8b0a78681SBenjamin Tissoires * Copyright (c) 2012-2013 Red Hat, Inc 95519cab4SBenjamin Tissoires * 104875ac11SRichard Nauber * This code is partly based on hid-egalax.c: 114875ac11SRichard Nauber * 124875ac11SRichard Nauber * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> 134875ac11SRichard Nauber * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 144875ac11SRichard Nauber * Copyright (c) 2010 Canonical, Ltd. 154875ac11SRichard Nauber * 16f786bba4SBenjamin Tissoires * This code is partly based on hid-3m-pct.c: 17f786bba4SBenjamin Tissoires * 18f786bba4SBenjamin Tissoires * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> 19f786bba4SBenjamin Tissoires * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 20f786bba4SBenjamin Tissoires * Copyright (c) 2010 Canonical, Ltd. 215519cab4SBenjamin Tissoires */ 225519cab4SBenjamin Tissoires 235519cab4SBenjamin Tissoires /* 245519cab4SBenjamin Tissoires */ 255519cab4SBenjamin Tissoires 26b0a78681SBenjamin Tissoires /* 27f146d1c4SBenjamin Tissoires * This driver is regularly tested thanks to the test suite in hid-tools[1]. 28b0a78681SBenjamin Tissoires * Please run these regression tests before patching this module so that 29b0a78681SBenjamin Tissoires * your patch won't break existing known devices. 30b0a78681SBenjamin Tissoires * 31f146d1c4SBenjamin Tissoires * [1] https://gitlab.freedesktop.org/libevdev/hid-tools 32b0a78681SBenjamin Tissoires */ 33b0a78681SBenjamin Tissoires 345519cab4SBenjamin Tissoires #include <linux/device.h> 355519cab4SBenjamin Tissoires #include <linux/hid.h> 365519cab4SBenjamin Tissoires #include <linux/module.h> 375519cab4SBenjamin Tissoires #include <linux/slab.h> 385519cab4SBenjamin Tissoires #include <linux/input/mt.h> 3929cc309dSNicolas Boichat #include <linux/jiffies.h> 4049a5a827SBenjamin Tissoires #include <linux/string.h> 414f4001bcSBenjamin Tissoires #include <linux/timer.h> 425519cab4SBenjamin Tissoires 435519cab4SBenjamin Tissoires 445519cab4SBenjamin Tissoires MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); 45ef2fafb3SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 465519cab4SBenjamin Tissoires MODULE_DESCRIPTION("HID multitouch panels"); 475519cab4SBenjamin Tissoires MODULE_LICENSE("GPL"); 485519cab4SBenjamin Tissoires 495519cab4SBenjamin Tissoires #include "hid-ids.h" 505519cab4SBenjamin Tissoires 515519cab4SBenjamin Tissoires /* quirks to control the device */ 52fd911896SBenjamin Tissoires #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) 53fd911896SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTID BIT(1) 54fd911896SBenjamin Tissoires #define MT_QUIRK_CYPRESS BIT(2) 55fd911896SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTNUMBER BIT(3) 56fd911896SBenjamin Tissoires #define MT_QUIRK_ALWAYS_VALID BIT(4) 57fd911896SBenjamin Tissoires #define MT_QUIRK_VALID_IS_INRANGE BIT(5) 58fd911896SBenjamin Tissoires #define MT_QUIRK_VALID_IS_CONFIDENCE BIT(6) 59fd911896SBenjamin Tissoires #define MT_QUIRK_CONFIDENCE BIT(7) 60fd911896SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE BIT(8) 61fd911896SBenjamin Tissoires #define MT_QUIRK_NO_AREA BIT(9) 62fd911896SBenjamin Tissoires #define MT_QUIRK_IGNORE_DUPLICATES BIT(10) 63fd911896SBenjamin Tissoires #define MT_QUIRK_HOVERING BIT(11) 64fd911896SBenjamin Tissoires #define MT_QUIRK_CONTACT_CNT_ACCURATE BIT(12) 65fd911896SBenjamin Tissoires #define MT_QUIRK_FORCE_GET_FEATURE BIT(13) 66fd911896SBenjamin Tissoires #define MT_QUIRK_FIX_CONST_CONTACT_ID BIT(14) 67fd911896SBenjamin Tissoires #define MT_QUIRK_TOUCH_SIZE_SCALING BIT(15) 684f4001bcSBenjamin Tissoires #define MT_QUIRK_STICKY_FINGERS BIT(16) 69957b8dffSJoão Paulo Rechi Vita #define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) 70d9c57a70SBenjamin Tissoires #define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18) 7169ecd44dSBenjamin Tissoires #define MT_QUIRK_SEPARATE_APP_REPORT BIT(19) 7240d5bb87SBenjamin Tissoires #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) 735519cab4SBenjamin Tissoires 749abebedbSAndrew Duggan #define MT_INPUTMODE_TOUCHSCREEN 0x02 759abebedbSAndrew Duggan #define MT_INPUTMODE_TOUCHPAD 0x03 769abebedbSAndrew Duggan 772c6e0277SSeth Forshee #define MT_BUTTONTYPE_CLICKPAD 0 782c6e0277SSeth Forshee 7902946f4bSBenjamin Tissoires enum latency_mode { 8002946f4bSBenjamin Tissoires HID_LATENCY_NORMAL = 0, 8102946f4bSBenjamin Tissoires HID_LATENCY_HIGH = 1, 8202946f4bSBenjamin Tissoires }; 8302946f4bSBenjamin Tissoires 844f4001bcSBenjamin Tissoires #define MT_IO_FLAGS_RUNNING 0 8596098274SBenjamin Tissoires #define MT_IO_FLAGS_ACTIVE_SLOTS 1 8696098274SBenjamin Tissoires #define MT_IO_FLAGS_PENDING_SLOTS 2 874f4001bcSBenjamin Tissoires 8801eaac7eSBenjamin Tissoires static const bool mtrue = true; /* default for true */ 8901eaac7eSBenjamin Tissoires static const bool mfalse; /* default for false */ 9001eaac7eSBenjamin Tissoires static const __s32 mzero; /* default for 0 */ 9101eaac7eSBenjamin Tissoires 9201eaac7eSBenjamin Tissoires #define DEFAULT_TRUE ((void *)&mtrue) 9301eaac7eSBenjamin Tissoires #define DEFAULT_FALSE ((void *)&mfalse) 9401eaac7eSBenjamin Tissoires #define DEFAULT_ZERO ((void *)&mzero) 9501eaac7eSBenjamin Tissoires 9601eaac7eSBenjamin Tissoires struct mt_usages { 9701eaac7eSBenjamin Tissoires struct list_head list; 9801eaac7eSBenjamin Tissoires __s32 *x, *y, *cx, *cy, *p, *w, *h, *a; 9901eaac7eSBenjamin Tissoires __s32 *contactid; /* the device ContactID assigned to this slot */ 10001eaac7eSBenjamin Tissoires bool *tip_state; /* is the touch valid? */ 10101eaac7eSBenjamin Tissoires bool *inrange_state; /* is the finger in proximity of the sensor? */ 10201eaac7eSBenjamin Tissoires bool *confidence_state; /* is the touch made by a finger? */ 1035519cab4SBenjamin Tissoires }; 1045519cab4SBenjamin Tissoires 105f146d1c4SBenjamin Tissoires struct mt_application { 106f146d1c4SBenjamin Tissoires struct list_head list; 107f146d1c4SBenjamin Tissoires unsigned int application; 10869ecd44dSBenjamin Tissoires unsigned int report_id; 10901eaac7eSBenjamin Tissoires struct list_head mt_usages; /* mt usages list */ 1103ceb3826SBenjamin Tissoires 1113ceb3826SBenjamin Tissoires __s32 quirks; 1123ceb3826SBenjamin Tissoires 11301eaac7eSBenjamin Tissoires __s32 *scantime; /* scantime reported */ 11401eaac7eSBenjamin Tissoires __s32 scantime_logical_max; /* max value for raw scantime */ 115f146d1c4SBenjamin Tissoires 11601eaac7eSBenjamin Tissoires __s32 *raw_cc; /* contact count in the report */ 117f146d1c4SBenjamin Tissoires int left_button_state; /* left button state */ 118f146d1c4SBenjamin Tissoires unsigned int mt_flags; /* flags to pass to input-mt */ 119f146d1c4SBenjamin Tissoires 12028a042a3SDmitry Torokhov unsigned long *pending_palm_slots; /* slots where we reported palm 12128a042a3SDmitry Torokhov * and need to release */ 12228a042a3SDmitry Torokhov 123f146d1c4SBenjamin Tissoires __u8 num_received; /* how many contacts we received */ 124f146d1c4SBenjamin Tissoires __u8 num_expected; /* expected last contact index */ 125f146d1c4SBenjamin Tissoires __u8 buttons_count; /* number of physical buttons per touchpad */ 126f146d1c4SBenjamin Tissoires __u8 touches_by_report; /* how many touches are present in one report: 127f146d1c4SBenjamin Tissoires * 1 means we should use a serial protocol 128f146d1c4SBenjamin Tissoires * > 1 means hybrid (multitouch) protocol 129f146d1c4SBenjamin Tissoires */ 130f146d1c4SBenjamin Tissoires 131f146d1c4SBenjamin Tissoires __s32 dev_time; /* the scan time provided by the device */ 132f146d1c4SBenjamin Tissoires unsigned long jiffies; /* the frame's jiffies */ 133f146d1c4SBenjamin Tissoires int timestamp; /* the timestamp to be sent */ 134f146d1c4SBenjamin Tissoires int prev_scantime; /* scantime reported previously */ 135f146d1c4SBenjamin Tissoires 136f146d1c4SBenjamin Tissoires bool have_contact_count; 137f146d1c4SBenjamin Tissoires }; 138f146d1c4SBenjamin Tissoires 1395519cab4SBenjamin Tissoires struct mt_class { 1402d93666eSBenjamin Tissoires __s32 name; /* MT_CLS */ 1415519cab4SBenjamin Tissoires __s32 quirks; 1425519cab4SBenjamin Tissoires __s32 sn_move; /* Signal/noise ratio for move events */ 143f786bba4SBenjamin Tissoires __s32 sn_width; /* Signal/noise ratio for width events */ 144f786bba4SBenjamin Tissoires __s32 sn_height; /* Signal/noise ratio for height events */ 1455519cab4SBenjamin Tissoires __s32 sn_pressure; /* Signal/noise ratio for pressure events */ 1465519cab4SBenjamin Tissoires __u8 maxcontacts; 147c2ef8f21SBenjamin Tissoires bool is_indirect; /* true for touchpads */ 1486aef704eSBenjamin Tissoires bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */ 1495519cab4SBenjamin Tissoires }; 1505519cab4SBenjamin Tissoires 1518dfe14b3SBenjamin Tissoires struct mt_report_data { 1528dfe14b3SBenjamin Tissoires struct list_head list; 1538dfe14b3SBenjamin Tissoires struct hid_report *report; 1548dfe14b3SBenjamin Tissoires struct mt_application *application; 1558dfe14b3SBenjamin Tissoires bool is_mt_collection; 1568dfe14b3SBenjamin Tissoires }; 1578dfe14b3SBenjamin Tissoires 1585519cab4SBenjamin Tissoires struct mt_device { 159eec29e3dSBenjamin Tissoires struct mt_class mtclass; /* our mt device class */ 1604f4001bcSBenjamin Tissoires struct timer_list release_timer; /* to release sticky fingers */ 1610ee32774SKees Cook struct hid_device *hdev; /* hid_device we're attached to */ 1624f4001bcSBenjamin Tissoires unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ 1639abebedbSAndrew Duggan __u8 inputmode_value; /* InputMode HID feature value */ 1645519cab4SBenjamin Tissoires __u8 maxcontacts; 1652c6e0277SSeth Forshee bool is_buttonpad; /* is this device a button pad? */ 16676f5902aSHenrik Rydberg bool serial_maybe; /* need to check for serial protocol */ 167f146d1c4SBenjamin Tissoires 168f146d1c4SBenjamin Tissoires struct list_head applications; 1698dfe14b3SBenjamin Tissoires struct list_head reports; 1705519cab4SBenjamin Tissoires }; 1715519cab4SBenjamin Tissoires 172f146d1c4SBenjamin Tissoires static void mt_post_parse_default_settings(struct mt_device *td, 173f146d1c4SBenjamin Tissoires struct mt_application *app); 174f146d1c4SBenjamin Tissoires static void mt_post_parse(struct mt_device *td, struct mt_application *app); 175a69c5f8bSBenjamin Tissoires 1765519cab4SBenjamin Tissoires /* classes of device behavior */ 17722408283SBenjamin Tissoires #define MT_CLS_DEFAULT 0x0001 17822408283SBenjamin Tissoires 179a062cc5aSStephane Chatty #define MT_CLS_SERIAL 0x0002 180a062cc5aSStephane Chatty #define MT_CLS_CONFIDENCE 0x0003 1815e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_CONTACT_ID 0x0004 1825e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 1835e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 1845e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 1850fa9c616SBenjamin Tissoires /* reserved 0x0008 */ 186b7ea95ffSAaron Tian #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 187dc3e1d80SBenjamin Tissoires #define MT_CLS_NSMU 0x000a 1880fa9c616SBenjamin Tissoires /* reserved 0x0010 */ 1890fa9c616SBenjamin Tissoires /* reserved 0x0011 */ 190f961bd35SBenjamin Tissoires #define MT_CLS_WIN_8 0x0012 1916aef704eSBenjamin Tissoires #define MT_CLS_EXPORT_ALL_INPUTS 0x0013 19227a6f701SKai-Heng Feng /* reserved 0x0014 */ 19340d5bb87SBenjamin Tissoires #define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015 19422408283SBenjamin Tissoires 19522408283SBenjamin Tissoires /* vendor specific classes */ 19622408283SBenjamin Tissoires #define MT_CLS_3M 0x0101 1970fa9c616SBenjamin Tissoires /* reserved 0x0102 */ 19822408283SBenjamin Tissoires #define MT_CLS_EGALAX 0x0103 1991b723e8dSBenjamin Tissoires #define MT_CLS_EGALAX_SERIAL 0x0104 200847672cdSBenjamin Tissoires #define MT_CLS_TOPSEED 0x0105 2012258e863SDenis Kovalev #define MT_CLS_PANASONIC 0x0106 20277723e3bSHenrik Rydberg #define MT_CLS_FLATFROG 0x0107 203cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 204cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 205f3287a99SBenjamin Tissoires #define MT_CLS_LG 0x010a 206957b8dffSJoão Paulo Rechi Vita #define MT_CLS_ASUS 0x010b 207da10bc25SMathieu Magnaudet #define MT_CLS_VTL 0x0110 2080e82232cSWei-Ning Huang #define MT_CLS_GOOGLE 0x0111 209843e475fSBenjamin Tissoires #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 21069ecd44dSBenjamin Tissoires #define MT_CLS_SMART_TECH 0x0113 2115519cab4SBenjamin Tissoires 2129498f954SBenjamin Tissoires #define MT_DEFAULT_MAXCONTACT 10 213afbcb04cSBenjamin Tissoires #define MT_MAX_MAXCONTACT 250 2149498f954SBenjamin Tissoires 21529cc309dSNicolas Boichat /* 21629cc309dSNicolas Boichat * Resync device and local timestamps after that many microseconds without 21729cc309dSNicolas Boichat * receiving data. 21829cc309dSNicolas Boichat */ 21929cc309dSNicolas Boichat #define MAX_TIMESTAMP_INTERVAL 1000000 22029cc309dSNicolas Boichat 2212c2110e9SHenrik Rydberg #define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) 2222c2110e9SHenrik Rydberg #define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) 2232c2110e9SHenrik Rydberg 2245519cab4SBenjamin Tissoires /* 2255519cab4SBenjamin Tissoires * these device-dependent functions determine what slot corresponds 2265519cab4SBenjamin Tissoires * to a valid contact that was just read. 2275519cab4SBenjamin Tissoires */ 2285519cab4SBenjamin Tissoires 22901eaac7eSBenjamin Tissoires static int cypress_compute_slot(struct mt_application *application, 23001eaac7eSBenjamin Tissoires struct mt_usages *slot) 231a3b5e577SBenjamin Tissoires { 23201eaac7eSBenjamin Tissoires if (*slot->contactid != 0 || application->num_received == 0) 23301eaac7eSBenjamin Tissoires return *slot->contactid; 234a3b5e577SBenjamin Tissoires else 235a3b5e577SBenjamin Tissoires return -1; 236a3b5e577SBenjamin Tissoires } 237a3b5e577SBenjamin Tissoires 238cf6d15d7SBenjamin Tissoires static const struct mt_class mt_classes[] = { 2392d93666eSBenjamin Tissoires { .name = MT_CLS_DEFAULT, 240dc3e1d80SBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 241dc3e1d80SBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE }, 242dc3e1d80SBenjamin Tissoires { .name = MT_CLS_NSMU, 2439498f954SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, 244a062cc5aSStephane Chatty { .name = MT_CLS_SERIAL, 245a062cc5aSStephane Chatty .quirks = MT_QUIRK_ALWAYS_VALID}, 24622408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE, 24722408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, 2485e7ea11fSBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_CONTACT_ID, 2495e7ea11fSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 2505e7ea11fSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID }, 25122408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_MINUS_ONE, 25222408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 25322408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, 2541e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTID, 2552d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 2562d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 2572d93666eSBenjamin Tissoires .maxcontacts = 2 }, 2581e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 2592d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 2602d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTNUMBER, 2612d93666eSBenjamin Tissoires .maxcontacts = 2 }, 262b7ea95ffSAaron Tian { .name = MT_CLS_INRANGE_CONTACTNUMBER, 263b7ea95ffSAaron Tian .quirks = MT_QUIRK_VALID_IS_INRANGE | 264b7ea95ffSAaron Tian MT_QUIRK_SLOT_IS_CONTACTNUMBER }, 265f961bd35SBenjamin Tissoires { .name = MT_CLS_WIN_8, 266f961bd35SBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 267f961bd35SBenjamin Tissoires MT_QUIRK_IGNORE_DUPLICATES | 268f961bd35SBenjamin Tissoires MT_QUIRK_HOVERING | 2694f4001bcSBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE | 270d9c57a70SBenjamin Tissoires MT_QUIRK_STICKY_FINGERS | 271c23e2043SBenjamin Tissoires MT_QUIRK_WIN8_PTP_BUTTONS, 272c23e2043SBenjamin Tissoires .export_all_inputs = true }, 2736aef704eSBenjamin Tissoires { .name = MT_CLS_EXPORT_ALL_INPUTS, 2746aef704eSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 2756aef704eSBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE, 2766aef704eSBenjamin Tissoires .export_all_inputs = true }, 27740d5bb87SBenjamin Tissoires { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 27840d5bb87SBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 27940d5bb87SBenjamin Tissoires MT_QUIRK_IGNORE_DUPLICATES | 28040d5bb87SBenjamin Tissoires MT_QUIRK_HOVERING | 28140d5bb87SBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE | 28240d5bb87SBenjamin Tissoires MT_QUIRK_STICKY_FINGERS | 28340d5bb87SBenjamin Tissoires MT_QUIRK_WIN8_PTP_BUTTONS | 28440d5bb87SBenjamin Tissoires MT_QUIRK_FORCE_MULTI_INPUT, 28540d5bb87SBenjamin Tissoires .export_all_inputs = true }, 28622408283SBenjamin Tissoires 28722408283SBenjamin Tissoires /* 28822408283SBenjamin Tissoires * vendor specific classes 28922408283SBenjamin Tissoires */ 29022408283SBenjamin Tissoires { .name = MT_CLS_3M, 29122408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 292e9d0a26dSHungNien Chen MT_QUIRK_SLOT_IS_CONTACTID | 293e9d0a26dSHungNien Chen MT_QUIRK_TOUCH_SIZE_SCALING, 29422408283SBenjamin Tissoires .sn_move = 2048, 29522408283SBenjamin Tissoires .sn_width = 128, 296c5d40be5SHenrik Rydberg .sn_height = 128, 297c5d40be5SHenrik Rydberg .maxcontacts = 60, 298c5d40be5SHenrik Rydberg }, 2994875ac11SRichard Nauber { .name = MT_CLS_EGALAX, 3004875ac11SRichard Nauber .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 3012261bb9fSBenjamin Tissoires MT_QUIRK_VALID_IS_INRANGE, 3024875ac11SRichard Nauber .sn_move = 4096, 3034875ac11SRichard Nauber .sn_pressure = 32, 3044875ac11SRichard Nauber }, 3051b723e8dSBenjamin Tissoires { .name = MT_CLS_EGALAX_SERIAL, 3061b723e8dSBenjamin Tissoires .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 3071b723e8dSBenjamin Tissoires MT_QUIRK_ALWAYS_VALID, 3082d93666eSBenjamin Tissoires .sn_move = 4096, 3092d93666eSBenjamin Tissoires .sn_pressure = 32, 3102d93666eSBenjamin Tissoires }, 311847672cdSBenjamin Tissoires { .name = MT_CLS_TOPSEED, 312847672cdSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID, 313847672cdSBenjamin Tissoires .is_indirect = true, 314847672cdSBenjamin Tissoires .maxcontacts = 2, 315847672cdSBenjamin Tissoires }, 3162258e863SDenis Kovalev { .name = MT_CLS_PANASONIC, 3172258e863SDenis Kovalev .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, 3182258e863SDenis Kovalev .maxcontacts = 4 }, 319f5ff4e1eSXianhan Yu { .name = MT_CLS_GENERALTOUCH_TWOFINGERS, 320f5ff4e1eSXianhan Yu .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 321f5ff4e1eSXianhan Yu MT_QUIRK_VALID_IS_INRANGE | 3227b226292SLuosong MT_QUIRK_SLOT_IS_CONTACTID, 323f5ff4e1eSXianhan Yu .maxcontacts = 2 324f5ff4e1eSXianhan Yu }, 325f5ff4e1eSXianhan Yu { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 326f5ff4e1eSXianhan Yu .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 3277b226292SLuosong MT_QUIRK_SLOT_IS_CONTACTID 328f5ff4e1eSXianhan Yu }, 329043b403aSBenjamin Tissoires 33077723e3bSHenrik Rydberg { .name = MT_CLS_FLATFROG, 33177723e3bSHenrik Rydberg .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 33277723e3bSHenrik Rydberg MT_QUIRK_NO_AREA, 33377723e3bSHenrik Rydberg .sn_move = 2048, 33477723e3bSHenrik Rydberg .maxcontacts = 40, 33577723e3bSHenrik Rydberg }, 336f3287a99SBenjamin Tissoires { .name = MT_CLS_LG, 337f3287a99SBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 338f3287a99SBenjamin Tissoires MT_QUIRK_FIX_CONST_CONTACT_ID | 339f3287a99SBenjamin Tissoires MT_QUIRK_IGNORE_DUPLICATES | 340f3287a99SBenjamin Tissoires MT_QUIRK_HOVERING | 341f3287a99SBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE }, 342957b8dffSJoão Paulo Rechi Vita { .name = MT_CLS_ASUS, 343957b8dffSJoão Paulo Rechi Vita .quirks = MT_QUIRK_ALWAYS_VALID | 344957b8dffSJoão Paulo Rechi Vita MT_QUIRK_CONTACT_CNT_ACCURATE | 345957b8dffSJoão Paulo Rechi Vita MT_QUIRK_ASUS_CUSTOM_UP }, 346da10bc25SMathieu Magnaudet { .name = MT_CLS_VTL, 347da10bc25SMathieu Magnaudet .quirks = MT_QUIRK_ALWAYS_VALID | 348da10bc25SMathieu Magnaudet MT_QUIRK_CONTACT_CNT_ACCURATE | 349da10bc25SMathieu Magnaudet MT_QUIRK_FORCE_GET_FEATURE, 350da10bc25SMathieu Magnaudet }, 3510e82232cSWei-Ning Huang { .name = MT_CLS_GOOGLE, 3520e82232cSWei-Ning Huang .quirks = MT_QUIRK_ALWAYS_VALID | 3530e82232cSWei-Ning Huang MT_QUIRK_CONTACT_CNT_ACCURATE | 3540e82232cSWei-Ning Huang MT_QUIRK_SLOT_IS_CONTACTID | 3550e82232cSWei-Ning Huang MT_QUIRK_HOVERING 3560e82232cSWei-Ning Huang }, 357843e475fSBenjamin Tissoires { .name = MT_CLS_RAZER_BLADE_STEALTH, 358843e475fSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 359843e475fSBenjamin Tissoires MT_QUIRK_IGNORE_DUPLICATES | 360843e475fSBenjamin Tissoires MT_QUIRK_HOVERING | 361843e475fSBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE | 362843e475fSBenjamin Tissoires MT_QUIRK_WIN8_PTP_BUTTONS, 363843e475fSBenjamin Tissoires }, 36469ecd44dSBenjamin Tissoires { .name = MT_CLS_SMART_TECH, 36569ecd44dSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID | 36669ecd44dSBenjamin Tissoires MT_QUIRK_IGNORE_DUPLICATES | 36769ecd44dSBenjamin Tissoires MT_QUIRK_CONTACT_CNT_ACCURATE | 36869ecd44dSBenjamin Tissoires MT_QUIRK_SEPARATE_APP_REPORT, 36969ecd44dSBenjamin Tissoires }, 3702d93666eSBenjamin Tissoires { } 3715519cab4SBenjamin Tissoires }; 3725519cab4SBenjamin Tissoires 373eec29e3dSBenjamin Tissoires static ssize_t mt_show_quirks(struct device *dev, 374eec29e3dSBenjamin Tissoires struct device_attribute *attr, 375eec29e3dSBenjamin Tissoires char *buf) 376eec29e3dSBenjamin Tissoires { 377ee79a8f8SGeliang Tang struct hid_device *hdev = to_hid_device(dev); 378eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 379eec29e3dSBenjamin Tissoires 380eec29e3dSBenjamin Tissoires return sprintf(buf, "%u\n", td->mtclass.quirks); 381eec29e3dSBenjamin Tissoires } 382eec29e3dSBenjamin Tissoires 383eec29e3dSBenjamin Tissoires static ssize_t mt_set_quirks(struct device *dev, 384eec29e3dSBenjamin Tissoires struct device_attribute *attr, 385eec29e3dSBenjamin Tissoires const char *buf, size_t count) 386eec29e3dSBenjamin Tissoires { 387ee79a8f8SGeliang Tang struct hid_device *hdev = to_hid_device(dev); 388eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 389f146d1c4SBenjamin Tissoires struct mt_application *application; 390eec29e3dSBenjamin Tissoires 391eec29e3dSBenjamin Tissoires unsigned long val; 392eec29e3dSBenjamin Tissoires 393eec29e3dSBenjamin Tissoires if (kstrtoul(buf, 0, &val)) 394eec29e3dSBenjamin Tissoires return -EINVAL; 395eec29e3dSBenjamin Tissoires 396eec29e3dSBenjamin Tissoires td->mtclass.quirks = val; 397eec29e3dSBenjamin Tissoires 398f146d1c4SBenjamin Tissoires list_for_each_entry(application, &td->applications, list) { 3993ceb3826SBenjamin Tissoires application->quirks = val; 4003ceb3826SBenjamin Tissoires if (!application->have_contact_count) 4013ceb3826SBenjamin Tissoires application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 402f146d1c4SBenjamin Tissoires } 403f146d1c4SBenjamin Tissoires 404eec29e3dSBenjamin Tissoires return count; 405eec29e3dSBenjamin Tissoires } 406eec29e3dSBenjamin Tissoires 407eec29e3dSBenjamin Tissoires static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); 408eec29e3dSBenjamin Tissoires 409eec29e3dSBenjamin Tissoires static struct attribute *sysfs_attrs[] = { 410eec29e3dSBenjamin Tissoires &dev_attr_quirks.attr, 411eec29e3dSBenjamin Tissoires NULL 412eec29e3dSBenjamin Tissoires }; 413eec29e3dSBenjamin Tissoires 4149182fb98SArvind Yadav static const struct attribute_group mt_attribute_group = { 415eec29e3dSBenjamin Tissoires .attrs = sysfs_attrs 416eec29e3dSBenjamin Tissoires }; 417eec29e3dSBenjamin Tissoires 4186d4f5440SMika Westerberg static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) 4196d4f5440SMika Westerberg { 4203064a03bSAaron Ma int ret; 4213064a03bSAaron Ma u32 size = hid_report_len(report); 4226d4f5440SMika Westerberg u8 *buf; 4236d4f5440SMika Westerberg 4246d4f5440SMika Westerberg /* 425b897f6dbSBenjamin Tissoires * Do not fetch the feature report if the device has been explicitly 426b897f6dbSBenjamin Tissoires * marked as non-capable. 4276d4f5440SMika Westerberg */ 428adaabbf4SBenjamin Tissoires if (hdev->quirks & HID_QUIRK_NO_INIT_REPORTS) 4296d4f5440SMika Westerberg return; 4306d4f5440SMika Westerberg 4316d4f5440SMika Westerberg buf = hid_alloc_report_buf(report, GFP_KERNEL); 4326d4f5440SMika Westerberg if (!buf) 4336d4f5440SMika Westerberg return; 4346d4f5440SMika Westerberg 4356d4f5440SMika Westerberg ret = hid_hw_raw_request(hdev, report->id, buf, size, 4366d4f5440SMika Westerberg HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 4376d4f5440SMika Westerberg if (ret < 0) { 4386d4f5440SMika Westerberg dev_warn(&hdev->dev, "failed to fetch feature %d\n", 4396d4f5440SMika Westerberg report->id); 4406d4f5440SMika Westerberg } else { 4416d4f5440SMika Westerberg ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, 4426d4f5440SMika Westerberg size, 0); 4436d4f5440SMika Westerberg if (ret) 4446d4f5440SMika Westerberg dev_warn(&hdev->dev, "failed to report feature\n"); 4456d4f5440SMika Westerberg } 4466d4f5440SMika Westerberg 4476d4f5440SMika Westerberg kfree(buf); 4486d4f5440SMika Westerberg } 4496d4f5440SMika Westerberg 450f635bd11SHenrik Rydberg static void mt_feature_mapping(struct hid_device *hdev, 4515519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage) 4525519cab4SBenjamin Tissoires { 4535519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 4549498f954SBenjamin Tissoires 4559498f954SBenjamin Tissoires switch (usage->hid) { 4569498f954SBenjamin Tissoires case HID_DG_CONTACTMAX: 4576d4f5440SMika Westerberg mt_get_feature(hdev, field->report); 4586d4f5440SMika Westerberg 4599498f954SBenjamin Tissoires td->maxcontacts = field->value[0]; 460afbcb04cSBenjamin Tissoires if (!td->maxcontacts && 461afbcb04cSBenjamin Tissoires field->logical_maximum <= MT_MAX_MAXCONTACT) 462afbcb04cSBenjamin Tissoires td->maxcontacts = field->logical_maximum; 463eec29e3dSBenjamin Tissoires if (td->mtclass.maxcontacts) 4649498f954SBenjamin Tissoires /* check if the maxcontacts is given by the class */ 465eec29e3dSBenjamin Tissoires td->maxcontacts = td->mtclass.maxcontacts; 4669498f954SBenjamin Tissoires 4679498f954SBenjamin Tissoires break; 4682c6e0277SSeth Forshee case HID_DG_BUTTONTYPE: 4692c6e0277SSeth Forshee if (usage->usage_index >= field->report_count) { 4702c6e0277SSeth Forshee dev_err(&hdev->dev, "HID_DG_BUTTONTYPE out of range\n"); 4712c6e0277SSeth Forshee break; 4722c6e0277SSeth Forshee } 4732c6e0277SSeth Forshee 4746d4f5440SMika Westerberg mt_get_feature(hdev, field->report); 4752c6e0277SSeth Forshee if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD) 4762c6e0277SSeth Forshee td->is_buttonpad = true; 4772c6e0277SSeth Forshee 4782c6e0277SSeth Forshee break; 47945c5c682SBenjamin Tissoires case 0xff0000c5: 48045c5c682SBenjamin Tissoires /* Retrieve the Win8 blob once to enable some devices */ 48145c5c682SBenjamin Tissoires if (usage->usage_index == 0) 48245c5c682SBenjamin Tissoires mt_get_feature(hdev, field->report); 48345c5c682SBenjamin Tissoires break; 4845519cab4SBenjamin Tissoires } 4855519cab4SBenjamin Tissoires } 4865519cab4SBenjamin Tissoires 4875519cab4SBenjamin Tissoires static void set_abs(struct input_dev *input, unsigned int code, 4885519cab4SBenjamin Tissoires struct hid_field *field, int snratio) 4895519cab4SBenjamin Tissoires { 4905519cab4SBenjamin Tissoires int fmin = field->logical_minimum; 4915519cab4SBenjamin Tissoires int fmax = field->logical_maximum; 4925519cab4SBenjamin Tissoires int fuzz = snratio ? (fmax - fmin) / snratio : 0; 4935519cab4SBenjamin Tissoires input_set_abs_params(input, code, fmin, fmax, fuzz, 0); 49437cf6e6fSBenjamin Tissoires input_abs_set_res(input, code, hidinput_calc_abs_res(field, code)); 4955519cab4SBenjamin Tissoires } 4965519cab4SBenjamin Tissoires 49701eaac7eSBenjamin Tissoires static struct mt_usages *mt_allocate_usage(struct hid_device *hdev, 49801eaac7eSBenjamin Tissoires struct mt_application *application) 49901eaac7eSBenjamin Tissoires { 50001eaac7eSBenjamin Tissoires struct mt_usages *usage; 50101eaac7eSBenjamin Tissoires 50201eaac7eSBenjamin Tissoires usage = devm_kzalloc(&hdev->dev, sizeof(*usage), GFP_KERNEL); 50301eaac7eSBenjamin Tissoires if (!usage) 50401eaac7eSBenjamin Tissoires return NULL; 50501eaac7eSBenjamin Tissoires 50601eaac7eSBenjamin Tissoires /* set some defaults so we do not need to check for null pointers */ 50701eaac7eSBenjamin Tissoires usage->x = DEFAULT_ZERO; 50801eaac7eSBenjamin Tissoires usage->y = DEFAULT_ZERO; 50901eaac7eSBenjamin Tissoires usage->cx = DEFAULT_ZERO; 51001eaac7eSBenjamin Tissoires usage->cy = DEFAULT_ZERO; 51101eaac7eSBenjamin Tissoires usage->p = DEFAULT_ZERO; 51201eaac7eSBenjamin Tissoires usage->w = DEFAULT_ZERO; 51301eaac7eSBenjamin Tissoires usage->h = DEFAULT_ZERO; 51401eaac7eSBenjamin Tissoires usage->a = DEFAULT_ZERO; 51501eaac7eSBenjamin Tissoires usage->contactid = DEFAULT_ZERO; 51601eaac7eSBenjamin Tissoires usage->tip_state = DEFAULT_FALSE; 51701eaac7eSBenjamin Tissoires usage->inrange_state = DEFAULT_FALSE; 51801eaac7eSBenjamin Tissoires usage->confidence_state = DEFAULT_TRUE; 51901eaac7eSBenjamin Tissoires 52001eaac7eSBenjamin Tissoires list_add_tail(&usage->list, &application->mt_usages); 52101eaac7eSBenjamin Tissoires 52201eaac7eSBenjamin Tissoires return usage; 52301eaac7eSBenjamin Tissoires } 52401eaac7eSBenjamin Tissoires 525f146d1c4SBenjamin Tissoires static struct mt_application *mt_allocate_application(struct mt_device *td, 52669ecd44dSBenjamin Tissoires struct hid_report *report) 527f146d1c4SBenjamin Tissoires { 52869ecd44dSBenjamin Tissoires unsigned int application = report->application; 529f146d1c4SBenjamin Tissoires struct mt_application *mt_application; 530f146d1c4SBenjamin Tissoires 531f146d1c4SBenjamin Tissoires mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application), 532f146d1c4SBenjamin Tissoires GFP_KERNEL); 533f146d1c4SBenjamin Tissoires if (!mt_application) 534f146d1c4SBenjamin Tissoires return NULL; 535f146d1c4SBenjamin Tissoires 536f146d1c4SBenjamin Tissoires mt_application->application = application; 53701eaac7eSBenjamin Tissoires INIT_LIST_HEAD(&mt_application->mt_usages); 538f146d1c4SBenjamin Tissoires 539f146d1c4SBenjamin Tissoires if (application == HID_DG_TOUCHSCREEN) 540f146d1c4SBenjamin Tissoires mt_application->mt_flags |= INPUT_MT_DIRECT; 541f146d1c4SBenjamin Tissoires 542f146d1c4SBenjamin Tissoires /* 543f146d1c4SBenjamin Tissoires * Model touchscreens providing buttons as touchpads. 544f146d1c4SBenjamin Tissoires */ 545f146d1c4SBenjamin Tissoires if (application == HID_DG_TOUCHPAD) { 546f146d1c4SBenjamin Tissoires mt_application->mt_flags |= INPUT_MT_POINTER; 547f146d1c4SBenjamin Tissoires td->inputmode_value = MT_INPUTMODE_TOUCHPAD; 548f146d1c4SBenjamin Tissoires } 549f146d1c4SBenjamin Tissoires 55001eaac7eSBenjamin Tissoires mt_application->scantime = DEFAULT_ZERO; 55101eaac7eSBenjamin Tissoires mt_application->raw_cc = DEFAULT_ZERO; 5523ceb3826SBenjamin Tissoires mt_application->quirks = td->mtclass.quirks; 55369ecd44dSBenjamin Tissoires mt_application->report_id = report->id; 554f146d1c4SBenjamin Tissoires 555f146d1c4SBenjamin Tissoires list_add_tail(&mt_application->list, &td->applications); 556f146d1c4SBenjamin Tissoires 557f146d1c4SBenjamin Tissoires return mt_application; 558f146d1c4SBenjamin Tissoires } 559f146d1c4SBenjamin Tissoires 560f146d1c4SBenjamin Tissoires static struct mt_application *mt_find_application(struct mt_device *td, 56169ecd44dSBenjamin Tissoires struct hid_report *report) 562f146d1c4SBenjamin Tissoires { 56369ecd44dSBenjamin Tissoires unsigned int application = report->application; 564f146d1c4SBenjamin Tissoires struct mt_application *tmp, *mt_application = NULL; 565f146d1c4SBenjamin Tissoires 566f146d1c4SBenjamin Tissoires list_for_each_entry(tmp, &td->applications, list) { 567f146d1c4SBenjamin Tissoires if (application == tmp->application) { 56869ecd44dSBenjamin Tissoires if (!(td->mtclass.quirks & MT_QUIRK_SEPARATE_APP_REPORT) || 56969ecd44dSBenjamin Tissoires tmp->report_id == report->id) { 570f146d1c4SBenjamin Tissoires mt_application = tmp; 571f146d1c4SBenjamin Tissoires break; 572f146d1c4SBenjamin Tissoires } 573f146d1c4SBenjamin Tissoires } 57469ecd44dSBenjamin Tissoires } 575f146d1c4SBenjamin Tissoires 576f146d1c4SBenjamin Tissoires if (!mt_application) 57769ecd44dSBenjamin Tissoires mt_application = mt_allocate_application(td, report); 578f146d1c4SBenjamin Tissoires 579f146d1c4SBenjamin Tissoires return mt_application; 580f146d1c4SBenjamin Tissoires } 581f146d1c4SBenjamin Tissoires 5828dfe14b3SBenjamin Tissoires static struct mt_report_data *mt_allocate_report_data(struct mt_device *td, 5838dfe14b3SBenjamin Tissoires struct hid_report *report) 5848dfe14b3SBenjamin Tissoires { 5858dfe14b3SBenjamin Tissoires struct mt_report_data *rdata; 5868dfe14b3SBenjamin Tissoires struct hid_field *field; 5878dfe14b3SBenjamin Tissoires int r, n; 5888dfe14b3SBenjamin Tissoires 5898dfe14b3SBenjamin Tissoires rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL); 5908dfe14b3SBenjamin Tissoires if (!rdata) 5918dfe14b3SBenjamin Tissoires return NULL; 5928dfe14b3SBenjamin Tissoires 5938dfe14b3SBenjamin Tissoires rdata->report = report; 59469ecd44dSBenjamin Tissoires rdata->application = mt_find_application(td, report); 5958dfe14b3SBenjamin Tissoires 5968dfe14b3SBenjamin Tissoires if (!rdata->application) { 5978dfe14b3SBenjamin Tissoires devm_kfree(&td->hdev->dev, rdata); 5988dfe14b3SBenjamin Tissoires return NULL; 5998dfe14b3SBenjamin Tissoires } 6008dfe14b3SBenjamin Tissoires 6018dfe14b3SBenjamin Tissoires for (r = 0; r < report->maxfield; r++) { 6028dfe14b3SBenjamin Tissoires field = report->field[r]; 6038dfe14b3SBenjamin Tissoires 6048dfe14b3SBenjamin Tissoires if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) 6058dfe14b3SBenjamin Tissoires continue; 6068dfe14b3SBenjamin Tissoires 6078dfe14b3SBenjamin Tissoires for (n = 0; n < field->report_count; n++) { 6088dfe14b3SBenjamin Tissoires if (field->usage[n].hid == HID_DG_CONTACTID) 6098dfe14b3SBenjamin Tissoires rdata->is_mt_collection = true; 6108dfe14b3SBenjamin Tissoires } 6118dfe14b3SBenjamin Tissoires } 6128dfe14b3SBenjamin Tissoires 6138dfe14b3SBenjamin Tissoires list_add_tail(&rdata->list, &td->reports); 6148dfe14b3SBenjamin Tissoires 6158dfe14b3SBenjamin Tissoires return rdata; 6168dfe14b3SBenjamin Tissoires } 6178dfe14b3SBenjamin Tissoires 6188dfe14b3SBenjamin Tissoires static struct mt_report_data *mt_find_report_data(struct mt_device *td, 6198dfe14b3SBenjamin Tissoires struct hid_report *report) 6208dfe14b3SBenjamin Tissoires { 6218dfe14b3SBenjamin Tissoires struct mt_report_data *tmp, *rdata = NULL; 6228dfe14b3SBenjamin Tissoires 6238dfe14b3SBenjamin Tissoires list_for_each_entry(tmp, &td->reports, list) { 6248dfe14b3SBenjamin Tissoires if (report == tmp->report) { 6258dfe14b3SBenjamin Tissoires rdata = tmp; 6268dfe14b3SBenjamin Tissoires break; 6278dfe14b3SBenjamin Tissoires } 6288dfe14b3SBenjamin Tissoires } 6298dfe14b3SBenjamin Tissoires 6308dfe14b3SBenjamin Tissoires if (!rdata) 6318dfe14b3SBenjamin Tissoires rdata = mt_allocate_report_data(td, report); 6328dfe14b3SBenjamin Tissoires 6338dfe14b3SBenjamin Tissoires return rdata; 6348dfe14b3SBenjamin Tissoires } 6358dfe14b3SBenjamin Tissoires 63601eaac7eSBenjamin Tissoires static void mt_store_field(struct hid_device *hdev, 63701eaac7eSBenjamin Tissoires struct mt_application *application, 63801eaac7eSBenjamin Tissoires __s32 *value, 63901eaac7eSBenjamin Tissoires size_t offset) 640ed9d5c96SBenjamin Tissoires { 64101eaac7eSBenjamin Tissoires struct mt_usages *usage; 64201eaac7eSBenjamin Tissoires __s32 **target; 6433ac36d15SBenjamin Tissoires 64401eaac7eSBenjamin Tissoires if (list_empty(&application->mt_usages)) 64501eaac7eSBenjamin Tissoires usage = mt_allocate_usage(hdev, application); 64601eaac7eSBenjamin Tissoires else 64701eaac7eSBenjamin Tissoires usage = list_last_entry(&application->mt_usages, 64801eaac7eSBenjamin Tissoires struct mt_usages, 64901eaac7eSBenjamin Tissoires list); 65001eaac7eSBenjamin Tissoires 65101eaac7eSBenjamin Tissoires if (!usage) 6523ac36d15SBenjamin Tissoires return; 6533ac36d15SBenjamin Tissoires 65401eaac7eSBenjamin Tissoires target = (__s32 **)((char *)usage + offset); 65501eaac7eSBenjamin Tissoires 65601eaac7eSBenjamin Tissoires /* the value has already been filled, create a new slot */ 65701eaac7eSBenjamin Tissoires if (*target != DEFAULT_TRUE && 65801eaac7eSBenjamin Tissoires *target != DEFAULT_FALSE && 65901eaac7eSBenjamin Tissoires *target != DEFAULT_ZERO) { 66081bcbad5SBenjamin Tissoires if (usage->contactid == DEFAULT_ZERO || 66181bcbad5SBenjamin Tissoires usage->x == DEFAULT_ZERO || 66281bcbad5SBenjamin Tissoires usage->y == DEFAULT_ZERO) { 66381bcbad5SBenjamin Tissoires hid_dbg(hdev, 66481bcbad5SBenjamin Tissoires "ignoring duplicate usage on incomplete"); 66581bcbad5SBenjamin Tissoires return; 66681bcbad5SBenjamin Tissoires } 66701eaac7eSBenjamin Tissoires usage = mt_allocate_usage(hdev, application); 66801eaac7eSBenjamin Tissoires if (!usage) 66901eaac7eSBenjamin Tissoires return; 67001eaac7eSBenjamin Tissoires 67101eaac7eSBenjamin Tissoires target = (__s32 **)((char *)usage + offset); 672ed9d5c96SBenjamin Tissoires } 673ed9d5c96SBenjamin Tissoires 67401eaac7eSBenjamin Tissoires *target = value; 67501eaac7eSBenjamin Tissoires } 67601eaac7eSBenjamin Tissoires 67701eaac7eSBenjamin Tissoires #define MT_STORE_FIELD(__name) \ 67801eaac7eSBenjamin Tissoires mt_store_field(hdev, app, \ 67901eaac7eSBenjamin Tissoires &field->value[usage->usage_index], \ 68001eaac7eSBenjamin Tissoires offsetof(struct mt_usages, __name)) 68101eaac7eSBenjamin Tissoires 682a69c5f8bSBenjamin Tissoires static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, 6835519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 684f146d1c4SBenjamin Tissoires unsigned long **bit, int *max, struct mt_application *app) 6855519cab4SBenjamin Tissoires { 6865519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 687eec29e3dSBenjamin Tissoires struct mt_class *cls = &td->mtclass; 688c2ef8f21SBenjamin Tissoires int code; 689349fd670SBenjamin Tissoires struct hid_usage *prev_usage = NULL; 6904875ac11SRichard Nauber 69176f5902aSHenrik Rydberg /* 69276f5902aSHenrik Rydberg * Model touchscreens providing buttons as touchpads. 693c2ef8f21SBenjamin Tissoires */ 694ba6b055eSBenjamin Tissoires if (field->application == HID_DG_TOUCHSCREEN && 695ba6b055eSBenjamin Tissoires (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { 696f146d1c4SBenjamin Tissoires app->mt_flags |= INPUT_MT_POINTER; 6979abebedbSAndrew Duggan td->inputmode_value = MT_INPUTMODE_TOUCHPAD; 6989abebedbSAndrew Duggan } 699c2ef8f21SBenjamin Tissoires 700015fdaa9SBenjamin Tissoires /* count the buttons on touchpads */ 701015fdaa9SBenjamin Tissoires if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) 702f146d1c4SBenjamin Tissoires app->buttons_count++; 703015fdaa9SBenjamin Tissoires 704349fd670SBenjamin Tissoires if (usage->usage_index) 705349fd670SBenjamin Tissoires prev_usage = &field->usage[usage->usage_index - 1]; 706349fd670SBenjamin Tissoires 7075519cab4SBenjamin Tissoires switch (usage->hid & HID_USAGE_PAGE) { 7085519cab4SBenjamin Tissoires 7095519cab4SBenjamin Tissoires case HID_UP_GENDESK: 7105519cab4SBenjamin Tissoires switch (usage->hid) { 7115519cab4SBenjamin Tissoires case HID_GD_X: 71201eaac7eSBenjamin Tissoires if (prev_usage && (prev_usage->hid == usage->hid)) { 713f146d1c4SBenjamin Tissoires code = ABS_MT_TOOL_X; 71401eaac7eSBenjamin Tissoires MT_STORE_FIELD(cx); 71501eaac7eSBenjamin Tissoires } else { 716f146d1c4SBenjamin Tissoires code = ABS_MT_POSITION_X; 71701eaac7eSBenjamin Tissoires MT_STORE_FIELD(x); 71801eaac7eSBenjamin Tissoires } 719349fd670SBenjamin Tissoires 720f146d1c4SBenjamin Tissoires set_abs(hi->input, code, field, cls->sn_move); 72101eaac7eSBenjamin Tissoires 722ba6b055eSBenjamin Tissoires /* 723ba6b055eSBenjamin Tissoires * A system multi-axis that exports X and Y has a high 724ba6b055eSBenjamin Tissoires * chance of being used directly on a surface 725ba6b055eSBenjamin Tissoires */ 726ba6b055eSBenjamin Tissoires if (field->application == HID_GD_SYSTEM_MULTIAXIS) { 727ba6b055eSBenjamin Tissoires __set_bit(INPUT_PROP_DIRECT, 728ba6b055eSBenjamin Tissoires hi->input->propbit); 729ba6b055eSBenjamin Tissoires input_set_abs_params(hi->input, 730ba6b055eSBenjamin Tissoires ABS_MT_TOOL_TYPE, 731ba6b055eSBenjamin Tissoires MT_TOOL_DIAL, 732ba6b055eSBenjamin Tissoires MT_TOOL_DIAL, 0, 0); 733ba6b055eSBenjamin Tissoires } 734ba6b055eSBenjamin Tissoires 7355519cab4SBenjamin Tissoires return 1; 7365519cab4SBenjamin Tissoires case HID_GD_Y: 73701eaac7eSBenjamin Tissoires if (prev_usage && (prev_usage->hid == usage->hid)) { 738f146d1c4SBenjamin Tissoires code = ABS_MT_TOOL_Y; 73901eaac7eSBenjamin Tissoires MT_STORE_FIELD(cy); 74001eaac7eSBenjamin Tissoires } else { 741f146d1c4SBenjamin Tissoires code = ABS_MT_POSITION_Y; 74201eaac7eSBenjamin Tissoires MT_STORE_FIELD(y); 74301eaac7eSBenjamin Tissoires } 744349fd670SBenjamin Tissoires 745f146d1c4SBenjamin Tissoires set_abs(hi->input, code, field, cls->sn_move); 74601eaac7eSBenjamin Tissoires 7475519cab4SBenjamin Tissoires return 1; 7485519cab4SBenjamin Tissoires } 7495519cab4SBenjamin Tissoires return 0; 7505519cab4SBenjamin Tissoires 7515519cab4SBenjamin Tissoires case HID_UP_DIGITIZER: 7525519cab4SBenjamin Tissoires switch (usage->hid) { 7535519cab4SBenjamin Tissoires case HID_DG_INRANGE: 7543ceb3826SBenjamin Tissoires if (app->quirks & MT_QUIRK_HOVERING) { 7559b3bb9b8SBenjamin Tissoires input_set_abs_params(hi->input, 7569b3bb9b8SBenjamin Tissoires ABS_MT_DISTANCE, 0, 1, 0, 0); 7579b3bb9b8SBenjamin Tissoires } 75801eaac7eSBenjamin Tissoires MT_STORE_FIELD(inrange_state); 7595519cab4SBenjamin Tissoires return 1; 7605519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 76127a6f701SKai-Heng Feng if (cls->name == MT_CLS_WIN_8 && 762f9024374SDmitry Torokhov (field->application == HID_DG_TOUCHPAD || 763f9024374SDmitry Torokhov field->application == HID_DG_TOUCHSCREEN)) 7643ceb3826SBenjamin Tissoires app->quirks |= MT_QUIRK_CONFIDENCE; 7659152c7d7SDmitry Torokhov 7669152c7d7SDmitry Torokhov if (app->quirks & MT_QUIRK_CONFIDENCE) 7679152c7d7SDmitry Torokhov input_set_abs_params(hi->input, 7689152c7d7SDmitry Torokhov ABS_MT_TOOL_TYPE, 7699152c7d7SDmitry Torokhov MT_TOOL_FINGER, 7709152c7d7SDmitry Torokhov MT_TOOL_PALM, 0, 0); 7719152c7d7SDmitry Torokhov 77201eaac7eSBenjamin Tissoires MT_STORE_FIELD(confidence_state); 7735519cab4SBenjamin Tissoires return 1; 7745519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 775ba6b055eSBenjamin Tissoires if (field->application != HID_GD_SYSTEM_MULTIAXIS) 776ba6b055eSBenjamin Tissoires input_set_capability(hi->input, 777ba6b055eSBenjamin Tissoires EV_KEY, BTN_TOUCH); 77801eaac7eSBenjamin Tissoires MT_STORE_FIELD(tip_state); 7795519cab4SBenjamin Tissoires return 1; 7805519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 78101eaac7eSBenjamin Tissoires MT_STORE_FIELD(contactid); 782f146d1c4SBenjamin Tissoires app->touches_by_report++; 7835519cab4SBenjamin Tissoires return 1; 7845519cab4SBenjamin Tissoires case HID_DG_WIDTH: 7853ceb3826SBenjamin Tissoires if (!(app->quirks & MT_QUIRK_NO_AREA)) 786f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, 787f786bba4SBenjamin Tissoires cls->sn_width); 78801eaac7eSBenjamin Tissoires MT_STORE_FIELD(w); 7895519cab4SBenjamin Tissoires return 1; 7905519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 7913ceb3826SBenjamin Tissoires if (!(app->quirks & MT_QUIRK_NO_AREA)) { 792f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, 793f786bba4SBenjamin Tissoires cls->sn_height); 79400720277SWei-Ning Huang 79500720277SWei-Ning Huang /* 79600720277SWei-Ning Huang * Only set ABS_MT_ORIENTATION if it is not 79700720277SWei-Ning Huang * already set by the HID_DG_AZIMUTH usage. 79800720277SWei-Ning Huang */ 79900720277SWei-Ning Huang if (!test_bit(ABS_MT_ORIENTATION, 80000720277SWei-Ning Huang hi->input->absbit)) 8011e648a13SBenjamin Tissoires input_set_abs_params(hi->input, 8021e648a13SBenjamin Tissoires ABS_MT_ORIENTATION, 0, 1, 0, 0); 80377723e3bSHenrik Rydberg } 80401eaac7eSBenjamin Tissoires MT_STORE_FIELD(h); 8055519cab4SBenjamin Tissoires return 1; 8065519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 8075519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_PRESSURE, field, 8085519cab4SBenjamin Tissoires cls->sn_pressure); 80901eaac7eSBenjamin Tissoires MT_STORE_FIELD(p); 8105519cab4SBenjamin Tissoires return 1; 81129cc309dSNicolas Boichat case HID_DG_SCANTIME: 81229cc309dSNicolas Boichat input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); 81301eaac7eSBenjamin Tissoires app->scantime = &field->value[usage->usage_index]; 81401eaac7eSBenjamin Tissoires app->scantime_logical_max = field->logical_maximum; 81529cc309dSNicolas Boichat return 1; 8165519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 81701eaac7eSBenjamin Tissoires app->have_contact_count = true; 81801eaac7eSBenjamin Tissoires app->raw_cc = &field->value[usage->usage_index]; 8195519cab4SBenjamin Tissoires return 1; 82000720277SWei-Ning Huang case HID_DG_AZIMUTH: 82100720277SWei-Ning Huang /* 82200720277SWei-Ning Huang * Azimuth has the range of [0, MAX) representing a full 82300720277SWei-Ning Huang * revolution. Set ABS_MT_ORIENTATION to a quarter of 82400720277SWei-Ning Huang * MAX according the definition of ABS_MT_ORIENTATION 82500720277SWei-Ning Huang */ 82600720277SWei-Ning Huang input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 82700720277SWei-Ning Huang -field->logical_maximum / 4, 82800720277SWei-Ning Huang field->logical_maximum / 4, 82900720277SWei-Ning Huang cls->sn_move ? 83000720277SWei-Ning Huang field->logical_maximum / cls->sn_move : 0, 0); 83101eaac7eSBenjamin Tissoires MT_STORE_FIELD(a); 83200720277SWei-Ning Huang return 1; 8335519cab4SBenjamin Tissoires case HID_DG_CONTACTMAX: 83401eaac7eSBenjamin Tissoires /* contact max are global to the report */ 8355519cab4SBenjamin Tissoires return -1; 836c2ef8f21SBenjamin Tissoires case HID_DG_TOUCH: 837c2ef8f21SBenjamin Tissoires /* Legacy devices use TIPSWITCH and not TOUCH. 838c2ef8f21SBenjamin Tissoires * Let's just ignore this field. */ 839c2ef8f21SBenjamin Tissoires return -1; 84065b258e9SAlan Cox } 8415519cab4SBenjamin Tissoires /* let hid-input decide for the others */ 8425519cab4SBenjamin Tissoires return 0; 8435519cab4SBenjamin Tissoires 844c2ef8f21SBenjamin Tissoires case HID_UP_BUTTON: 845c2ef8f21SBenjamin Tissoires code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); 846594312b8SBenjamin Tissoires /* 847594312b8SBenjamin Tissoires * MS PTP spec says that external buttons left and right have 848594312b8SBenjamin Tissoires * usages 2 and 3. 849594312b8SBenjamin Tissoires */ 8503ceb3826SBenjamin Tissoires if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && 851594312b8SBenjamin Tissoires field->application == HID_DG_TOUCHPAD && 852594312b8SBenjamin Tissoires (usage->hid & HID_USAGE) > 1) 853594312b8SBenjamin Tissoires code--; 854ba6b055eSBenjamin Tissoires 855ba6b055eSBenjamin Tissoires if (field->application == HID_GD_SYSTEM_MULTIAXIS) 856ba6b055eSBenjamin Tissoires code = BTN_0 + ((usage->hid - 1) & HID_USAGE); 857ba6b055eSBenjamin Tissoires 858c2ef8f21SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, code); 85935556bedSMarc Zyngier if (!*bit) 86035556bedSMarc Zyngier return -1; 861c2ef8f21SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, code); 862c2ef8f21SBenjamin Tissoires return 1; 863c2ef8f21SBenjamin Tissoires 8645519cab4SBenjamin Tissoires case 0xff000000: 8655519cab4SBenjamin Tissoires /* we do not want to map these: no input-oriented meaning */ 8665519cab4SBenjamin Tissoires return -1; 8675519cab4SBenjamin Tissoires } 8685519cab4SBenjamin Tissoires 8695519cab4SBenjamin Tissoires return 0; 8705519cab4SBenjamin Tissoires } 8715519cab4SBenjamin Tissoires 872f146d1c4SBenjamin Tissoires static int mt_compute_slot(struct mt_device *td, struct mt_application *app, 87301eaac7eSBenjamin Tissoires struct mt_usages *slot, 874f146d1c4SBenjamin Tissoires struct input_dev *input) 8755519cab4SBenjamin Tissoires { 8763ceb3826SBenjamin Tissoires __s32 quirks = app->quirks; 8775519cab4SBenjamin Tissoires 8782d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) 87901eaac7eSBenjamin Tissoires return *slot->contactid; 8805519cab4SBenjamin Tissoires 8812d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_CYPRESS) 88201eaac7eSBenjamin Tissoires return cypress_compute_slot(app, slot); 883a3b5e577SBenjamin Tissoires 8842d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) 885f146d1c4SBenjamin Tissoires return app->num_received; 8865572da08SBenjamin Tissoires 8874a6ee685SBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) 88801eaac7eSBenjamin Tissoires return *slot->contactid - 1; 8894a6ee685SBenjamin Tissoires 89001eaac7eSBenjamin Tissoires return input_mt_get_slot_by_key(input, *slot->contactid); 8913e1b5015SHenrik Rydberg } 8923e1b5015SHenrik Rydberg 89328a042a3SDmitry Torokhov static void mt_release_pending_palms(struct mt_device *td, 89428a042a3SDmitry Torokhov struct mt_application *app, 89528a042a3SDmitry Torokhov struct input_dev *input) 89628a042a3SDmitry Torokhov { 89728a042a3SDmitry Torokhov int slotnum; 89828a042a3SDmitry Torokhov bool need_sync = false; 89928a042a3SDmitry Torokhov 90028a042a3SDmitry Torokhov for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) { 90128a042a3SDmitry Torokhov clear_bit(slotnum, app->pending_palm_slots); 90228a042a3SDmitry Torokhov 90328a042a3SDmitry Torokhov input_mt_slot(input, slotnum); 9045fc70e35SJiada Wang input_mt_report_slot_inactive(input); 90528a042a3SDmitry Torokhov 90628a042a3SDmitry Torokhov need_sync = true; 90728a042a3SDmitry Torokhov } 90828a042a3SDmitry Torokhov 90928a042a3SDmitry Torokhov if (need_sync) { 91028a042a3SDmitry Torokhov input_mt_sync_frame(input); 91128a042a3SDmitry Torokhov input_sync(input); 91228a042a3SDmitry Torokhov } 91328a042a3SDmitry Torokhov } 91428a042a3SDmitry Torokhov 9153e1b5015SHenrik Rydberg /* 9163e1b5015SHenrik Rydberg * this function is called when a whole packet has been received and processed, 9173e1b5015SHenrik Rydberg * so that it can decide what to send to the input layer. 9183e1b5015SHenrik Rydberg */ 919f146d1c4SBenjamin Tissoires static void mt_sync_frame(struct mt_device *td, struct mt_application *app, 920f146d1c4SBenjamin Tissoires struct input_dev *input) 9213e1b5015SHenrik Rydberg { 9223ceb3826SBenjamin Tissoires if (app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) 923f146d1c4SBenjamin Tissoires input_event(input, EV_KEY, BTN_LEFT, app->left_button_state); 924127e71bdSHans de Goede 92576f5902aSHenrik Rydberg input_mt_sync_frame(input); 926f146d1c4SBenjamin Tissoires input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp); 9275519cab4SBenjamin Tissoires input_sync(input); 92828a042a3SDmitry Torokhov 92928a042a3SDmitry Torokhov mt_release_pending_palms(td, app, input); 93028a042a3SDmitry Torokhov 931f146d1c4SBenjamin Tissoires app->num_received = 0; 932f146d1c4SBenjamin Tissoires app->left_button_state = 0; 933f146d1c4SBenjamin Tissoires 93496098274SBenjamin Tissoires if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) 93596098274SBenjamin Tissoires set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 93696098274SBenjamin Tissoires else 93796098274SBenjamin Tissoires clear_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 93896098274SBenjamin Tissoires clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 9395519cab4SBenjamin Tissoires } 9405519cab4SBenjamin Tissoires 94101eaac7eSBenjamin Tissoires static int mt_compute_timestamp(struct mt_application *app, __s32 value) 94229cc309dSNicolas Boichat { 943f146d1c4SBenjamin Tissoires long delta = value - app->prev_scantime; 944f146d1c4SBenjamin Tissoires unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies); 94529cc309dSNicolas Boichat 946f146d1c4SBenjamin Tissoires app->jiffies = jiffies; 94729cc309dSNicolas Boichat 94829cc309dSNicolas Boichat if (delta < 0) 94901eaac7eSBenjamin Tissoires delta += app->scantime_logical_max; 95029cc309dSNicolas Boichat 95129cc309dSNicolas Boichat /* HID_DG_SCANTIME is expressed in 100us, we want it in us. */ 95229cc309dSNicolas Boichat delta *= 100; 95329cc309dSNicolas Boichat 95429cc309dSNicolas Boichat if (jdelta > MAX_TIMESTAMP_INTERVAL) 95529cc309dSNicolas Boichat /* No data received for a while, resync the timestamp. */ 95629cc309dSNicolas Boichat return 0; 95729cc309dSNicolas Boichat else 958f146d1c4SBenjamin Tissoires return app->timestamp + delta; 95929cc309dSNicolas Boichat } 96029cc309dSNicolas Boichat 961a69c5f8bSBenjamin Tissoires static int mt_touch_event(struct hid_device *hid, struct hid_field *field, 9625519cab4SBenjamin Tissoires struct hid_usage *usage, __s32 value) 9635519cab4SBenjamin Tissoires { 96455978fa9SBenjamin Tissoires /* we will handle the hidinput part later, now remains hiddev */ 96555978fa9SBenjamin Tissoires if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 96655978fa9SBenjamin Tissoires hid->hiddev_hid_event(hid, field, usage, value); 96755978fa9SBenjamin Tissoires 96855978fa9SBenjamin Tissoires return 1; 96955978fa9SBenjamin Tissoires } 97055978fa9SBenjamin Tissoires 97101eaac7eSBenjamin Tissoires static int mt_process_slot(struct mt_device *td, struct input_dev *input, 97201eaac7eSBenjamin Tissoires struct mt_application *app, 97301eaac7eSBenjamin Tissoires struct mt_usages *slot) 97455978fa9SBenjamin Tissoires { 97501eaac7eSBenjamin Tissoires struct input_mt *mt = input->mt; 9763ceb3826SBenjamin Tissoires __s32 quirks = app->quirks; 97701eaac7eSBenjamin Tissoires bool valid = true; 97801eaac7eSBenjamin Tissoires bool confidence_state = true; 97901eaac7eSBenjamin Tissoires bool inrange_state = false; 98001eaac7eSBenjamin Tissoires int active; 98101eaac7eSBenjamin Tissoires int slotnum; 982ba6b055eSBenjamin Tissoires int tool = MT_TOOL_FINGER; 9835519cab4SBenjamin Tissoires 98401eaac7eSBenjamin Tissoires if (!slot) 98501eaac7eSBenjamin Tissoires return -EINVAL; 98601eaac7eSBenjamin Tissoires 98701eaac7eSBenjamin Tissoires if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) && 98801eaac7eSBenjamin Tissoires app->num_received >= app->num_expected) 98901eaac7eSBenjamin Tissoires return -EAGAIN; 99001eaac7eSBenjamin Tissoires 99101eaac7eSBenjamin Tissoires if (!(quirks & MT_QUIRK_ALWAYS_VALID)) { 99220b60e6dSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_INRANGE) 99301eaac7eSBenjamin Tissoires valid = *slot->inrange_state; 9942d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 99501eaac7eSBenjamin Tissoires valid = *slot->tip_state; 9962d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) 99701eaac7eSBenjamin Tissoires valid = *slot->confidence_state; 99801eaac7eSBenjamin Tissoires 99901eaac7eSBenjamin Tissoires if (!valid) 100001eaac7eSBenjamin Tissoires return 0; 100101eaac7eSBenjamin Tissoires } 100201eaac7eSBenjamin Tissoires 100301eaac7eSBenjamin Tissoires slotnum = mt_compute_slot(td, app, slot, input); 100401eaac7eSBenjamin Tissoires if (slotnum < 0 || slotnum >= td->maxcontacts) 100501eaac7eSBenjamin Tissoires return 0; 100601eaac7eSBenjamin Tissoires 100701eaac7eSBenjamin Tissoires if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) { 100801eaac7eSBenjamin Tissoires struct input_mt_slot *i_slot = &mt->slots[slotnum]; 100901eaac7eSBenjamin Tissoires 101001eaac7eSBenjamin Tissoires if (input_mt_is_active(i_slot) && 101101eaac7eSBenjamin Tissoires input_mt_is_used(mt, i_slot)) 101201eaac7eSBenjamin Tissoires return -EAGAIN; 101301eaac7eSBenjamin Tissoires } 101401eaac7eSBenjamin Tissoires 101501eaac7eSBenjamin Tissoires if (quirks & MT_QUIRK_CONFIDENCE) 101601eaac7eSBenjamin Tissoires confidence_state = *slot->confidence_state; 101701eaac7eSBenjamin Tissoires 101801eaac7eSBenjamin Tissoires if (quirks & MT_QUIRK_HOVERING) 101901eaac7eSBenjamin Tissoires inrange_state = *slot->inrange_state; 102001eaac7eSBenjamin Tissoires 10219152c7d7SDmitry Torokhov active = *slot->tip_state || inrange_state; 102201eaac7eSBenjamin Tissoires 1023ba6b055eSBenjamin Tissoires if (app->application == HID_GD_SYSTEM_MULTIAXIS) 1024ba6b055eSBenjamin Tissoires tool = MT_TOOL_DIAL; 102528a042a3SDmitry Torokhov else if (unlikely(!confidence_state)) { 10269152c7d7SDmitry Torokhov tool = MT_TOOL_PALM; 1027306d5acbSPan Zhang if (!active && mt && 102828a042a3SDmitry Torokhov input_mt_is_active(&mt->slots[slotnum])) { 102928a042a3SDmitry Torokhov /* 103028a042a3SDmitry Torokhov * The non-confidence was reported for 103128a042a3SDmitry Torokhov * previously valid contact that is also no 103228a042a3SDmitry Torokhov * longer valid. We can't simply report 103328a042a3SDmitry Torokhov * lift-off as userspace will not be aware 103428a042a3SDmitry Torokhov * of non-confidence, so we need to split 103528a042a3SDmitry Torokhov * it into 2 events: active MT_TOOL_PALM 103628a042a3SDmitry Torokhov * and a separate liftoff. 103728a042a3SDmitry Torokhov */ 103828a042a3SDmitry Torokhov active = true; 103928a042a3SDmitry Torokhov set_bit(slotnum, app->pending_palm_slots); 104028a042a3SDmitry Torokhov } 104128a042a3SDmitry Torokhov } 1042ba6b055eSBenjamin Tissoires 104301eaac7eSBenjamin Tissoires input_mt_slot(input, slotnum); 1044ba6b055eSBenjamin Tissoires input_mt_report_slot_state(input, tool, active); 104501eaac7eSBenjamin Tissoires if (active) { 104601eaac7eSBenjamin Tissoires /* this finger is in proximity of the sensor */ 104701eaac7eSBenjamin Tissoires int wide = (*slot->w > *slot->h); 104801eaac7eSBenjamin Tissoires int major = max(*slot->w, *slot->h); 104901eaac7eSBenjamin Tissoires int minor = min(*slot->w, *slot->h); 105001eaac7eSBenjamin Tissoires int orientation = wide; 105101eaac7eSBenjamin Tissoires int max_azimuth; 105201eaac7eSBenjamin Tissoires int azimuth; 105301eaac7eSBenjamin Tissoires 105401eaac7eSBenjamin Tissoires if (slot->a != DEFAULT_ZERO) { 105500720277SWei-Ning Huang /* 105600720277SWei-Ning Huang * Azimuth is counter-clockwise and ranges from [0, MAX) 105700720277SWei-Ning Huang * (a full revolution). Convert it to clockwise ranging 105800720277SWei-Ning Huang * [-MAX/2, MAX/2]. 105900720277SWei-Ning Huang * 106000720277SWei-Ning Huang * Note that ABS_MT_ORIENTATION require us to report 106100720277SWei-Ning Huang * the limit of [-MAX/4, MAX/4], but the value can go 106200720277SWei-Ning Huang * out of range to [-MAX/2, MAX/2] to report an upside 106300720277SWei-Ning Huang * down ellipsis. 106400720277SWei-Ning Huang */ 106501eaac7eSBenjamin Tissoires azimuth = *slot->a; 106601eaac7eSBenjamin Tissoires max_azimuth = input_abs_get_max(input, 106701eaac7eSBenjamin Tissoires ABS_MT_ORIENTATION); 106801eaac7eSBenjamin Tissoires if (azimuth > max_azimuth * 2) 106901eaac7eSBenjamin Tissoires azimuth -= max_azimuth * 4; 107001eaac7eSBenjamin Tissoires orientation = -azimuth; 107101eaac7eSBenjamin Tissoires } 10725519cab4SBenjamin Tissoires 10739152c7d7SDmitry Torokhov if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { 107401eaac7eSBenjamin Tissoires /* 107501eaac7eSBenjamin Tissoires * divided by two to match visual scale of touch 107601eaac7eSBenjamin Tissoires * for devices with this quirk 107701eaac7eSBenjamin Tissoires */ 107801eaac7eSBenjamin Tissoires major = major >> 1; 107901eaac7eSBenjamin Tissoires minor = minor >> 1; 108001eaac7eSBenjamin Tissoires } 108101eaac7eSBenjamin Tissoires 108201eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x); 108301eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y); 108401eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx); 108501eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy); 108601eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state); 108701eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation); 108801eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p); 108901eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 109001eaac7eSBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 109101eaac7eSBenjamin Tissoires 109201eaac7eSBenjamin Tissoires set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 109301eaac7eSBenjamin Tissoires } 109401eaac7eSBenjamin Tissoires 109501eaac7eSBenjamin Tissoires return 0; 109601eaac7eSBenjamin Tissoires } 109701eaac7eSBenjamin Tissoires 109801eaac7eSBenjamin Tissoires static void mt_process_mt_event(struct hid_device *hid, 109901eaac7eSBenjamin Tissoires struct mt_application *app, 110001eaac7eSBenjamin Tissoires struct hid_field *field, 110101eaac7eSBenjamin Tissoires struct hid_usage *usage, 110201eaac7eSBenjamin Tissoires __s32 value, 110301eaac7eSBenjamin Tissoires bool first_packet) 110401eaac7eSBenjamin Tissoires { 110501eaac7eSBenjamin Tissoires __s32 quirks = app->quirks; 110601eaac7eSBenjamin Tissoires struct input_dev *input = field->hidinput->input; 110701eaac7eSBenjamin Tissoires 110801eaac7eSBenjamin Tissoires if (!usage->type || !(hid->claimed & HID_CLAIMED_INPUT)) 110901eaac7eSBenjamin Tissoires return; 111001eaac7eSBenjamin Tissoires 111101eaac7eSBenjamin Tissoires if (quirks & MT_QUIRK_WIN8_PTP_BUTTONS) { 111201eaac7eSBenjamin Tissoires 111355746d28SHans de Goede /* 111455746d28SHans de Goede * For Win8 PTP touchpads we should only look at 111501eaac7eSBenjamin Tissoires * non finger/touch events in the first_packet of a 111601eaac7eSBenjamin Tissoires * (possible) multi-packet frame. 111755746d28SHans de Goede */ 111801eaac7eSBenjamin Tissoires if (!first_packet) 111955746d28SHans de Goede return; 112055746d28SHans de Goede 1121127e71bdSHans de Goede /* 1122127e71bdSHans de Goede * For Win8 PTP touchpads we map both the clickpad click 1123127e71bdSHans de Goede * and any "external" left buttons to BTN_LEFT if a 1124127e71bdSHans de Goede * device claims to have both we need to report 1 for 1125127e71bdSHans de Goede * BTN_LEFT if either is pressed, so we or all values 1126127e71bdSHans de Goede * together and report the result in mt_sync_frame(). 1127127e71bdSHans de Goede */ 112801eaac7eSBenjamin Tissoires if (usage->type == EV_KEY && usage->code == BTN_LEFT) { 1129f146d1c4SBenjamin Tissoires app->left_button_state |= value; 1130127e71bdSHans de Goede return; 1131127e71bdSHans de Goede } 11325519cab4SBenjamin Tissoires } 11335519cab4SBenjamin Tissoires 113401eaac7eSBenjamin Tissoires input_event(input, usage->type, usage->code, value); 113555978fa9SBenjamin Tissoires } 11362d93666eSBenjamin Tissoires 11378dfe14b3SBenjamin Tissoires static void mt_touch_report(struct hid_device *hid, 11388dfe14b3SBenjamin Tissoires struct mt_report_data *rdata) 113955978fa9SBenjamin Tissoires { 114055978fa9SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 11418dfe14b3SBenjamin Tissoires struct hid_report *report = rdata->report; 11428dfe14b3SBenjamin Tissoires struct mt_application *app = rdata->application; 114355978fa9SBenjamin Tissoires struct hid_field *field; 114401eaac7eSBenjamin Tissoires struct input_dev *input; 114501eaac7eSBenjamin Tissoires struct mt_usages *slot; 114655746d28SHans de Goede bool first_packet; 114755978fa9SBenjamin Tissoires unsigned count; 1148f146d1c4SBenjamin Tissoires int r, n; 1149f146d1c4SBenjamin Tissoires int scantime = 0; 1150f146d1c4SBenjamin Tissoires int contact_count = -1; 11515519cab4SBenjamin Tissoires 11524f4001bcSBenjamin Tissoires /* sticky fingers release in progress, abort */ 11534f4001bcSBenjamin Tissoires if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 11544f4001bcSBenjamin Tissoires return; 11554f4001bcSBenjamin Tissoires 115601eaac7eSBenjamin Tissoires scantime = *app->scantime; 115701eaac7eSBenjamin Tissoires app->timestamp = mt_compute_timestamp(app, scantime); 115801eaac7eSBenjamin Tissoires if (app->raw_cc != DEFAULT_ZERO) 115901eaac7eSBenjamin Tissoires contact_count = *app->raw_cc; 116001eaac7eSBenjamin Tissoires 1161c2517f62SBenjamin Tissoires /* 1162c2517f62SBenjamin Tissoires * Includes multi-packet support where subsequent 1163c2517f62SBenjamin Tissoires * packets are sent with zero contactcount. 1164c2517f62SBenjamin Tissoires */ 116501eaac7eSBenjamin Tissoires if (contact_count >= 0) { 1166af8dc4d0SHans de Goede /* 1167af8dc4d0SHans de Goede * For Win8 PTPs the first packet (td->num_received == 0) may 1168af8dc4d0SHans de Goede * have a contactcount of 0 if there only is a button event. 1169af8dc4d0SHans de Goede * We double check that this is not a continuation packet 1170af8dc4d0SHans de Goede * of a possible multi-packet frame be checking that the 1171af8dc4d0SHans de Goede * timestamp has changed. 1172af8dc4d0SHans de Goede */ 11733ceb3826SBenjamin Tissoires if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && 1174f146d1c4SBenjamin Tissoires app->num_received == 0 && 1175f146d1c4SBenjamin Tissoires app->prev_scantime != scantime) 1176f146d1c4SBenjamin Tissoires app->num_expected = contact_count; 1177af8dc4d0SHans de Goede /* A non 0 contact count always indicates a first packet */ 1178f146d1c4SBenjamin Tissoires else if (contact_count) 1179f146d1c4SBenjamin Tissoires app->num_expected = contact_count; 11807e3cc447SBenjamin Tissoires } 1181f146d1c4SBenjamin Tissoires app->prev_scantime = scantime; 1182c2517f62SBenjamin Tissoires 1183f146d1c4SBenjamin Tissoires first_packet = app->num_received == 0; 118401eaac7eSBenjamin Tissoires 118501eaac7eSBenjamin Tissoires input = report->field[0]->hidinput->input; 118601eaac7eSBenjamin Tissoires 118701eaac7eSBenjamin Tissoires list_for_each_entry(slot, &app->mt_usages, list) { 118801eaac7eSBenjamin Tissoires if (!mt_process_slot(td, input, app, slot)) 118901eaac7eSBenjamin Tissoires app->num_received++; 119001eaac7eSBenjamin Tissoires } 119101eaac7eSBenjamin Tissoires 119255978fa9SBenjamin Tissoires for (r = 0; r < report->maxfield; r++) { 119355978fa9SBenjamin Tissoires field = report->field[r]; 119455978fa9SBenjamin Tissoires count = field->report_count; 119555978fa9SBenjamin Tissoires 119655978fa9SBenjamin Tissoires if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) 119755978fa9SBenjamin Tissoires continue; 119855978fa9SBenjamin Tissoires 119955978fa9SBenjamin Tissoires for (n = 0; n < count; n++) 120001eaac7eSBenjamin Tissoires mt_process_mt_event(hid, app, field, 120101eaac7eSBenjamin Tissoires &field->usage[n], field->value[n], 120201eaac7eSBenjamin Tissoires first_packet); 120355978fa9SBenjamin Tissoires } 12045b62efd8SBenjamin Tissoires 1205f146d1c4SBenjamin Tissoires if (app->num_received >= app->num_expected) 120601eaac7eSBenjamin Tissoires mt_sync_frame(td, app, input); 12074f4001bcSBenjamin Tissoires 12084f4001bcSBenjamin Tissoires /* 12094f4001bcSBenjamin Tissoires * Windows 8 specs says 2 things: 12104f4001bcSBenjamin Tissoires * - once a contact has been reported, it has to be reported in each 12114f4001bcSBenjamin Tissoires * subsequent report 12124f4001bcSBenjamin Tissoires * - the report rate when fingers are present has to be at least 12134f4001bcSBenjamin Tissoires * the refresh rate of the screen, 60 or 120 Hz 12144f4001bcSBenjamin Tissoires * 12154f4001bcSBenjamin Tissoires * I interprete this that the specification forces a report rate of 12164f4001bcSBenjamin Tissoires * at least 60 Hz for a touchscreen to be certified. 12174f4001bcSBenjamin Tissoires * Which means that if we do not get a report whithin 16 ms, either 12184f4001bcSBenjamin Tissoires * something wrong happens, either the touchscreen forgets to send 12194f4001bcSBenjamin Tissoires * a release. Taking a reasonable margin allows to remove issues 12204f4001bcSBenjamin Tissoires * with USB communication or the load of the machine. 12214f4001bcSBenjamin Tissoires * 12224f4001bcSBenjamin Tissoires * Given that Win 8 devices are forced to send a release, this will 12234f4001bcSBenjamin Tissoires * only affect laggish machines and the ones that have a firmware 12244f4001bcSBenjamin Tissoires * defect. 12254f4001bcSBenjamin Tissoires */ 12263ceb3826SBenjamin Tissoires if (app->quirks & MT_QUIRK_STICKY_FINGERS) { 122796098274SBenjamin Tissoires if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 122896098274SBenjamin Tissoires mod_timer(&td->release_timer, 122996098274SBenjamin Tissoires jiffies + msecs_to_jiffies(100)); 123096098274SBenjamin Tissoires else 123196098274SBenjamin Tissoires del_timer(&td->release_timer); 123296098274SBenjamin Tissoires } 12334f4001bcSBenjamin Tissoires 12344f4001bcSBenjamin Tissoires clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 12355519cab4SBenjamin Tissoires } 12365519cab4SBenjamin Tissoires 1237b2c68a2fSDmitry Torokhov static int mt_touch_input_configured(struct hid_device *hdev, 1238f146d1c4SBenjamin Tissoires struct hid_input *hi, 1239f146d1c4SBenjamin Tissoires struct mt_application *app) 1240a69c5f8bSBenjamin Tissoires { 1241a69c5f8bSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 1242a69c5f8bSBenjamin Tissoires struct mt_class *cls = &td->mtclass; 1243a69c5f8bSBenjamin Tissoires struct input_dev *input = hi->input; 1244b2c68a2fSDmitry Torokhov int ret; 1245a69c5f8bSBenjamin Tissoires 1246a69c5f8bSBenjamin Tissoires if (!td->maxcontacts) 1247a69c5f8bSBenjamin Tissoires td->maxcontacts = MT_DEFAULT_MAXCONTACT; 1248a69c5f8bSBenjamin Tissoires 1249f146d1c4SBenjamin Tissoires mt_post_parse(td, app); 1250a69c5f8bSBenjamin Tissoires if (td->serial_maybe) 1251f146d1c4SBenjamin Tissoires mt_post_parse_default_settings(td, app); 1252a69c5f8bSBenjamin Tissoires 1253a69c5f8bSBenjamin Tissoires if (cls->is_indirect) 1254f146d1c4SBenjamin Tissoires app->mt_flags |= INPUT_MT_POINTER; 1255a69c5f8bSBenjamin Tissoires 12563ceb3826SBenjamin Tissoires if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 1257f146d1c4SBenjamin Tissoires app->mt_flags |= INPUT_MT_DROP_UNUSED; 1258a69c5f8bSBenjamin Tissoires 1259015fdaa9SBenjamin Tissoires /* check for clickpads */ 1260f146d1c4SBenjamin Tissoires if ((app->mt_flags & INPUT_MT_POINTER) && 1261f146d1c4SBenjamin Tissoires (app->buttons_count == 1)) 12622c6e0277SSeth Forshee td->is_buttonpad = true; 12632c6e0277SSeth Forshee 12642c6e0277SSeth Forshee if (td->is_buttonpad) 1265015fdaa9SBenjamin Tissoires __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 1266015fdaa9SBenjamin Tissoires 126728a042a3SDmitry Torokhov app->pending_palm_slots = devm_kcalloc(&hi->input->dev, 126828a042a3SDmitry Torokhov BITS_TO_LONGS(td->maxcontacts), 126928a042a3SDmitry Torokhov sizeof(long), 127028a042a3SDmitry Torokhov GFP_KERNEL); 127128a042a3SDmitry Torokhov if (!app->pending_palm_slots) 127228a042a3SDmitry Torokhov return -ENOMEM; 127328a042a3SDmitry Torokhov 1274f146d1c4SBenjamin Tissoires ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags); 1275b2c68a2fSDmitry Torokhov if (ret) 1276b2c68a2fSDmitry Torokhov return ret; 1277a69c5f8bSBenjamin Tissoires 1278f146d1c4SBenjamin Tissoires app->mt_flags = 0; 1279b2c68a2fSDmitry Torokhov return 0; 1280a69c5f8bSBenjamin Tissoires } 1281a69c5f8bSBenjamin Tissoires 1282957b8dffSJoão Paulo Rechi Vita #define mt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \ 1283957b8dffSJoão Paulo Rechi Vita max, EV_KEY, (c)) 1284a69c5f8bSBenjamin Tissoires static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 1285a69c5f8bSBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 1286a69c5f8bSBenjamin Tissoires unsigned long **bit, int *max) 1287a69c5f8bSBenjamin Tissoires { 12886aef704eSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 1289f146d1c4SBenjamin Tissoires struct mt_application *application; 12908dfe14b3SBenjamin Tissoires struct mt_report_data *rdata; 12916aef704eSBenjamin Tissoires 12928dfe14b3SBenjamin Tissoires rdata = mt_find_report_data(td, field->report); 12938dfe14b3SBenjamin Tissoires if (!rdata) { 12948dfe14b3SBenjamin Tissoires hid_err(hdev, "failed to allocate data for report\n"); 12958dfe14b3SBenjamin Tissoires return 0; 12968dfe14b3SBenjamin Tissoires } 12978dfe14b3SBenjamin Tissoires 12988dfe14b3SBenjamin Tissoires application = rdata->application; 12993ceb3826SBenjamin Tissoires 13006aef704eSBenjamin Tissoires /* 13016aef704eSBenjamin Tissoires * If mtclass.export_all_inputs is not set, only map fields from 13026aef704eSBenjamin Tissoires * TouchScreen or TouchPad collections. We need to ignore fields 13036aef704eSBenjamin Tissoires * that belong to other collections such as Mouse that might have 13046aef704eSBenjamin Tissoires * the same GenericDesktop usages. 13056aef704eSBenjamin Tissoires */ 13066aef704eSBenjamin Tissoires if (!td->mtclass.export_all_inputs && 13076aef704eSBenjamin Tissoires field->application != HID_DG_TOUCHSCREEN && 1308fa11aa72SBenjamin Tissoires field->application != HID_DG_PEN && 13098fe89ef0SBenjamin Tissoires field->application != HID_DG_TOUCHPAD && 13108fe89ef0SBenjamin Tissoires field->application != HID_GD_KEYBOARD && 1311e57f4e67SHans de Goede field->application != HID_GD_SYSTEM_CONTROL && 13121fbf74efSJoão Paulo Rechi Vita field->application != HID_CP_CONSUMER_CONTROL && 1313957b8dffSJoão Paulo Rechi Vita field->application != HID_GD_WIRELESS_RADIO_CTLS && 1314ba6b055eSBenjamin Tissoires field->application != HID_GD_SYSTEM_MULTIAXIS && 1315957b8dffSJoão Paulo Rechi Vita !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 13163ceb3826SBenjamin Tissoires application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) 13176f492f28SBenjamin Tissoires return -1; 1318a69c5f8bSBenjamin Tissoires 13196aef704eSBenjamin Tissoires /* 1320957b8dffSJoão Paulo Rechi Vita * Some Asus keyboard+touchpad devices have the hotkeys defined in the 1321957b8dffSJoão Paulo Rechi Vita * touchpad report descriptor. We need to treat these as an array to 1322957b8dffSJoão Paulo Rechi Vita * map usages to input keys. 1323957b8dffSJoão Paulo Rechi Vita */ 132439bbf402SJiri Kosina if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 13253ceb3826SBenjamin Tissoires application->quirks & MT_QUIRK_ASUS_CUSTOM_UP && 1326957b8dffSJoão Paulo Rechi Vita (usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) { 1327957b8dffSJoão Paulo Rechi Vita set_bit(EV_REP, hi->input->evbit); 1328957b8dffSJoão Paulo Rechi Vita if (field->flags & HID_MAIN_ITEM_VARIABLE) 1329957b8dffSJoão Paulo Rechi Vita field->flags &= ~HID_MAIN_ITEM_VARIABLE; 1330957b8dffSJoão Paulo Rechi Vita switch (usage->hid & HID_USAGE) { 1331957b8dffSJoão Paulo Rechi Vita case 0x10: mt_map_key_clear(KEY_BRIGHTNESSDOWN); break; 1332957b8dffSJoão Paulo Rechi Vita case 0x20: mt_map_key_clear(KEY_BRIGHTNESSUP); break; 1333957b8dffSJoão Paulo Rechi Vita case 0x35: mt_map_key_clear(KEY_DISPLAY_OFF); break; 1334957b8dffSJoão Paulo Rechi Vita case 0x6b: mt_map_key_clear(KEY_F21); break; 1335957b8dffSJoão Paulo Rechi Vita case 0x6c: mt_map_key_clear(KEY_SLEEP); break; 1336957b8dffSJoão Paulo Rechi Vita default: 1337957b8dffSJoão Paulo Rechi Vita return -1; 1338957b8dffSJoão Paulo Rechi Vita } 1339957b8dffSJoão Paulo Rechi Vita return 1; 1340957b8dffSJoão Paulo Rechi Vita } 1341957b8dffSJoão Paulo Rechi Vita 1342ba6b055eSBenjamin Tissoires if (rdata->is_mt_collection) 1343f146d1c4SBenjamin Tissoires return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, 1344f146d1c4SBenjamin Tissoires application); 13456aef704eSBenjamin Tissoires 13467ffa13beSBenjamin Tissoires /* 13477ffa13beSBenjamin Tissoires * some egalax touchscreens have "application == DG_TOUCHSCREEN" 13487ffa13beSBenjamin Tissoires * for the stylus. Overwrite the hid_input application 13497ffa13beSBenjamin Tissoires */ 13507ffa13beSBenjamin Tissoires if (field->physical == HID_DG_STYLUS) 13517ffa13beSBenjamin Tissoires hi->application = HID_DG_STYLUS; 13527ffa13beSBenjamin Tissoires 13536aef704eSBenjamin Tissoires /* let hid-core decide for the others */ 13546aef704eSBenjamin Tissoires return 0; 1355a69c5f8bSBenjamin Tissoires } 1356a69c5f8bSBenjamin Tissoires 1357a69c5f8bSBenjamin Tissoires static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, 1358a69c5f8bSBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 1359a69c5f8bSBenjamin Tissoires unsigned long **bit, int *max) 1360a69c5f8bSBenjamin Tissoires { 1361ba6b055eSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 1362ba6b055eSBenjamin Tissoires struct mt_report_data *rdata; 1363fa11aa72SBenjamin Tissoires 1364ba6b055eSBenjamin Tissoires rdata = mt_find_report_data(td, field->report); 1365ba6b055eSBenjamin Tissoires if (rdata && rdata->is_mt_collection) { 13664cf56a89SDmitry Torokhov /* We own these mappings, tell hid-input to ignore them */ 13674cf56a89SDmitry Torokhov return -1; 13684cf56a89SDmitry Torokhov } 13696aef704eSBenjamin Tissoires 13706aef704eSBenjamin Tissoires /* let hid-core decide for the others */ 13716aef704eSBenjamin Tissoires return 0; 1372a69c5f8bSBenjamin Tissoires } 1373a69c5f8bSBenjamin Tissoires 1374a69c5f8bSBenjamin Tissoires static int mt_event(struct hid_device *hid, struct hid_field *field, 1375a69c5f8bSBenjamin Tissoires struct hid_usage *usage, __s32 value) 1376a69c5f8bSBenjamin Tissoires { 1377a69c5f8bSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 13788dfe14b3SBenjamin Tissoires struct mt_report_data *rdata; 1379a69c5f8bSBenjamin Tissoires 13808dfe14b3SBenjamin Tissoires rdata = mt_find_report_data(td, field->report); 13818dfe14b3SBenjamin Tissoires if (rdata && rdata->is_mt_collection) 1382a69c5f8bSBenjamin Tissoires return mt_touch_event(hid, field, usage, value); 1383a69c5f8bSBenjamin Tissoires 1384e55f6200SBenjamin Tissoires return 0; 1385a69c5f8bSBenjamin Tissoires } 1386a69c5f8bSBenjamin Tissoires 1387a69c5f8bSBenjamin Tissoires static void mt_report(struct hid_device *hid, struct hid_report *report) 1388a69c5f8bSBenjamin Tissoires { 1389a69c5f8bSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 1390e55f6200SBenjamin Tissoires struct hid_field *field = report->field[0]; 13918dfe14b3SBenjamin Tissoires struct mt_report_data *rdata; 1392a69c5f8bSBenjamin Tissoires 1393a69c5f8bSBenjamin Tissoires if (!(hid->claimed & HID_CLAIMED_INPUT)) 1394a69c5f8bSBenjamin Tissoires return; 1395a69c5f8bSBenjamin Tissoires 13968dfe14b3SBenjamin Tissoires rdata = mt_find_report_data(td, report); 13978dfe14b3SBenjamin Tissoires if (rdata && rdata->is_mt_collection) 13988dfe14b3SBenjamin Tissoires return mt_touch_report(hid, rdata); 1399fa11aa72SBenjamin Tissoires 1400e55f6200SBenjamin Tissoires if (field && field->hidinput && field->hidinput->input) 1401e55f6200SBenjamin Tissoires input_sync(field->hidinput->input); 14025519cab4SBenjamin Tissoires } 14035519cab4SBenjamin Tissoires 14047f81c8dbSBenjamin Tissoires static bool mt_need_to_apply_feature(struct hid_device *hdev, 14057f81c8dbSBenjamin Tissoires struct hid_field *field, 140602946f4bSBenjamin Tissoires struct hid_usage *usage, 140702946f4bSBenjamin Tissoires enum latency_mode latency, 140802946f4bSBenjamin Tissoires bool surface_switch, 1409ec6adef5SBenjamin Tissoires bool button_switch, 1410ec6adef5SBenjamin Tissoires bool *inputmode_found) 14115519cab4SBenjamin Tissoires { 14125519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 1413da10bc25SMathieu Magnaudet struct mt_class *cls = &td->mtclass; 14147f81c8dbSBenjamin Tissoires struct hid_report *report = field->report; 14157f81c8dbSBenjamin Tissoires unsigned int index = usage->usage_index; 1416da10bc25SMathieu Magnaudet char *buf; 14173064a03bSAaron Ma u32 report_len; 14187f81c8dbSBenjamin Tissoires int max; 14195519cab4SBenjamin Tissoires 14207f81c8dbSBenjamin Tissoires switch (usage->hid) { 14217f81c8dbSBenjamin Tissoires case HID_DG_INPUTMODE: 1422ec6adef5SBenjamin Tissoires /* 1423ec6adef5SBenjamin Tissoires * Some elan panels wrongly declare 2 input mode features, 1424ec6adef5SBenjamin Tissoires * and silently ignore when we set the value in the second 1425ec6adef5SBenjamin Tissoires * field. Skip the second feature and hope for the best. 1426ec6adef5SBenjamin Tissoires */ 1427ec6adef5SBenjamin Tissoires if (*inputmode_found) 1428ec6adef5SBenjamin Tissoires return false; 1429ec6adef5SBenjamin Tissoires 1430da10bc25SMathieu Magnaudet if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) { 14317f81c8dbSBenjamin Tissoires report_len = hid_report_len(report); 14327f81c8dbSBenjamin Tissoires buf = hid_alloc_report_buf(report, GFP_KERNEL); 1433da10bc25SMathieu Magnaudet if (!buf) { 14347f81c8dbSBenjamin Tissoires hid_err(hdev, 14357f81c8dbSBenjamin Tissoires "failed to allocate buffer for report\n"); 14367f81c8dbSBenjamin Tissoires return false; 1437da10bc25SMathieu Magnaudet } 14387f81c8dbSBenjamin Tissoires hid_hw_raw_request(hdev, report->id, buf, report_len, 1439da10bc25SMathieu Magnaudet HID_FEATURE_REPORT, 1440da10bc25SMathieu Magnaudet HID_REQ_GET_REPORT); 1441da10bc25SMathieu Magnaudet kfree(buf); 1442da10bc25SMathieu Magnaudet } 14437f81c8dbSBenjamin Tissoires 14447f81c8dbSBenjamin Tissoires field->value[index] = td->inputmode_value; 1445ec6adef5SBenjamin Tissoires *inputmode_found = true; 14467f81c8dbSBenjamin Tissoires return true; 14477f81c8dbSBenjamin Tissoires 14487f81c8dbSBenjamin Tissoires case HID_DG_CONTACTMAX: 14493ceb3826SBenjamin Tissoires if (cls->maxcontacts) { 14507f81c8dbSBenjamin Tissoires max = min_t(int, field->logical_maximum, 14513ceb3826SBenjamin Tissoires cls->maxcontacts); 14527f81c8dbSBenjamin Tissoires if (field->value[index] != max) { 14537f81c8dbSBenjamin Tissoires field->value[index] = max; 14547f81c8dbSBenjamin Tissoires return true; 14555519cab4SBenjamin Tissoires } 14565519cab4SBenjamin Tissoires } 14577f81c8dbSBenjamin Tissoires break; 145802946f4bSBenjamin Tissoires 145902946f4bSBenjamin Tissoires case HID_DG_LATENCYMODE: 146002946f4bSBenjamin Tissoires field->value[index] = latency; 146199c703acSJiri Kosina return true; 146202946f4bSBenjamin Tissoires 146302946f4bSBenjamin Tissoires case HID_DG_SURFACESWITCH: 146402946f4bSBenjamin Tissoires field->value[index] = surface_switch; 146599c703acSJiri Kosina return true; 146602946f4bSBenjamin Tissoires 146702946f4bSBenjamin Tissoires case HID_DG_BUTTONSWITCH: 146802946f4bSBenjamin Tissoires field->value[index] = button_switch; 146999c703acSJiri Kosina return true; 14707f81c8dbSBenjamin Tissoires } 14715519cab4SBenjamin Tissoires 14727f81c8dbSBenjamin Tissoires return false; /* no need to update the report */ 14737f81c8dbSBenjamin Tissoires } 14747f81c8dbSBenjamin Tissoires 147502946f4bSBenjamin Tissoires static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency, 147602946f4bSBenjamin Tissoires bool surface_switch, bool button_switch) 147731ae9bddSBenjamin Tissoires { 14787f81c8dbSBenjamin Tissoires struct hid_report_enum *rep_enum; 14797f81c8dbSBenjamin Tissoires struct hid_report *rep; 14807f81c8dbSBenjamin Tissoires struct hid_usage *usage; 14817f81c8dbSBenjamin Tissoires int i, j; 14827f81c8dbSBenjamin Tissoires bool update_report; 1483ec6adef5SBenjamin Tissoires bool inputmode_found = false; 148431ae9bddSBenjamin Tissoires 14857f81c8dbSBenjamin Tissoires rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; 14867f81c8dbSBenjamin Tissoires list_for_each_entry(rep, &rep_enum->report_list, list) { 14877f81c8dbSBenjamin Tissoires update_report = false; 148831ae9bddSBenjamin Tissoires 14897f81c8dbSBenjamin Tissoires for (i = 0; i < rep->maxfield; i++) { 14907f81c8dbSBenjamin Tissoires /* Ignore if report count is out of bounds. */ 14917f81c8dbSBenjamin Tissoires if (rep->field[i]->report_count < 1) 14927f81c8dbSBenjamin Tissoires continue; 149331ae9bddSBenjamin Tissoires 14947f81c8dbSBenjamin Tissoires for (j = 0; j < rep->field[i]->maxusage; j++) { 14957f81c8dbSBenjamin Tissoires usage = &rep->field[i]->usage[j]; 14967f81c8dbSBenjamin Tissoires 14977f81c8dbSBenjamin Tissoires if (mt_need_to_apply_feature(hdev, 14987f81c8dbSBenjamin Tissoires rep->field[i], 149902946f4bSBenjamin Tissoires usage, 150002946f4bSBenjamin Tissoires latency, 150102946f4bSBenjamin Tissoires surface_switch, 1502ec6adef5SBenjamin Tissoires button_switch, 1503ec6adef5SBenjamin Tissoires &inputmode_found)) 15047f81c8dbSBenjamin Tissoires update_report = true; 150531ae9bddSBenjamin Tissoires } 150631ae9bddSBenjamin Tissoires } 15077f81c8dbSBenjamin Tissoires 15087f81c8dbSBenjamin Tissoires if (update_report) 15097f81c8dbSBenjamin Tissoires hid_hw_request(hdev, rep, HID_REQ_SET_REPORT); 15107f81c8dbSBenjamin Tissoires } 151131ae9bddSBenjamin Tissoires } 151231ae9bddSBenjamin Tissoires 1513f146d1c4SBenjamin Tissoires static void mt_post_parse_default_settings(struct mt_device *td, 1514f146d1c4SBenjamin Tissoires struct mt_application *app) 15154fa3a583SHenrik Rydberg { 15163ceb3826SBenjamin Tissoires __s32 quirks = app->quirks; 15174fa3a583SHenrik Rydberg 15184fa3a583SHenrik Rydberg /* unknown serial device needs special quirks */ 151901eaac7eSBenjamin Tissoires if (list_is_singular(&app->mt_usages)) { 15204fa3a583SHenrik Rydberg quirks |= MT_QUIRK_ALWAYS_VALID; 15214fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; 15224fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_INRANGE; 15234fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; 1524e0bb8f9aSBenjamin Tissoires quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 15254fa3a583SHenrik Rydberg } 15264fa3a583SHenrik Rydberg 15273ceb3826SBenjamin Tissoires app->quirks = quirks; 15284fa3a583SHenrik Rydberg } 15294fa3a583SHenrik Rydberg 1530f146d1c4SBenjamin Tissoires static void mt_post_parse(struct mt_device *td, struct mt_application *app) 15313ac36d15SBenjamin Tissoires { 153201eaac7eSBenjamin Tissoires if (!app->have_contact_count) 15333ceb3826SBenjamin Tissoires app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 15343ac36d15SBenjamin Tissoires } 15353ac36d15SBenjamin Tissoires 1536b2c68a2fSDmitry Torokhov static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) 153776f5902aSHenrik Rydberg { 153876f5902aSHenrik Rydberg struct mt_device *td = hid_get_drvdata(hdev); 1539c08d46aaSBenjamin Tissoires char *name; 1540c08d46aaSBenjamin Tissoires const char *suffix = NULL; 15418dfe14b3SBenjamin Tissoires struct mt_report_data *rdata; 1542f146d1c4SBenjamin Tissoires struct mt_application *mt_application = NULL; 154340ec2603SBenjamin Tissoires struct hid_report *report; 1544b2c68a2fSDmitry Torokhov int ret; 154576f5902aSHenrik Rydberg 154640ec2603SBenjamin Tissoires list_for_each_entry(report, &hi->reports, hidinput_list) { 15478dfe14b3SBenjamin Tissoires rdata = mt_find_report_data(td, report); 15488dfe14b3SBenjamin Tissoires if (!rdata) { 15498dfe14b3SBenjamin Tissoires hid_err(hdev, "failed to allocate data for report\n"); 15508dfe14b3SBenjamin Tissoires return -ENOMEM; 15518dfe14b3SBenjamin Tissoires } 1552f146d1c4SBenjamin Tissoires 15538dfe14b3SBenjamin Tissoires mt_application = rdata->application; 15548dfe14b3SBenjamin Tissoires 15558dfe14b3SBenjamin Tissoires if (rdata->is_mt_collection) { 1556f146d1c4SBenjamin Tissoires ret = mt_touch_input_configured(hdev, hi, 1557f146d1c4SBenjamin Tissoires mt_application); 1558b2c68a2fSDmitry Torokhov if (ret) 1559b2c68a2fSDmitry Torokhov return ret; 1560b2c68a2fSDmitry Torokhov } 156140ec2603SBenjamin Tissoires } 156240ec2603SBenjamin Tissoires 15637ffa13beSBenjamin Tissoires switch (hi->application) { 15646aef704eSBenjamin Tissoires case HID_GD_KEYBOARD: 15656aef704eSBenjamin Tissoires case HID_GD_KEYPAD: 15666aef704eSBenjamin Tissoires case HID_GD_MOUSE: 156740ec2603SBenjamin Tissoires case HID_DG_TOUCHPAD: 156840ec2603SBenjamin Tissoires case HID_GD_SYSTEM_CONTROL: 156940ec2603SBenjamin Tissoires case HID_CP_CONSUMER_CONTROL: 157040ec2603SBenjamin Tissoires case HID_GD_WIRELESS_RADIO_CTLS: 1571ba6b055eSBenjamin Tissoires case HID_GD_SYSTEM_MULTIAXIS: 157240ec2603SBenjamin Tissoires /* already handled by hid core */ 15736aef704eSBenjamin Tissoires break; 15746aef704eSBenjamin Tissoires case HID_DG_TOUCHSCREEN: 15756aef704eSBenjamin Tissoires /* we do not set suffix = "Touchscreen" */ 157640ec2603SBenjamin Tissoires hi->input->name = hdev->name; 15776aef704eSBenjamin Tissoires break; 157840ec2603SBenjamin Tissoires case HID_DG_STYLUS: 157940ec2603SBenjamin Tissoires /* force BTN_STYLUS to allow tablet matching in udev */ 158040ec2603SBenjamin Tissoires __set_bit(BTN_STYLUS, hi->input->keybit); 15811fbf74efSJoão Paulo Rechi Vita break; 1582957b8dffSJoão Paulo Rechi Vita case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: 1583957b8dffSJoão Paulo Rechi Vita suffix = "Custom Media Keys"; 1584957b8dffSJoão Paulo Rechi Vita break; 158569ecd44dSBenjamin Tissoires case HID_DG_PEN: 158669ecd44dSBenjamin Tissoires suffix = "Stylus"; 158769ecd44dSBenjamin Tissoires break; 15886aef704eSBenjamin Tissoires default: 15896aef704eSBenjamin Tissoires suffix = "UNKNOWN"; 15906aef704eSBenjamin Tissoires break; 15916aef704eSBenjamin Tissoires } 159276f5902aSHenrik Rydberg 1593c08d46aaSBenjamin Tissoires if (suffix) { 1594c08d46aaSBenjamin Tissoires name = devm_kzalloc(&hi->input->dev, 1595c08d46aaSBenjamin Tissoires strlen(hdev->name) + strlen(suffix) + 2, 1596c08d46aaSBenjamin Tissoires GFP_KERNEL); 1597c08d46aaSBenjamin Tissoires if (name) { 1598c08d46aaSBenjamin Tissoires sprintf(name, "%s %s", hdev->name, suffix); 1599c08d46aaSBenjamin Tissoires hi->input->name = name; 1600c08d46aaSBenjamin Tissoires } 1601c08d46aaSBenjamin Tissoires } 1602b2c68a2fSDmitry Torokhov 1603b2c68a2fSDmitry Torokhov return 0; 1604c08d46aaSBenjamin Tissoires } 1605c08d46aaSBenjamin Tissoires 1606f3287a99SBenjamin Tissoires static void mt_fix_const_field(struct hid_field *field, unsigned int usage) 1607f3287a99SBenjamin Tissoires { 1608f3287a99SBenjamin Tissoires if (field->usage[0].hid != usage || 1609f3287a99SBenjamin Tissoires !(field->flags & HID_MAIN_ITEM_CONSTANT)) 1610f3287a99SBenjamin Tissoires return; 1611f3287a99SBenjamin Tissoires 1612f3287a99SBenjamin Tissoires field->flags &= ~HID_MAIN_ITEM_CONSTANT; 1613f3287a99SBenjamin Tissoires field->flags |= HID_MAIN_ITEM_VARIABLE; 1614f3287a99SBenjamin Tissoires } 1615f3287a99SBenjamin Tissoires 1616f3287a99SBenjamin Tissoires static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage) 1617f3287a99SBenjamin Tissoires { 1618f3287a99SBenjamin Tissoires struct hid_report *report; 1619f3287a99SBenjamin Tissoires int i; 1620f3287a99SBenjamin Tissoires 1621f3287a99SBenjamin Tissoires list_for_each_entry(report, 1622f3287a99SBenjamin Tissoires &hdev->report_enum[HID_INPUT_REPORT].report_list, 1623f3287a99SBenjamin Tissoires list) { 1624f3287a99SBenjamin Tissoires 1625f3287a99SBenjamin Tissoires if (!report->maxfield) 1626f3287a99SBenjamin Tissoires continue; 1627f3287a99SBenjamin Tissoires 1628f3287a99SBenjamin Tissoires for (i = 0; i < report->maxfield; i++) 1629f3287a99SBenjamin Tissoires if (report->field[i]->maxusage >= 1) 1630f3287a99SBenjamin Tissoires mt_fix_const_field(report->field[i], usage); 1631f3287a99SBenjamin Tissoires } 1632f3287a99SBenjamin Tissoires } 1633f3287a99SBenjamin Tissoires 16344f4001bcSBenjamin Tissoires static void mt_release_contacts(struct hid_device *hid) 16354f4001bcSBenjamin Tissoires { 16364f4001bcSBenjamin Tissoires struct hid_input *hidinput; 1637f146d1c4SBenjamin Tissoires struct mt_application *application; 16384f4001bcSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 16394f4001bcSBenjamin Tissoires 16404f4001bcSBenjamin Tissoires list_for_each_entry(hidinput, &hid->inputs, list) { 16414f4001bcSBenjamin Tissoires struct input_dev *input_dev = hidinput->input; 16424f4001bcSBenjamin Tissoires struct input_mt *mt = input_dev->mt; 16434f4001bcSBenjamin Tissoires int i; 16444f4001bcSBenjamin Tissoires 16454f4001bcSBenjamin Tissoires if (mt) { 16464f4001bcSBenjamin Tissoires for (i = 0; i < mt->num_slots; i++) { 16474f4001bcSBenjamin Tissoires input_mt_slot(input_dev, i); 16485fc70e35SJiada Wang input_mt_report_slot_inactive(input_dev); 16494f4001bcSBenjamin Tissoires } 16504f4001bcSBenjamin Tissoires input_mt_sync_frame(input_dev); 16514f4001bcSBenjamin Tissoires input_sync(input_dev); 16524f4001bcSBenjamin Tissoires } 16534f4001bcSBenjamin Tissoires } 16544f4001bcSBenjamin Tissoires 1655f146d1c4SBenjamin Tissoires list_for_each_entry(application, &td->applications, list) { 1656f146d1c4SBenjamin Tissoires application->num_received = 0; 1657f146d1c4SBenjamin Tissoires } 16584f4001bcSBenjamin Tissoires } 16594f4001bcSBenjamin Tissoires 16600ee32774SKees Cook static void mt_expired_timeout(struct timer_list *t) 16614f4001bcSBenjamin Tissoires { 16620ee32774SKees Cook struct mt_device *td = from_timer(td, t, release_timer); 16630ee32774SKees Cook struct hid_device *hdev = td->hdev; 16644f4001bcSBenjamin Tissoires 16654f4001bcSBenjamin Tissoires /* 16664f4001bcSBenjamin Tissoires * An input report came in just before we release the sticky fingers, 16674f4001bcSBenjamin Tissoires * it will take care of the sticky fingers. 16684f4001bcSBenjamin Tissoires */ 16694f4001bcSBenjamin Tissoires if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 16704f4001bcSBenjamin Tissoires return; 167196098274SBenjamin Tissoires if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 16724f4001bcSBenjamin Tissoires mt_release_contacts(hdev); 16734f4001bcSBenjamin Tissoires clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 16744f4001bcSBenjamin Tissoires } 16754f4001bcSBenjamin Tissoires 16765519cab4SBenjamin Tissoires static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 16775519cab4SBenjamin Tissoires { 16782d93666eSBenjamin Tissoires int ret, i; 16795519cab4SBenjamin Tissoires struct mt_device *td; 1680cf6d15d7SBenjamin Tissoires const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ 16812d93666eSBenjamin Tissoires 16822d93666eSBenjamin Tissoires for (i = 0; mt_classes[i].name ; i++) { 16832d93666eSBenjamin Tissoires if (id->driver_data == mt_classes[i].name) { 16842d93666eSBenjamin Tissoires mtclass = &(mt_classes[i]); 16852d93666eSBenjamin Tissoires break; 16862d93666eSBenjamin Tissoires } 16872d93666eSBenjamin Tissoires } 16885519cab4SBenjamin Tissoires 1689c08d46aaSBenjamin Tissoires td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); 16905519cab4SBenjamin Tissoires if (!td) { 16915519cab4SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch data\n"); 16925519cab4SBenjamin Tissoires return -ENOMEM; 16935519cab4SBenjamin Tissoires } 16940ee32774SKees Cook td->hdev = hdev; 1695eec29e3dSBenjamin Tissoires td->mtclass = *mtclass; 16969abebedbSAndrew Duggan td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; 16975519cab4SBenjamin Tissoires hid_set_drvdata(hdev, td); 16985519cab4SBenjamin Tissoires 1699f146d1c4SBenjamin Tissoires INIT_LIST_HEAD(&td->applications); 17008dfe14b3SBenjamin Tissoires INIT_LIST_HEAD(&td->reports); 1701f146d1c4SBenjamin Tissoires 170276f5902aSHenrik Rydberg if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) 170376f5902aSHenrik Rydberg td->serial_maybe = true; 170476f5902aSHenrik Rydberg 1705b897f6dbSBenjamin Tissoires /* This allows the driver to correctly support devices 1706b897f6dbSBenjamin Tissoires * that emit events over several HID messages. 1707b897f6dbSBenjamin Tissoires */ 1708b897f6dbSBenjamin Tissoires hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 1709b897f6dbSBenjamin Tissoires 1710b897f6dbSBenjamin Tissoires /* 1711b897f6dbSBenjamin Tissoires * This allows the driver to handle different input sensors 171240ec2603SBenjamin Tissoires * that emits events through different applications on the same HID 1713b897f6dbSBenjamin Tissoires * device. 1714b897f6dbSBenjamin Tissoires */ 171540ec2603SBenjamin Tissoires hdev->quirks |= HID_QUIRK_INPUT_PER_APP; 1716b897f6dbSBenjamin Tissoires 17170d6c3011SBenjamin Tissoires if (id->group != HID_GROUP_MULTITOUCH_WIN_8) 17180d6c3011SBenjamin Tissoires hdev->quirks |= HID_QUIRK_MULTI_INPUT; 17190d6c3011SBenjamin Tissoires 172040d5bb87SBenjamin Tissoires if (mtclass->quirks & MT_QUIRK_FORCE_MULTI_INPUT) { 172140d5bb87SBenjamin Tissoires hdev->quirks &= ~HID_QUIRK_INPUT_PER_APP; 172240d5bb87SBenjamin Tissoires hdev->quirks |= HID_QUIRK_MULTI_INPUT; 172340d5bb87SBenjamin Tissoires } 172440d5bb87SBenjamin Tissoires 17250ee32774SKees Cook timer_setup(&td->release_timer, mt_expired_timeout, 0); 17264f4001bcSBenjamin Tissoires 17275519cab4SBenjamin Tissoires ret = hid_parse(hdev); 17285519cab4SBenjamin Tissoires if (ret != 0) 1729c08d46aaSBenjamin Tissoires return ret; 17305519cab4SBenjamin Tissoires 1731f3287a99SBenjamin Tissoires if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) 1732f3287a99SBenjamin Tissoires mt_fix_const_fields(hdev, HID_DG_CONTACTID); 1733f3287a99SBenjamin Tissoires 17345519cab4SBenjamin Tissoires ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 17352d93666eSBenjamin Tissoires if (ret) 1736c08d46aaSBenjamin Tissoires return ret; 17375519cab4SBenjamin Tissoires 1738eec29e3dSBenjamin Tissoires ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); 17390c4b3c63SNicholas Krause if (ret) 17400c4b3c63SNicholas Krause dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n", 17410c4b3c63SNicholas Krause hdev->name); 1742eec29e3dSBenjamin Tissoires 174302946f4bSBenjamin Tissoires mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 17445519cab4SBenjamin Tissoires 17455519cab4SBenjamin Tissoires return 0; 17465519cab4SBenjamin Tissoires } 17475519cab4SBenjamin Tissoires 17485519cab4SBenjamin Tissoires #ifdef CONFIG_PM 17495519cab4SBenjamin Tissoires static int mt_reset_resume(struct hid_device *hdev) 17505519cab4SBenjamin Tissoires { 1751d3e69b9aSBenson Leung mt_release_contacts(hdev); 175202946f4bSBenjamin Tissoires mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 17535519cab4SBenjamin Tissoires return 0; 17545519cab4SBenjamin Tissoires } 1755dfeefd10SScott Liu 1756dfeefd10SScott Liu static int mt_resume(struct hid_device *hdev) 1757dfeefd10SScott Liu { 1758dfeefd10SScott Liu /* Some Elan legacy devices require SET_IDLE to be set on resume. 1759dfeefd10SScott Liu * It should be safe to send it to other devices too. 1760dfeefd10SScott Liu * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ 1761dfeefd10SScott Liu 17624ba25d3fSBenjamin Tissoires hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE); 1763dfeefd10SScott Liu 1764dfeefd10SScott Liu return 0; 1765dfeefd10SScott Liu } 17665519cab4SBenjamin Tissoires #endif 17675519cab4SBenjamin Tissoires 17685519cab4SBenjamin Tissoires static void mt_remove(struct hid_device *hdev) 17695519cab4SBenjamin Tissoires { 1770b897f6dbSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 1771b897f6dbSBenjamin Tissoires 17724f4001bcSBenjamin Tissoires del_timer_sync(&td->release_timer); 17734f4001bcSBenjamin Tissoires 1774eec29e3dSBenjamin Tissoires sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); 17755939212dSBenjamin Tissoires hid_hw_stop(hdev); 17765519cab4SBenjamin Tissoires } 17775519cab4SBenjamin Tissoires 17780fa9c616SBenjamin Tissoires /* 17790fa9c616SBenjamin Tissoires * This list contains only: 17800fa9c616SBenjamin Tissoires * - VID/PID of products not working with the default multitouch handling 17810fa9c616SBenjamin Tissoires * - 2 generic rules. 17820fa9c616SBenjamin Tissoires * So there is no point in adding here any device with MT_CLS_DEFAULT. 17830fa9c616SBenjamin Tissoires */ 17845519cab4SBenjamin Tissoires static const struct hid_device_id mt_devices[] = { 17855519cab4SBenjamin Tissoires 1786f786bba4SBenjamin Tissoires /* 3M panels */ 1787f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 17882c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 1789f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M1968) }, 1790f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 17912c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 1792f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M2256) }, 1793c4fad877SBenjamin Tissoires { .driver_data = MT_CLS_3M, 17942c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 1795c4fad877SBenjamin Tissoires USB_DEVICE_ID_3M3266) }, 1796f786bba4SBenjamin Tissoires 17976aef704eSBenjamin Tissoires /* Anton devices */ 17986aef704eSBenjamin Tissoires { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, 17996aef704eSBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_ANTON, 18006aef704eSBenjamin Tissoires USB_DEVICE_ID_ANTON_TOUCH_PAD) }, 1801e6aac342SBenjamin Tissoires 1802957b8dffSJoão Paulo Rechi Vita /* Asus T304UA */ 1803957b8dffSJoão Paulo Rechi Vita { .driver_data = MT_CLS_ASUS, 1804957b8dffSJoão Paulo Rechi Vita HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 1805957b8dffSJoão Paulo Rechi Vita USB_VENDOR_ID_ASUSTEK, 1806957b8dffSJoão Paulo Rechi Vita USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD) }, 1807957b8dffSJoão Paulo Rechi Vita 1808b1057124SBenjamin Tissoires /* Atmel panels */ 1809b1057124SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 18102c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 1811841cb157SBenjamin Tissoires USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, 1812b1057124SBenjamin Tissoires 18139ed32695SJiri Kosina /* Baanto multitouch devices */ 1814dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 181516b79bb8SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, 18169ed32695SJiri Kosina USB_DEVICE_ID_BAANTO_MT_190W2) }, 18170fa9c616SBenjamin Tissoires 1818a841b62cSBenjamin Tissoires /* Cando panels */ 1819a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 18202c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 1821a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, 1822a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 18232c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 1824a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, 1825a841b62cSBenjamin Tissoires 1826942fd422SAustin Zhang /* Chunghwa Telecom touch panels */ 1827dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 18282c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, 1829942fd422SAustin Zhang USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, 1830942fd422SAustin Zhang 1831070f63b4SYang Bo /* CJTouch panels */ 1832070f63b4SYang Bo { .driver_data = MT_CLS_NSMU, 1833070f63b4SYang Bo MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 1834070f63b4SYang Bo USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) }, 1835070f63b4SYang Bo { .driver_data = MT_CLS_NSMU, 1836070f63b4SYang Bo MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 1837070f63b4SYang Bo USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) }, 1838070f63b4SYang Bo 183979603dc9SBenjamin Tissoires /* CVTouch panels */ 1840dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 18412c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, 184279603dc9SBenjamin Tissoires USB_DEVICE_ID_CVTOUCH_SCREEN) }, 184379603dc9SBenjamin Tissoires 184422408283SBenjamin Tissoires /* eGalax devices (resistive) */ 184522408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 18462c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1847e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, 184822408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 18492c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1850e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, 185122408283SBenjamin Tissoires 185222408283SBenjamin Tissoires /* eGalax devices (capacitive) */ 1853fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18542c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1855fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) }, 185622408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 18572c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1858e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, 1859fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18602c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1861fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, 18622ce09df4SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18632c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18642ce09df4SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) }, 186522408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18662c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 186722408283SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) }, 1868fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18692c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1870fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) }, 187122408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 18722c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 187322408283SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, 187422408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 187522408283SBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1876e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, 1877fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18782c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1879fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) }, 18801fd8f047SChris Bagwell { .driver_data = MT_CLS_EGALAX, 1881aa672da1SAndy Shevchenko HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 1882aa672da1SAndy Shevchenko USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) }, 1883aa672da1SAndy Shevchenko { .driver_data = MT_CLS_EGALAX, 1884aa672da1SAndy Shevchenko HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 1885aa672da1SAndy Shevchenko USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) }, 1886aa672da1SAndy Shevchenko { .driver_data = MT_CLS_EGALAX, 18872c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 188866f06127SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, 188966f06127SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 18902c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1891bb9ff210SMarek Vasut USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, 18921b723e8dSBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18932c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1894fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, 1895fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 18962c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1897ae01c9e5SThierry Reding USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) }, 1898ae01c9e5SThierry Reding { .driver_data = MT_CLS_EGALAX_SERIAL, 1899ae01c9e5SThierry Reding MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1900e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, 1901f9e82295SSebastian Reichel { .driver_data = MT_CLS_EGALAX, 1902f9e82295SSebastian Reichel MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 1903f9e82295SSebastian Reichel USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) }, 190422408283SBenjamin Tissoires 190540d5bb87SBenjamin Tissoires /* Elan devices */ 190640d5bb87SBenjamin Tissoires { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 190740d5bb87SBenjamin Tissoires HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 190840d5bb87SBenjamin Tissoires USB_VENDOR_ID_ELAN, 0x313a) }, 190940d5bb87SBenjamin Tissoires 19107c7606a2STomas Sokorai /* Elitegroup panel */ 19117c7606a2STomas Sokorai { .driver_data = MT_CLS_SERIAL, 19127c7606a2STomas Sokorai MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP, 19137c7606a2STomas Sokorai USB_DEVICE_ID_ELITEGROUP_05D8) }, 19147c7606a2STomas Sokorai 191577723e3bSHenrik Rydberg /* Flatfrog Panels */ 191677723e3bSHenrik Rydberg { .driver_data = MT_CLS_FLATFROG, 191777723e3bSHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, 191877723e3bSHenrik Rydberg USB_DEVICE_ID_MULTITOUCH_3200) }, 191977723e3bSHenrik Rydberg 19203db187e7SBenjamin Tissoires /* FocalTech Panels */ 19213db187e7SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 19223db187e7SBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL, 19233db187e7SBenjamin Tissoires USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) }, 19243db187e7SBenjamin Tissoires 19255572da08SBenjamin Tissoires /* GeneralTouch panel */ 1926f5ff4e1eSXianhan Yu { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 19272c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19285572da08SBenjamin Tissoires USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, 1929f5ff4e1eSXianhan Yu { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 1930f5ff4e1eSXianhan Yu MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 1931f5ff4e1eSXianhan Yu USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, 19327b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 19337b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19347b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101) }, 19357b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19367b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19377b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102) }, 19387b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19397b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19407b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106) }, 19417b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19427b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19437b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A) }, 19447b226292SLuosong { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19457b226292SLuosong MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19467b226292SLuosong USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100) }, 19475572da08SBenjamin Tissoires 19484d5df5d1SAndreas Nielsen /* Gametel game controller */ 1949dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 19502c2110e9SHenrik Rydberg MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL, 19514d5df5d1SAndreas Nielsen USB_DEVICE_ID_GAMETEL_MT_MODE) }, 19524d5df5d1SAndreas Nielsen 1953ee0fbd14SBenjamin Tissoires /* GoodTouch panels */ 1954dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 19552c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, 1956ee0fbd14SBenjamin Tissoires USB_DEVICE_ID_GOODTOUCH_000f) }, 1957ee0fbd14SBenjamin Tissoires 195854580365SBenjamin Tissoires /* Hanvon panels */ 195954580365SBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 19602c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, 196154580365SBenjamin Tissoires USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, 196254580365SBenjamin Tissoires 19634e61f0d7SAustin Zhang /* Ilitek dual touch panel */ 1964dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 19652c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, 19664e61f0d7SAustin Zhang USB_DEVICE_ID_ILITEK_MULTITOUCH) }, 19674e61f0d7SAustin Zhang 1968f3287a99SBenjamin Tissoires /* LG Melfas panel */ 1969f3287a99SBenjamin Tissoires { .driver_data = MT_CLS_LG, 1970f3287a99SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_LG, 1971f3287a99SBenjamin Tissoires USB_DEVICE_ID_LG_MELFAS_MT) }, 1972348b80b2SAaron Ma { .driver_data = MT_CLS_LG, 1973348b80b2SAaron Ma HID_DEVICE(BUS_I2C, HID_GROUP_GENERIC, 1974348b80b2SAaron Ma USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_7010) }, 1975f3287a99SBenjamin Tissoires 19764a6a4c96SMikael Wikström /* Lenovo X1 TAB Gen 2 */ 19774a6a4c96SMikael Wikström { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 19784a6a4c96SMikael Wikström HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 19794a6a4c96SMikael Wikström USB_VENDOR_ID_LENOVO, 19804a6a4c96SMikael Wikström USB_DEVICE_ID_LENOVO_X1_TAB) }, 19814a6a4c96SMikael Wikström 1982140958daSMikael Wikström /* Lenovo X1 TAB Gen 3 */ 1983140958daSMikael Wikström { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 1984140958daSMikael Wikström HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 1985140958daSMikael Wikström USB_VENDOR_ID_LENOVO, 1986140958daSMikael Wikström USB_DEVICE_ID_LENOVO_X1_TAB3) }, 1987140958daSMikael Wikström 19884a6ee685SBenjamin Tissoires /* MosArt panels */ 19894a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 19902c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 19914a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUS_T91MT)}, 19924a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 19932c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 19944a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 19954a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 19962c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, 19974a6ee685SBenjamin Tissoires USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 19984a6ee685SBenjamin Tissoires 19994db703eaSAustin Hendrix /* Novatek Panel */ 2000dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 20014380d819SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, 20024db703eaSAustin Hendrix USB_DEVICE_ID_NOVATEK_PCT) }, 20034db703eaSAustin Hendrix 2004a80e803aSBenjamin Tissoires /* Ntrig Panel */ 2005a80e803aSBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 2006a80e803aSBenjamin Tissoires HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 2007a80e803aSBenjamin Tissoires USB_VENDOR_ID_NTRIG, 0x1b05) }, 2008a80e803aSBenjamin Tissoires 2009fb55b402SHans de Goede /* Panasonic panels */ 2010fb55b402SHans de Goede { .driver_data = MT_CLS_PANASONIC, 2011fb55b402SHans de Goede MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 2012fb55b402SHans de Goede USB_DEVICE_ID_PANABOARD_UBT780) }, 2013fb55b402SHans de Goede { .driver_data = MT_CLS_PANASONIC, 2014fb55b402SHans de Goede MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 2015fb55b402SHans de Goede USB_DEVICE_ID_PANABOARD_UBT880) }, 2016fb55b402SHans de Goede 2017b7ea95ffSAaron Tian /* PixArt optical touch screen */ 2018b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 20192c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 2020b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) }, 2021b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 20222c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 2023b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) }, 2024b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 20252c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 2026b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) }, 2027b7ea95ffSAaron Tian 20285519cab4SBenjamin Tissoires /* PixCir-based panels */ 20291e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 20302c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 20315519cab4SBenjamin Tissoires USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, 20325519cab4SBenjamin Tissoires 20335e7ea11fSBenjamin Tissoires /* Quanta-based panels */ 20345e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 20352c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 20365e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, 2037a6802e00SForest Bond 2038843e475fSBenjamin Tissoires /* Razer touchpads */ 2039843e475fSBenjamin Tissoires { .driver_data = MT_CLS_RAZER_BLADE_STEALTH, 2040843e475fSBenjamin Tissoires HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 2041843e475fSBenjamin Tissoires USB_VENDOR_ID_SYNAPTICS, 0x8323) }, 2042843e475fSBenjamin Tissoires 204369ecd44dSBenjamin Tissoires /* Smart Tech panels */ 204469ecd44dSBenjamin Tissoires { .driver_data = MT_CLS_SMART_TECH, 204569ecd44dSBenjamin Tissoires MT_USB_DEVICE(0x0b8c, 0x0092)}, 204669ecd44dSBenjamin Tissoires 2047043b403aSBenjamin Tissoires /* Stantum panels */ 2048bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 20492c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, 2050043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_STM)}, 2051043b403aSBenjamin Tissoires 205240d5bb87SBenjamin Tissoires /* Synaptics devices */ 205340d5bb87SBenjamin Tissoires { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 205440d5bb87SBenjamin Tissoires HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 205540d5bb87SBenjamin Tissoires USB_VENDOR_ID_SYNAPTICS, 0xce08) }, 205640d5bb87SBenjamin Tissoires 2057*c3d6eb6eSKai-Heng Feng { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 2058*c3d6eb6eSKai-Heng Feng HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 2059*c3d6eb6eSKai-Heng Feng USB_VENDOR_ID_SYNAPTICS, 0xce09) }, 2060*c3d6eb6eSKai-Heng Feng 2061847672cdSBenjamin Tissoires /* TopSeed panels */ 2062847672cdSBenjamin Tissoires { .driver_data = MT_CLS_TOPSEED, 20632c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, 2064847672cdSBenjamin Tissoires USB_DEVICE_ID_TOPSEED2_PERIPAD_701) }, 2065847672cdSBenjamin Tissoires 20665e74e56dSBenjamin Tissoires /* Touch International panels */ 2067dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 20682c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, 20695e74e56dSBenjamin Tissoires USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, 20705e74e56dSBenjamin Tissoires 2071617b64f9SBenjamin Tissoires /* Unitec panels */ 2072dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 20732c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 2074617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, 2075dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 20762c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 2077617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, 2078bf9d121eSKaiChung Cheng 2079da10bc25SMathieu Magnaudet /* VTL panels */ 2080da10bc25SMathieu Magnaudet { .driver_data = MT_CLS_VTL, 2081da10bc25SMathieu Magnaudet MT_USB_DEVICE(USB_VENDOR_ID_VTL, 2082da10bc25SMathieu Magnaudet USB_DEVICE_ID_VTL_MULTITOUCH_FF3F) }, 2083da10bc25SMathieu Magnaudet 2084bf9d121eSKaiChung Cheng /* Wistron panels */ 2085bf9d121eSKaiChung Cheng { .driver_data = MT_CLS_NSMU, 2086bf9d121eSKaiChung Cheng MT_USB_DEVICE(USB_VENDOR_ID_WISTRON, 2087bf9d121eSKaiChung Cheng USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH) }, 2088bf9d121eSKaiChung Cheng 2089bc8a2a9bSice chien /* XAT */ 2090dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 20912c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XAT, 2092bc8a2a9bSice chien USB_DEVICE_ID_XAT_CSR) }, 2093617b64f9SBenjamin Tissoires 209411576c61SMasatoshi Hoshikawa /* Xiroku */ 2095dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 20962c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 209711576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX) }, 2098dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 20992c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 210011576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX) }, 2101dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 21022c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 210311576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR) }, 2104dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 21052c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 210611576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX1) }, 2107dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 21082c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 210911576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX1) }, 2110dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 21112c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 211211576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR1) }, 2113dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 21142c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 211511576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX2) }, 2116dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 21172c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 211811576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX2) }, 2119dc3e1d80SBenjamin Tissoires { .driver_data = MT_CLS_NSMU, 21202c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 212111576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR2) }, 212211576c61SMasatoshi Hoshikawa 21230e82232cSWei-Ning Huang /* Google MT devices */ 21240e82232cSWei-Ning Huang { .driver_data = MT_CLS_GOOGLE, 21250e82232cSWei-Ning Huang HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, 21260e82232cSWei-Ning Huang USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) }, 21270e82232cSWei-Ning Huang 21284fa3a583SHenrik Rydberg /* Generic MT device */ 21294fa3a583SHenrik Rydberg { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, 2130f961bd35SBenjamin Tissoires 2131f961bd35SBenjamin Tissoires /* Generic Win 8 certified MT device */ 2132f961bd35SBenjamin Tissoires { .driver_data = MT_CLS_WIN_8, 2133f961bd35SBenjamin Tissoires HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8, 2134f961bd35SBenjamin Tissoires HID_ANY_ID, HID_ANY_ID) }, 21355519cab4SBenjamin Tissoires { } 21365519cab4SBenjamin Tissoires }; 21375519cab4SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, mt_devices); 21385519cab4SBenjamin Tissoires 21395519cab4SBenjamin Tissoires static const struct hid_usage_id mt_grabbed_usages[] = { 21405519cab4SBenjamin Tissoires { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 21415519cab4SBenjamin Tissoires { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 21425519cab4SBenjamin Tissoires }; 21435519cab4SBenjamin Tissoires 21445519cab4SBenjamin Tissoires static struct hid_driver mt_driver = { 21455519cab4SBenjamin Tissoires .name = "hid-multitouch", 21465519cab4SBenjamin Tissoires .id_table = mt_devices, 21475519cab4SBenjamin Tissoires .probe = mt_probe, 21485519cab4SBenjamin Tissoires .remove = mt_remove, 21495519cab4SBenjamin Tissoires .input_mapping = mt_input_mapping, 21505519cab4SBenjamin Tissoires .input_mapped = mt_input_mapped, 215176f5902aSHenrik Rydberg .input_configured = mt_input_configured, 21525519cab4SBenjamin Tissoires .feature_mapping = mt_feature_mapping, 21535519cab4SBenjamin Tissoires .usage_table = mt_grabbed_usages, 21545519cab4SBenjamin Tissoires .event = mt_event, 215555978fa9SBenjamin Tissoires .report = mt_report, 21565519cab4SBenjamin Tissoires #ifdef CONFIG_PM 21575519cab4SBenjamin Tissoires .reset_resume = mt_reset_resume, 2158dfeefd10SScott Liu .resume = mt_resume, 21595519cab4SBenjamin Tissoires #endif 21605519cab4SBenjamin Tissoires }; 2161f425458eSH Hartley Sweeten module_hid_driver(mt_driver); 2162