18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * HID driver for multitouch panels 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> 68c2ecf20Sopenharmony_ci * Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com> 78c2ecf20Sopenharmony_ci * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France 88c2ecf20Sopenharmony_ci * Copyright (c) 2012-2013 Red Hat, Inc 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This code is partly based on hid-egalax.c: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> 138c2ecf20Sopenharmony_ci * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 148c2ecf20Sopenharmony_ci * Copyright (c) 2010 Canonical, Ltd. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This code is partly based on hid-3m-pct.c: 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> 198c2ecf20Sopenharmony_ci * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 208c2ecf20Sopenharmony_ci * Copyright (c) 2010 Canonical, Ltd. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * This driver is regularly tested thanks to the test suite in hid-tools[1]. 288c2ecf20Sopenharmony_ci * Please run these regression tests before patching this module so that 298c2ecf20Sopenharmony_ci * your patch won't break existing known devices. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * [1] https://gitlab.freedesktop.org/libevdev/hid-tools 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/device.h> 358c2ecf20Sopenharmony_ci#include <linux/hid.h> 368c2ecf20Sopenharmony_ci#include <linux/module.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 398c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 408c2ecf20Sopenharmony_ci#include <linux/string.h> 418c2ecf20Sopenharmony_ci#include <linux/timer.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); 458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HID multitouch panels"); 478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "hid-ids.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* quirks to control the device */ 528c2ecf20Sopenharmony_ci#define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) 538c2ecf20Sopenharmony_ci#define MT_QUIRK_SLOT_IS_CONTACTID BIT(1) 548c2ecf20Sopenharmony_ci#define MT_QUIRK_CYPRESS BIT(2) 558c2ecf20Sopenharmony_ci#define MT_QUIRK_SLOT_IS_CONTACTNUMBER BIT(3) 568c2ecf20Sopenharmony_ci#define MT_QUIRK_ALWAYS_VALID BIT(4) 578c2ecf20Sopenharmony_ci#define MT_QUIRK_VALID_IS_INRANGE BIT(5) 588c2ecf20Sopenharmony_ci#define MT_QUIRK_VALID_IS_CONFIDENCE BIT(6) 598c2ecf20Sopenharmony_ci#define MT_QUIRK_CONFIDENCE BIT(7) 608c2ecf20Sopenharmony_ci#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE BIT(8) 618c2ecf20Sopenharmony_ci#define MT_QUIRK_NO_AREA BIT(9) 628c2ecf20Sopenharmony_ci#define MT_QUIRK_IGNORE_DUPLICATES BIT(10) 638c2ecf20Sopenharmony_ci#define MT_QUIRK_HOVERING BIT(11) 648c2ecf20Sopenharmony_ci#define MT_QUIRK_CONTACT_CNT_ACCURATE BIT(12) 658c2ecf20Sopenharmony_ci#define MT_QUIRK_FORCE_GET_FEATURE BIT(13) 668c2ecf20Sopenharmony_ci#define MT_QUIRK_FIX_CONST_CONTACT_ID BIT(14) 678c2ecf20Sopenharmony_ci#define MT_QUIRK_TOUCH_SIZE_SCALING BIT(15) 688c2ecf20Sopenharmony_ci#define MT_QUIRK_STICKY_FINGERS BIT(16) 698c2ecf20Sopenharmony_ci#define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) 708c2ecf20Sopenharmony_ci#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18) 718c2ecf20Sopenharmony_ci#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19) 728c2ecf20Sopenharmony_ci#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define MT_INPUTMODE_TOUCHSCREEN 0x02 758c2ecf20Sopenharmony_ci#define MT_INPUTMODE_TOUCHPAD 0x03 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define MT_BUTTONTYPE_CLICKPAD 0 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cienum latency_mode { 808c2ecf20Sopenharmony_ci HID_LATENCY_NORMAL = 0, 818c2ecf20Sopenharmony_ci HID_LATENCY_HIGH = 1, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define MT_IO_FLAGS_RUNNING 0 858c2ecf20Sopenharmony_ci#define MT_IO_FLAGS_ACTIVE_SLOTS 1 868c2ecf20Sopenharmony_ci#define MT_IO_FLAGS_PENDING_SLOTS 2 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const bool mtrue = true; /* default for true */ 898c2ecf20Sopenharmony_cistatic const bool mfalse; /* default for false */ 908c2ecf20Sopenharmony_cistatic const __s32 mzero; /* default for 0 */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define DEFAULT_TRUE ((void *)&mtrue) 938c2ecf20Sopenharmony_ci#define DEFAULT_FALSE ((void *)&mfalse) 948c2ecf20Sopenharmony_ci#define DEFAULT_ZERO ((void *)&mzero) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistruct mt_usages { 978c2ecf20Sopenharmony_ci struct list_head list; 988c2ecf20Sopenharmony_ci __s32 *x, *y, *cx, *cy, *p, *w, *h, *a; 998c2ecf20Sopenharmony_ci __s32 *contactid; /* the device ContactID assigned to this slot */ 1008c2ecf20Sopenharmony_ci bool *tip_state; /* is the touch valid? */ 1018c2ecf20Sopenharmony_ci bool *inrange_state; /* is the finger in proximity of the sensor? */ 1028c2ecf20Sopenharmony_ci bool *confidence_state; /* is the touch made by a finger? */ 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistruct mt_application { 1068c2ecf20Sopenharmony_ci struct list_head list; 1078c2ecf20Sopenharmony_ci unsigned int application; 1088c2ecf20Sopenharmony_ci unsigned int report_id; 1098c2ecf20Sopenharmony_ci struct list_head mt_usages; /* mt usages list */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci __s32 quirks; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci __s32 *scantime; /* scantime reported */ 1148c2ecf20Sopenharmony_ci __s32 scantime_logical_max; /* max value for raw scantime */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci __s32 *raw_cc; /* contact count in the report */ 1178c2ecf20Sopenharmony_ci int left_button_state; /* left button state */ 1188c2ecf20Sopenharmony_ci unsigned int mt_flags; /* flags to pass to input-mt */ 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci unsigned long *pending_palm_slots; /* slots where we reported palm 1218c2ecf20Sopenharmony_ci * and need to release */ 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci __u8 num_received; /* how many contacts we received */ 1248c2ecf20Sopenharmony_ci __u8 num_expected; /* expected last contact index */ 1258c2ecf20Sopenharmony_ci __u8 buttons_count; /* number of physical buttons per touchpad */ 1268c2ecf20Sopenharmony_ci __u8 touches_by_report; /* how many touches are present in one report: 1278c2ecf20Sopenharmony_ci * 1 means we should use a serial protocol 1288c2ecf20Sopenharmony_ci * > 1 means hybrid (multitouch) protocol 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci __s32 dev_time; /* the scan time provided by the device */ 1328c2ecf20Sopenharmony_ci unsigned long jiffies; /* the frame's jiffies */ 1338c2ecf20Sopenharmony_ci int timestamp; /* the timestamp to be sent */ 1348c2ecf20Sopenharmony_ci int prev_scantime; /* scantime reported previously */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci bool have_contact_count; 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistruct mt_class { 1408c2ecf20Sopenharmony_ci __s32 name; /* MT_CLS */ 1418c2ecf20Sopenharmony_ci __s32 quirks; 1428c2ecf20Sopenharmony_ci __s32 sn_move; /* Signal/noise ratio for move events */ 1438c2ecf20Sopenharmony_ci __s32 sn_width; /* Signal/noise ratio for width events */ 1448c2ecf20Sopenharmony_ci __s32 sn_height; /* Signal/noise ratio for height events */ 1458c2ecf20Sopenharmony_ci __s32 sn_pressure; /* Signal/noise ratio for pressure events */ 1468c2ecf20Sopenharmony_ci __u8 maxcontacts; 1478c2ecf20Sopenharmony_ci bool is_indirect; /* true for touchpads */ 1488c2ecf20Sopenharmony_ci bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */ 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistruct mt_report_data { 1528c2ecf20Sopenharmony_ci struct list_head list; 1538c2ecf20Sopenharmony_ci struct hid_report *report; 1548c2ecf20Sopenharmony_ci struct mt_application *application; 1558c2ecf20Sopenharmony_ci bool is_mt_collection; 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistruct mt_device { 1598c2ecf20Sopenharmony_ci struct mt_class mtclass; /* our mt device class */ 1608c2ecf20Sopenharmony_ci struct timer_list release_timer; /* to release sticky fingers */ 1618c2ecf20Sopenharmony_ci struct hid_device *hdev; /* hid_device we're attached to */ 1628c2ecf20Sopenharmony_ci unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ 1638c2ecf20Sopenharmony_ci __u8 inputmode_value; /* InputMode HID feature value */ 1648c2ecf20Sopenharmony_ci __u8 maxcontacts; 1658c2ecf20Sopenharmony_ci bool is_buttonpad; /* is this device a button pad? */ 1668c2ecf20Sopenharmony_ci bool serial_maybe; /* need to check for serial protocol */ 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci struct list_head applications; 1698c2ecf20Sopenharmony_ci struct list_head reports; 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void mt_post_parse_default_settings(struct mt_device *td, 1738c2ecf20Sopenharmony_ci struct mt_application *app); 1748c2ecf20Sopenharmony_cistatic void mt_post_parse(struct mt_device *td, struct mt_application *app); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* classes of device behavior */ 1778c2ecf20Sopenharmony_ci#define MT_CLS_DEFAULT 0x0001 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#define MT_CLS_SERIAL 0x0002 1808c2ecf20Sopenharmony_ci#define MT_CLS_CONFIDENCE 0x0003 1818c2ecf20Sopenharmony_ci#define MT_CLS_CONFIDENCE_CONTACT_ID 0x0004 1828c2ecf20Sopenharmony_ci#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 1838c2ecf20Sopenharmony_ci#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 1848c2ecf20Sopenharmony_ci#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 1858c2ecf20Sopenharmony_ci/* reserved 0x0008 */ 1868c2ecf20Sopenharmony_ci#define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 1878c2ecf20Sopenharmony_ci#define MT_CLS_NSMU 0x000a 1888c2ecf20Sopenharmony_ci/* reserved 0x0010 */ 1898c2ecf20Sopenharmony_ci/* reserved 0x0011 */ 1908c2ecf20Sopenharmony_ci#define MT_CLS_WIN_8 0x0012 1918c2ecf20Sopenharmony_ci#define MT_CLS_EXPORT_ALL_INPUTS 0x0013 1928c2ecf20Sopenharmony_ci/* reserved 0x0014 */ 1938c2ecf20Sopenharmony_ci#define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* vendor specific classes */ 1968c2ecf20Sopenharmony_ci#define MT_CLS_3M 0x0101 1978c2ecf20Sopenharmony_ci/* reserved 0x0102 */ 1988c2ecf20Sopenharmony_ci#define MT_CLS_EGALAX 0x0103 1998c2ecf20Sopenharmony_ci#define MT_CLS_EGALAX_SERIAL 0x0104 2008c2ecf20Sopenharmony_ci#define MT_CLS_TOPSEED 0x0105 2018c2ecf20Sopenharmony_ci#define MT_CLS_PANASONIC 0x0106 2028c2ecf20Sopenharmony_ci#define MT_CLS_FLATFROG 0x0107 2038c2ecf20Sopenharmony_ci#define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 2048c2ecf20Sopenharmony_ci#define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 2058c2ecf20Sopenharmony_ci#define MT_CLS_LG 0x010a 2068c2ecf20Sopenharmony_ci#define MT_CLS_ASUS 0x010b 2078c2ecf20Sopenharmony_ci#define MT_CLS_VTL 0x0110 2088c2ecf20Sopenharmony_ci#define MT_CLS_GOOGLE 0x0111 2098c2ecf20Sopenharmony_ci#define MT_CLS_RAZER_BLADE_STEALTH 0x0112 2108c2ecf20Sopenharmony_ci#define MT_CLS_SMART_TECH 0x0113 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#define MT_DEFAULT_MAXCONTACT 10 2138c2ecf20Sopenharmony_ci#define MT_MAX_MAXCONTACT 250 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* 2168c2ecf20Sopenharmony_ci * Resync device and local timestamps after that many microseconds without 2178c2ecf20Sopenharmony_ci * receiving data. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci#define MAX_TIMESTAMP_INTERVAL 1000000 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci#define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) 2228c2ecf20Sopenharmony_ci#define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* 2258c2ecf20Sopenharmony_ci * these device-dependent functions determine what slot corresponds 2268c2ecf20Sopenharmony_ci * to a valid contact that was just read. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int cypress_compute_slot(struct mt_application *application, 2308c2ecf20Sopenharmony_ci struct mt_usages *slot) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci if (*slot->contactid != 0 || application->num_received == 0) 2338c2ecf20Sopenharmony_ci return *slot->contactid; 2348c2ecf20Sopenharmony_ci else 2358c2ecf20Sopenharmony_ci return -1; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic const struct mt_class mt_classes[] = { 2398c2ecf20Sopenharmony_ci { .name = MT_CLS_DEFAULT, 2408c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 2418c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE }, 2428c2ecf20Sopenharmony_ci { .name = MT_CLS_NSMU, 2438c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, 2448c2ecf20Sopenharmony_ci { .name = MT_CLS_SERIAL, 2458c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID}, 2468c2ecf20Sopenharmony_ci { .name = MT_CLS_CONFIDENCE, 2478c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, 2488c2ecf20Sopenharmony_ci { .name = MT_CLS_CONFIDENCE_CONTACT_ID, 2498c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 2508c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID }, 2518c2ecf20Sopenharmony_ci { .name = MT_CLS_CONFIDENCE_MINUS_ONE, 2528c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 2538c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, 2548c2ecf20Sopenharmony_ci { .name = MT_CLS_DUAL_INRANGE_CONTACTID, 2558c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_INRANGE | 2568c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID, 2578c2ecf20Sopenharmony_ci .maxcontacts = 2 }, 2588c2ecf20Sopenharmony_ci { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 2598c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_INRANGE | 2608c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTNUMBER, 2618c2ecf20Sopenharmony_ci .maxcontacts = 2 }, 2628c2ecf20Sopenharmony_ci { .name = MT_CLS_INRANGE_CONTACTNUMBER, 2638c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_INRANGE | 2648c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTNUMBER }, 2658c2ecf20Sopenharmony_ci { .name = MT_CLS_WIN_8, 2668c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 2678c2ecf20Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 2688c2ecf20Sopenharmony_ci MT_QUIRK_HOVERING | 2698c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 2708c2ecf20Sopenharmony_ci MT_QUIRK_STICKY_FINGERS | 2718c2ecf20Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS, 2728c2ecf20Sopenharmony_ci .export_all_inputs = true }, 2738c2ecf20Sopenharmony_ci { .name = MT_CLS_EXPORT_ALL_INPUTS, 2748c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 2758c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE, 2768c2ecf20Sopenharmony_ci .export_all_inputs = true }, 2778c2ecf20Sopenharmony_ci { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 2788c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 2798c2ecf20Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 2808c2ecf20Sopenharmony_ci MT_QUIRK_HOVERING | 2818c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 2828c2ecf20Sopenharmony_ci MT_QUIRK_STICKY_FINGERS | 2838c2ecf20Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS | 2848c2ecf20Sopenharmony_ci MT_QUIRK_FORCE_MULTI_INPUT, 2858c2ecf20Sopenharmony_ci .export_all_inputs = true }, 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* 2888c2ecf20Sopenharmony_ci * vendor specific classes 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci { .name = MT_CLS_3M, 2918c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 2928c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID | 2938c2ecf20Sopenharmony_ci MT_QUIRK_TOUCH_SIZE_SCALING, 2948c2ecf20Sopenharmony_ci .sn_move = 2048, 2958c2ecf20Sopenharmony_ci .sn_width = 128, 2968c2ecf20Sopenharmony_ci .sn_height = 128, 2978c2ecf20Sopenharmony_ci .maxcontacts = 60, 2988c2ecf20Sopenharmony_ci }, 2998c2ecf20Sopenharmony_ci { .name = MT_CLS_EGALAX, 3008c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 3018c2ecf20Sopenharmony_ci MT_QUIRK_VALID_IS_INRANGE, 3028c2ecf20Sopenharmony_ci .sn_move = 4096, 3038c2ecf20Sopenharmony_ci .sn_pressure = 32, 3048c2ecf20Sopenharmony_ci }, 3058c2ecf20Sopenharmony_ci { .name = MT_CLS_EGALAX_SERIAL, 3068c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 3078c2ecf20Sopenharmony_ci MT_QUIRK_ALWAYS_VALID, 3088c2ecf20Sopenharmony_ci .sn_move = 4096, 3098c2ecf20Sopenharmony_ci .sn_pressure = 32, 3108c2ecf20Sopenharmony_ci }, 3118c2ecf20Sopenharmony_ci { .name = MT_CLS_TOPSEED, 3128c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID, 3138c2ecf20Sopenharmony_ci .is_indirect = true, 3148c2ecf20Sopenharmony_ci .maxcontacts = 2, 3158c2ecf20Sopenharmony_ci }, 3168c2ecf20Sopenharmony_ci { .name = MT_CLS_PANASONIC, 3178c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, 3188c2ecf20Sopenharmony_ci .maxcontacts = 4 }, 3198c2ecf20Sopenharmony_ci { .name = MT_CLS_GENERALTOUCH_TWOFINGERS, 3208c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 3218c2ecf20Sopenharmony_ci MT_QUIRK_VALID_IS_INRANGE | 3228c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID, 3238c2ecf20Sopenharmony_ci .maxcontacts = 2 3248c2ecf20Sopenharmony_ci }, 3258c2ecf20Sopenharmony_ci { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 3268c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 3278c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID 3288c2ecf20Sopenharmony_ci }, 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci { .name = MT_CLS_FLATFROG, 3318c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 3328c2ecf20Sopenharmony_ci MT_QUIRK_NO_AREA, 3338c2ecf20Sopenharmony_ci .sn_move = 2048, 3348c2ecf20Sopenharmony_ci .maxcontacts = 40, 3358c2ecf20Sopenharmony_ci }, 3368c2ecf20Sopenharmony_ci { .name = MT_CLS_LG, 3378c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 3388c2ecf20Sopenharmony_ci MT_QUIRK_FIX_CONST_CONTACT_ID | 3398c2ecf20Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 3408c2ecf20Sopenharmony_ci MT_QUIRK_HOVERING | 3418c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE }, 3428c2ecf20Sopenharmony_ci { .name = MT_CLS_ASUS, 3438c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 3448c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 3458c2ecf20Sopenharmony_ci MT_QUIRK_ASUS_CUSTOM_UP }, 3468c2ecf20Sopenharmony_ci { .name = MT_CLS_VTL, 3478c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 3488c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 3498c2ecf20Sopenharmony_ci MT_QUIRK_FORCE_GET_FEATURE, 3508c2ecf20Sopenharmony_ci }, 3518c2ecf20Sopenharmony_ci { .name = MT_CLS_GOOGLE, 3528c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 3538c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 3548c2ecf20Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID | 3558c2ecf20Sopenharmony_ci MT_QUIRK_HOVERING 3568c2ecf20Sopenharmony_ci }, 3578c2ecf20Sopenharmony_ci { .name = MT_CLS_RAZER_BLADE_STEALTH, 3588c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 3598c2ecf20Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 3608c2ecf20Sopenharmony_ci MT_QUIRK_HOVERING | 3618c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 3628c2ecf20Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS, 3638c2ecf20Sopenharmony_ci }, 3648c2ecf20Sopenharmony_ci { .name = MT_CLS_SMART_TECH, 3658c2ecf20Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 3668c2ecf20Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 3678c2ecf20Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 3688c2ecf20Sopenharmony_ci MT_QUIRK_SEPARATE_APP_REPORT, 3698c2ecf20Sopenharmony_ci }, 3708c2ecf20Sopenharmony_ci { } 3718c2ecf20Sopenharmony_ci}; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic ssize_t mt_show_quirks(struct device *dev, 3748c2ecf20Sopenharmony_ci struct device_attribute *attr, 3758c2ecf20Sopenharmony_ci char *buf) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct hid_device *hdev = to_hid_device(dev); 3788c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", td->mtclass.quirks); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic ssize_t mt_set_quirks(struct device *dev, 3848c2ecf20Sopenharmony_ci struct device_attribute *attr, 3858c2ecf20Sopenharmony_ci const char *buf, size_t count) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct hid_device *hdev = to_hid_device(dev); 3888c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 3898c2ecf20Sopenharmony_ci struct mt_application *application; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci unsigned long val; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (kstrtoul(buf, 0, &val)) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci td->mtclass.quirks = val; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci list_for_each_entry(application, &td->applications, list) { 3998c2ecf20Sopenharmony_ci application->quirks = val; 4008c2ecf20Sopenharmony_ci if (!application->have_contact_count) 4018c2ecf20Sopenharmony_ci application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return count; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic struct attribute *sysfs_attrs[] = { 4108c2ecf20Sopenharmony_ci &dev_attr_quirks.attr, 4118c2ecf20Sopenharmony_ci NULL 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic const struct attribute_group mt_attribute_group = { 4158c2ecf20Sopenharmony_ci .attrs = sysfs_attrs 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic void mt_get_feature(struct hid_device *hdev, struct hid_report *report) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci int ret; 4218c2ecf20Sopenharmony_ci u32 size = hid_report_len(report); 4228c2ecf20Sopenharmony_ci u8 *buf; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* 4258c2ecf20Sopenharmony_ci * Do not fetch the feature report if the device has been explicitly 4268c2ecf20Sopenharmony_ci * marked as non-capable. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci if (hdev->quirks & HID_QUIRK_NO_INIT_REPORTS) 4298c2ecf20Sopenharmony_ci return; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci buf = hid_alloc_report_buf(report, GFP_KERNEL); 4328c2ecf20Sopenharmony_ci if (!buf) 4338c2ecf20Sopenharmony_ci return; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ret = hid_hw_raw_request(hdev, report->id, buf, size, 4368c2ecf20Sopenharmony_ci HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 4378c2ecf20Sopenharmony_ci if (ret < 0) { 4388c2ecf20Sopenharmony_ci dev_warn(&hdev->dev, "failed to fetch feature %d\n", 4398c2ecf20Sopenharmony_ci report->id); 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, 4428c2ecf20Sopenharmony_ci size, 0); 4438c2ecf20Sopenharmony_ci if (ret) 4448c2ecf20Sopenharmony_ci dev_warn(&hdev->dev, "failed to report feature\n"); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci kfree(buf); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void mt_feature_mapping(struct hid_device *hdev, 4518c2ecf20Sopenharmony_ci struct hid_field *field, struct hid_usage *usage) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci switch (usage->hid) { 4568c2ecf20Sopenharmony_ci case HID_DG_CONTACTMAX: 4578c2ecf20Sopenharmony_ci mt_get_feature(hdev, field->report); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci td->maxcontacts = field->value[0]; 4608c2ecf20Sopenharmony_ci if (!td->maxcontacts && 4618c2ecf20Sopenharmony_ci field->logical_maximum <= MT_MAX_MAXCONTACT) 4628c2ecf20Sopenharmony_ci td->maxcontacts = field->logical_maximum; 4638c2ecf20Sopenharmony_ci if (td->mtclass.maxcontacts) 4648c2ecf20Sopenharmony_ci /* check if the maxcontacts is given by the class */ 4658c2ecf20Sopenharmony_ci td->maxcontacts = td->mtclass.maxcontacts; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case HID_DG_BUTTONTYPE: 4698c2ecf20Sopenharmony_ci if (usage->usage_index >= field->report_count) { 4708c2ecf20Sopenharmony_ci dev_err(&hdev->dev, "HID_DG_BUTTONTYPE out of range\n"); 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci mt_get_feature(hdev, field->report); 4758c2ecf20Sopenharmony_ci if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD) 4768c2ecf20Sopenharmony_ci td->is_buttonpad = true; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci case 0xff0000c5: 4808c2ecf20Sopenharmony_ci /* Retrieve the Win8 blob once to enable some devices */ 4818c2ecf20Sopenharmony_ci if (usage->usage_index == 0) 4828c2ecf20Sopenharmony_ci mt_get_feature(hdev, field->report); 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic void set_abs(struct input_dev *input, unsigned int code, 4888c2ecf20Sopenharmony_ci struct hid_field *field, int snratio) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci int fmin = field->logical_minimum; 4918c2ecf20Sopenharmony_ci int fmax = field->logical_maximum; 4928c2ecf20Sopenharmony_ci int fuzz = snratio ? (fmax - fmin) / snratio : 0; 4938c2ecf20Sopenharmony_ci input_set_abs_params(input, code, fmin, fmax, fuzz, 0); 4948c2ecf20Sopenharmony_ci input_abs_set_res(input, code, hidinput_calc_abs_res(field, code)); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic struct mt_usages *mt_allocate_usage(struct hid_device *hdev, 4988c2ecf20Sopenharmony_ci struct mt_application *application) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct mt_usages *usage; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci usage = devm_kzalloc(&hdev->dev, sizeof(*usage), GFP_KERNEL); 5038c2ecf20Sopenharmony_ci if (!usage) 5048c2ecf20Sopenharmony_ci return NULL; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* set some defaults so we do not need to check for null pointers */ 5078c2ecf20Sopenharmony_ci usage->x = DEFAULT_ZERO; 5088c2ecf20Sopenharmony_ci usage->y = DEFAULT_ZERO; 5098c2ecf20Sopenharmony_ci usage->cx = DEFAULT_ZERO; 5108c2ecf20Sopenharmony_ci usage->cy = DEFAULT_ZERO; 5118c2ecf20Sopenharmony_ci usage->p = DEFAULT_ZERO; 5128c2ecf20Sopenharmony_ci usage->w = DEFAULT_ZERO; 5138c2ecf20Sopenharmony_ci usage->h = DEFAULT_ZERO; 5148c2ecf20Sopenharmony_ci usage->a = DEFAULT_ZERO; 5158c2ecf20Sopenharmony_ci usage->contactid = DEFAULT_ZERO; 5168c2ecf20Sopenharmony_ci usage->tip_state = DEFAULT_FALSE; 5178c2ecf20Sopenharmony_ci usage->inrange_state = DEFAULT_FALSE; 5188c2ecf20Sopenharmony_ci usage->confidence_state = DEFAULT_TRUE; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci list_add_tail(&usage->list, &application->mt_usages); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return usage; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic struct mt_application *mt_allocate_application(struct mt_device *td, 5268c2ecf20Sopenharmony_ci struct hid_report *report) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci unsigned int application = report->application; 5298c2ecf20Sopenharmony_ci struct mt_application *mt_application; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application), 5328c2ecf20Sopenharmony_ci GFP_KERNEL); 5338c2ecf20Sopenharmony_ci if (!mt_application) 5348c2ecf20Sopenharmony_ci return NULL; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci mt_application->application = application; 5378c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mt_application->mt_usages); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (application == HID_DG_TOUCHSCREEN) 5408c2ecf20Sopenharmony_ci mt_application->mt_flags |= INPUT_MT_DIRECT; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* 5438c2ecf20Sopenharmony_ci * Model touchscreens providing buttons as touchpads. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ci if (application == HID_DG_TOUCHPAD) { 5468c2ecf20Sopenharmony_ci mt_application->mt_flags |= INPUT_MT_POINTER; 5478c2ecf20Sopenharmony_ci td->inputmode_value = MT_INPUTMODE_TOUCHPAD; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci mt_application->scantime = DEFAULT_ZERO; 5518c2ecf20Sopenharmony_ci mt_application->raw_cc = DEFAULT_ZERO; 5528c2ecf20Sopenharmony_ci mt_application->quirks = td->mtclass.quirks; 5538c2ecf20Sopenharmony_ci mt_application->report_id = report->id; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci list_add_tail(&mt_application->list, &td->applications); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return mt_application; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic struct mt_application *mt_find_application(struct mt_device *td, 5618c2ecf20Sopenharmony_ci struct hid_report *report) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci unsigned int application = report->application; 5648c2ecf20Sopenharmony_ci struct mt_application *tmp, *mt_application = NULL; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &td->applications, list) { 5678c2ecf20Sopenharmony_ci if (application == tmp->application) { 5688c2ecf20Sopenharmony_ci if (!(td->mtclass.quirks & MT_QUIRK_SEPARATE_APP_REPORT) || 5698c2ecf20Sopenharmony_ci tmp->report_id == report->id) { 5708c2ecf20Sopenharmony_ci mt_application = tmp; 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (!mt_application) 5778c2ecf20Sopenharmony_ci mt_application = mt_allocate_application(td, report); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return mt_application; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic struct mt_report_data *mt_allocate_report_data(struct mt_device *td, 5838c2ecf20Sopenharmony_ci struct hid_report *report) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct mt_report_data *rdata; 5868c2ecf20Sopenharmony_ci struct hid_field *field; 5878c2ecf20Sopenharmony_ci int r, n; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL); 5908c2ecf20Sopenharmony_ci if (!rdata) 5918c2ecf20Sopenharmony_ci return NULL; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci rdata->report = report; 5948c2ecf20Sopenharmony_ci rdata->application = mt_find_application(td, report); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!rdata->application) { 5978c2ecf20Sopenharmony_ci devm_kfree(&td->hdev->dev, rdata); 5988c2ecf20Sopenharmony_ci return NULL; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci for (r = 0; r < report->maxfield; r++) { 6028c2ecf20Sopenharmony_ci field = report->field[r]; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) 6058c2ecf20Sopenharmony_ci continue; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (field->logical == HID_DG_FINGER || td->hdev->group != HID_GROUP_MULTITOUCH_WIN_8) { 6088c2ecf20Sopenharmony_ci for (n = 0; n < field->report_count; n++) { 6098c2ecf20Sopenharmony_ci if (field->usage[n].hid == HID_DG_CONTACTID) { 6108c2ecf20Sopenharmony_ci rdata->is_mt_collection = true; 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci list_add_tail(&rdata->list, &td->reports); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return rdata; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic struct mt_report_data *mt_find_report_data(struct mt_device *td, 6238c2ecf20Sopenharmony_ci struct hid_report *report) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct mt_report_data *tmp, *rdata = NULL; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &td->reports, list) { 6288c2ecf20Sopenharmony_ci if (report == tmp->report) { 6298c2ecf20Sopenharmony_ci rdata = tmp; 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (!rdata) 6358c2ecf20Sopenharmony_ci rdata = mt_allocate_report_data(td, report); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci return rdata; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic void mt_store_field(struct hid_device *hdev, 6418c2ecf20Sopenharmony_ci struct mt_application *application, 6428c2ecf20Sopenharmony_ci __s32 *value, 6438c2ecf20Sopenharmony_ci size_t offset) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct mt_usages *usage; 6468c2ecf20Sopenharmony_ci __s32 **target; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (list_empty(&application->mt_usages)) 6498c2ecf20Sopenharmony_ci usage = mt_allocate_usage(hdev, application); 6508c2ecf20Sopenharmony_ci else 6518c2ecf20Sopenharmony_ci usage = list_last_entry(&application->mt_usages, 6528c2ecf20Sopenharmony_ci struct mt_usages, 6538c2ecf20Sopenharmony_ci list); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (!usage) 6568c2ecf20Sopenharmony_ci return; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci target = (__s32 **)((char *)usage + offset); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* the value has already been filled, create a new slot */ 6618c2ecf20Sopenharmony_ci if (*target != DEFAULT_TRUE && 6628c2ecf20Sopenharmony_ci *target != DEFAULT_FALSE && 6638c2ecf20Sopenharmony_ci *target != DEFAULT_ZERO) { 6648c2ecf20Sopenharmony_ci if (usage->contactid == DEFAULT_ZERO || 6658c2ecf20Sopenharmony_ci usage->x == DEFAULT_ZERO || 6668c2ecf20Sopenharmony_ci usage->y == DEFAULT_ZERO) { 6678c2ecf20Sopenharmony_ci hid_dbg(hdev, 6688c2ecf20Sopenharmony_ci "ignoring duplicate usage on incomplete"); 6698c2ecf20Sopenharmony_ci return; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci usage = mt_allocate_usage(hdev, application); 6728c2ecf20Sopenharmony_ci if (!usage) 6738c2ecf20Sopenharmony_ci return; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci target = (__s32 **)((char *)usage + offset); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci *target = value; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci#define MT_STORE_FIELD(__name) \ 6828c2ecf20Sopenharmony_ci mt_store_field(hdev, app, \ 6838c2ecf20Sopenharmony_ci &field->value[usage->usage_index], \ 6848c2ecf20Sopenharmony_ci offsetof(struct mt_usages, __name)) 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, 6878c2ecf20Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 6888c2ecf20Sopenharmony_ci unsigned long **bit, int *max, struct mt_application *app) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 6918c2ecf20Sopenharmony_ci struct mt_class *cls = &td->mtclass; 6928c2ecf20Sopenharmony_ci int code; 6938c2ecf20Sopenharmony_ci struct hid_usage *prev_usage = NULL; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * Model touchscreens providing buttons as touchpads. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci if (field->application == HID_DG_TOUCHSCREEN && 6998c2ecf20Sopenharmony_ci (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { 7008c2ecf20Sopenharmony_ci app->mt_flags |= INPUT_MT_POINTER; 7018c2ecf20Sopenharmony_ci td->inputmode_value = MT_INPUTMODE_TOUCHPAD; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* count the buttons on touchpads */ 7058c2ecf20Sopenharmony_ci if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) 7068c2ecf20Sopenharmony_ci app->buttons_count++; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (usage->usage_index) 7098c2ecf20Sopenharmony_ci prev_usage = &field->usage[usage->usage_index - 1]; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci switch (usage->hid & HID_USAGE_PAGE) { 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci case HID_UP_GENDESK: 7148c2ecf20Sopenharmony_ci switch (usage->hid) { 7158c2ecf20Sopenharmony_ci case HID_GD_X: 7168c2ecf20Sopenharmony_ci if (prev_usage && (prev_usage->hid == usage->hid)) { 7178c2ecf20Sopenharmony_ci code = ABS_MT_TOOL_X; 7188c2ecf20Sopenharmony_ci MT_STORE_FIELD(cx); 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci code = ABS_MT_POSITION_X; 7218c2ecf20Sopenharmony_ci MT_STORE_FIELD(x); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci set_abs(hi->input, code, field, cls->sn_move); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* 7278c2ecf20Sopenharmony_ci * A system multi-axis that exports X and Y has a high 7288c2ecf20Sopenharmony_ci * chance of being used directly on a surface 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_ci if (field->application == HID_GD_SYSTEM_MULTIAXIS) { 7318c2ecf20Sopenharmony_ci __set_bit(INPUT_PROP_DIRECT, 7328c2ecf20Sopenharmony_ci hi->input->propbit); 7338c2ecf20Sopenharmony_ci input_set_abs_params(hi->input, 7348c2ecf20Sopenharmony_ci ABS_MT_TOOL_TYPE, 7358c2ecf20Sopenharmony_ci MT_TOOL_DIAL, 7368c2ecf20Sopenharmony_ci MT_TOOL_DIAL, 0, 0); 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return 1; 7408c2ecf20Sopenharmony_ci case HID_GD_Y: 7418c2ecf20Sopenharmony_ci if (prev_usage && (prev_usage->hid == usage->hid)) { 7428c2ecf20Sopenharmony_ci code = ABS_MT_TOOL_Y; 7438c2ecf20Sopenharmony_ci MT_STORE_FIELD(cy); 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci code = ABS_MT_POSITION_Y; 7468c2ecf20Sopenharmony_ci MT_STORE_FIELD(y); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci set_abs(hi->input, code, field, cls->sn_move); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return 1; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci case HID_UP_DIGITIZER: 7568c2ecf20Sopenharmony_ci switch (usage->hid) { 7578c2ecf20Sopenharmony_ci case HID_DG_INRANGE: 7588c2ecf20Sopenharmony_ci if (app->quirks & MT_QUIRK_HOVERING) { 7598c2ecf20Sopenharmony_ci input_set_abs_params(hi->input, 7608c2ecf20Sopenharmony_ci ABS_MT_DISTANCE, 0, 1, 0, 0); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci MT_STORE_FIELD(inrange_state); 7638c2ecf20Sopenharmony_ci return 1; 7648c2ecf20Sopenharmony_ci case HID_DG_CONFIDENCE: 7658c2ecf20Sopenharmony_ci if ((cls->name == MT_CLS_WIN_8 || 7668c2ecf20Sopenharmony_ci cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT) && 7678c2ecf20Sopenharmony_ci (field->application == HID_DG_TOUCHPAD || 7688c2ecf20Sopenharmony_ci field->application == HID_DG_TOUCHSCREEN)) 7698c2ecf20Sopenharmony_ci app->quirks |= MT_QUIRK_CONFIDENCE; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (app->quirks & MT_QUIRK_CONFIDENCE) 7728c2ecf20Sopenharmony_ci input_set_abs_params(hi->input, 7738c2ecf20Sopenharmony_ci ABS_MT_TOOL_TYPE, 7748c2ecf20Sopenharmony_ci MT_TOOL_FINGER, 7758c2ecf20Sopenharmony_ci MT_TOOL_PALM, 0, 0); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci MT_STORE_FIELD(confidence_state); 7788c2ecf20Sopenharmony_ci return 1; 7798c2ecf20Sopenharmony_ci case HID_DG_TIPSWITCH: 7808c2ecf20Sopenharmony_ci if (field->application != HID_GD_SYSTEM_MULTIAXIS) 7818c2ecf20Sopenharmony_ci input_set_capability(hi->input, 7828c2ecf20Sopenharmony_ci EV_KEY, BTN_TOUCH); 7838c2ecf20Sopenharmony_ci MT_STORE_FIELD(tip_state); 7848c2ecf20Sopenharmony_ci return 1; 7858c2ecf20Sopenharmony_ci case HID_DG_CONTACTID: 7868c2ecf20Sopenharmony_ci MT_STORE_FIELD(contactid); 7878c2ecf20Sopenharmony_ci app->touches_by_report++; 7888c2ecf20Sopenharmony_ci return 1; 7898c2ecf20Sopenharmony_ci case HID_DG_WIDTH: 7908c2ecf20Sopenharmony_ci if (!(app->quirks & MT_QUIRK_NO_AREA)) 7918c2ecf20Sopenharmony_ci set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, 7928c2ecf20Sopenharmony_ci cls->sn_width); 7938c2ecf20Sopenharmony_ci MT_STORE_FIELD(w); 7948c2ecf20Sopenharmony_ci return 1; 7958c2ecf20Sopenharmony_ci case HID_DG_HEIGHT: 7968c2ecf20Sopenharmony_ci if (!(app->quirks & MT_QUIRK_NO_AREA)) { 7978c2ecf20Sopenharmony_ci set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, 7988c2ecf20Sopenharmony_ci cls->sn_height); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* 8018c2ecf20Sopenharmony_ci * Only set ABS_MT_ORIENTATION if it is not 8028c2ecf20Sopenharmony_ci * already set by the HID_DG_AZIMUTH usage. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci if (!test_bit(ABS_MT_ORIENTATION, 8058c2ecf20Sopenharmony_ci hi->input->absbit)) 8068c2ecf20Sopenharmony_ci input_set_abs_params(hi->input, 8078c2ecf20Sopenharmony_ci ABS_MT_ORIENTATION, 0, 1, 0, 0); 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci MT_STORE_FIELD(h); 8108c2ecf20Sopenharmony_ci return 1; 8118c2ecf20Sopenharmony_ci case HID_DG_TIPPRESSURE: 8128c2ecf20Sopenharmony_ci set_abs(hi->input, ABS_MT_PRESSURE, field, 8138c2ecf20Sopenharmony_ci cls->sn_pressure); 8148c2ecf20Sopenharmony_ci MT_STORE_FIELD(p); 8158c2ecf20Sopenharmony_ci return 1; 8168c2ecf20Sopenharmony_ci case HID_DG_SCANTIME: 8178c2ecf20Sopenharmony_ci input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); 8188c2ecf20Sopenharmony_ci app->scantime = &field->value[usage->usage_index]; 8198c2ecf20Sopenharmony_ci app->scantime_logical_max = field->logical_maximum; 8208c2ecf20Sopenharmony_ci return 1; 8218c2ecf20Sopenharmony_ci case HID_DG_CONTACTCOUNT: 8228c2ecf20Sopenharmony_ci app->have_contact_count = true; 8238c2ecf20Sopenharmony_ci app->raw_cc = &field->value[usage->usage_index]; 8248c2ecf20Sopenharmony_ci return 1; 8258c2ecf20Sopenharmony_ci case HID_DG_AZIMUTH: 8268c2ecf20Sopenharmony_ci /* 8278c2ecf20Sopenharmony_ci * Azimuth has the range of [0, MAX) representing a full 8288c2ecf20Sopenharmony_ci * revolution. Set ABS_MT_ORIENTATION to a quarter of 8298c2ecf20Sopenharmony_ci * MAX according the definition of ABS_MT_ORIENTATION 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 8328c2ecf20Sopenharmony_ci -field->logical_maximum / 4, 8338c2ecf20Sopenharmony_ci field->logical_maximum / 4, 8348c2ecf20Sopenharmony_ci cls->sn_move ? 8358c2ecf20Sopenharmony_ci field->logical_maximum / cls->sn_move : 0, 0); 8368c2ecf20Sopenharmony_ci MT_STORE_FIELD(a); 8378c2ecf20Sopenharmony_ci return 1; 8388c2ecf20Sopenharmony_ci case HID_DG_CONTACTMAX: 8398c2ecf20Sopenharmony_ci /* contact max are global to the report */ 8408c2ecf20Sopenharmony_ci return -1; 8418c2ecf20Sopenharmony_ci case HID_DG_TOUCH: 8428c2ecf20Sopenharmony_ci /* Legacy devices use TIPSWITCH and not TOUCH. 8438c2ecf20Sopenharmony_ci * Let's just ignore this field. */ 8448c2ecf20Sopenharmony_ci return -1; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci /* let hid-input decide for the others */ 8478c2ecf20Sopenharmony_ci return 0; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci case HID_UP_BUTTON: 8508c2ecf20Sopenharmony_ci code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); 8518c2ecf20Sopenharmony_ci /* 8528c2ecf20Sopenharmony_ci * MS PTP spec says that external buttons left and right have 8538c2ecf20Sopenharmony_ci * usages 2 and 3. 8548c2ecf20Sopenharmony_ci */ 8558c2ecf20Sopenharmony_ci if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && 8568c2ecf20Sopenharmony_ci field->application == HID_DG_TOUCHPAD && 8578c2ecf20Sopenharmony_ci (usage->hid & HID_USAGE) > 1) 8588c2ecf20Sopenharmony_ci code--; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (field->application == HID_GD_SYSTEM_MULTIAXIS) 8618c2ecf20Sopenharmony_ci code = BTN_0 + ((usage->hid - 1) & HID_USAGE); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci hid_map_usage(hi, usage, bit, max, EV_KEY, code); 8648c2ecf20Sopenharmony_ci if (!*bit) 8658c2ecf20Sopenharmony_ci return -1; 8668c2ecf20Sopenharmony_ci input_set_capability(hi->input, EV_KEY, code); 8678c2ecf20Sopenharmony_ci return 1; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci case 0xff000000: 8708c2ecf20Sopenharmony_ci /* we do not want to map these: no input-oriented meaning */ 8718c2ecf20Sopenharmony_ci return -1; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci return 0; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic int mt_compute_slot(struct mt_device *td, struct mt_application *app, 8788c2ecf20Sopenharmony_ci struct mt_usages *slot, 8798c2ecf20Sopenharmony_ci struct input_dev *input) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci __s32 quirks = app->quirks; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) 8848c2ecf20Sopenharmony_ci return *slot->contactid; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_CYPRESS) 8878c2ecf20Sopenharmony_ci return cypress_compute_slot(app, slot); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) 8908c2ecf20Sopenharmony_ci return app->num_received; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) 8938c2ecf20Sopenharmony_ci return *slot->contactid - 1; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return input_mt_get_slot_by_key(input, *slot->contactid); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void mt_release_pending_palms(struct mt_device *td, 8998c2ecf20Sopenharmony_ci struct mt_application *app, 9008c2ecf20Sopenharmony_ci struct input_dev *input) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci int slotnum; 9038c2ecf20Sopenharmony_ci bool need_sync = false; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) { 9068c2ecf20Sopenharmony_ci clear_bit(slotnum, app->pending_palm_slots); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci input_mt_slot(input, slotnum); 9098c2ecf20Sopenharmony_ci input_mt_report_slot_inactive(input); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci need_sync = true; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (need_sync) { 9158c2ecf20Sopenharmony_ci input_mt_sync_frame(input); 9168c2ecf20Sopenharmony_ci input_sync(input); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/* 9218c2ecf20Sopenharmony_ci * this function is called when a whole packet has been received and processed, 9228c2ecf20Sopenharmony_ci * so that it can decide what to send to the input layer. 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_cistatic void mt_sync_frame(struct mt_device *td, struct mt_application *app, 9258c2ecf20Sopenharmony_ci struct input_dev *input) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci if (app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) 9288c2ecf20Sopenharmony_ci input_event(input, EV_KEY, BTN_LEFT, app->left_button_state); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci input_mt_sync_frame(input); 9318c2ecf20Sopenharmony_ci input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp); 9328c2ecf20Sopenharmony_ci input_sync(input); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci mt_release_pending_palms(td, app, input); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci app->num_received = 0; 9378c2ecf20Sopenharmony_ci app->left_button_state = 0; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) 9408c2ecf20Sopenharmony_ci set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 9418c2ecf20Sopenharmony_ci else 9428c2ecf20Sopenharmony_ci clear_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 9438c2ecf20Sopenharmony_ci clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic int mt_compute_timestamp(struct mt_application *app, __s32 value) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci long delta = value - app->prev_scantime; 9498c2ecf20Sopenharmony_ci unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci app->jiffies = jiffies; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (delta < 0) 9548c2ecf20Sopenharmony_ci delta += app->scantime_logical_max; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* HID_DG_SCANTIME is expressed in 100us, we want it in us. */ 9578c2ecf20Sopenharmony_ci delta *= 100; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (jdelta > MAX_TIMESTAMP_INTERVAL) 9608c2ecf20Sopenharmony_ci /* No data received for a while, resync the timestamp. */ 9618c2ecf20Sopenharmony_ci return 0; 9628c2ecf20Sopenharmony_ci else 9638c2ecf20Sopenharmony_ci return app->timestamp + delta; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cistatic int mt_touch_event(struct hid_device *hid, struct hid_field *field, 9678c2ecf20Sopenharmony_ci struct hid_usage *usage, __s32 value) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci /* we will handle the hidinput part later, now remains hiddev */ 9708c2ecf20Sopenharmony_ci if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 9718c2ecf20Sopenharmony_ci hid->hiddev_hid_event(hid, field, usage, value); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci return 1; 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic int mt_process_slot(struct mt_device *td, struct input_dev *input, 9778c2ecf20Sopenharmony_ci struct mt_application *app, 9788c2ecf20Sopenharmony_ci struct mt_usages *slot) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct input_mt *mt = input->mt; 9818c2ecf20Sopenharmony_ci __s32 quirks = app->quirks; 9828c2ecf20Sopenharmony_ci bool valid = true; 9838c2ecf20Sopenharmony_ci bool confidence_state = true; 9848c2ecf20Sopenharmony_ci bool inrange_state = false; 9858c2ecf20Sopenharmony_ci int active; 9868c2ecf20Sopenharmony_ci int slotnum; 9878c2ecf20Sopenharmony_ci int tool = MT_TOOL_FINGER; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (!slot) 9908c2ecf20Sopenharmony_ci return -EINVAL; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) && 9938c2ecf20Sopenharmony_ci app->num_received >= app->num_expected) 9948c2ecf20Sopenharmony_ci return -EAGAIN; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (!(quirks & MT_QUIRK_ALWAYS_VALID)) { 9978c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_VALID_IS_INRANGE) 9988c2ecf20Sopenharmony_ci valid = *slot->inrange_state; 9998c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 10008c2ecf20Sopenharmony_ci valid = *slot->tip_state; 10018c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) 10028c2ecf20Sopenharmony_ci valid = *slot->confidence_state; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (!valid) 10058c2ecf20Sopenharmony_ci return 0; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci slotnum = mt_compute_slot(td, app, slot, input); 10098c2ecf20Sopenharmony_ci if (slotnum < 0 || slotnum >= td->maxcontacts) 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) { 10138c2ecf20Sopenharmony_ci struct input_mt_slot *i_slot = &mt->slots[slotnum]; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (input_mt_is_active(i_slot) && 10168c2ecf20Sopenharmony_ci input_mt_is_used(mt, i_slot)) 10178c2ecf20Sopenharmony_ci return -EAGAIN; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_CONFIDENCE) 10218c2ecf20Sopenharmony_ci confidence_state = *slot->confidence_state; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_HOVERING) 10248c2ecf20Sopenharmony_ci inrange_state = *slot->inrange_state; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci active = *slot->tip_state || inrange_state; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (app->application == HID_GD_SYSTEM_MULTIAXIS) 10298c2ecf20Sopenharmony_ci tool = MT_TOOL_DIAL; 10308c2ecf20Sopenharmony_ci else if (unlikely(!confidence_state)) { 10318c2ecf20Sopenharmony_ci tool = MT_TOOL_PALM; 10328c2ecf20Sopenharmony_ci if (!active && mt && 10338c2ecf20Sopenharmony_ci input_mt_is_active(&mt->slots[slotnum])) { 10348c2ecf20Sopenharmony_ci /* 10358c2ecf20Sopenharmony_ci * The non-confidence was reported for 10368c2ecf20Sopenharmony_ci * previously valid contact that is also no 10378c2ecf20Sopenharmony_ci * longer valid. We can't simply report 10388c2ecf20Sopenharmony_ci * lift-off as userspace will not be aware 10398c2ecf20Sopenharmony_ci * of non-confidence, so we need to split 10408c2ecf20Sopenharmony_ci * it into 2 events: active MT_TOOL_PALM 10418c2ecf20Sopenharmony_ci * and a separate liftoff. 10428c2ecf20Sopenharmony_ci */ 10438c2ecf20Sopenharmony_ci active = true; 10448c2ecf20Sopenharmony_ci set_bit(slotnum, app->pending_palm_slots); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci input_mt_slot(input, slotnum); 10498c2ecf20Sopenharmony_ci input_mt_report_slot_state(input, tool, active); 10508c2ecf20Sopenharmony_ci if (active) { 10518c2ecf20Sopenharmony_ci /* this finger is in proximity of the sensor */ 10528c2ecf20Sopenharmony_ci int wide = (*slot->w > *slot->h); 10538c2ecf20Sopenharmony_ci int major = max(*slot->w, *slot->h); 10548c2ecf20Sopenharmony_ci int minor = min(*slot->w, *slot->h); 10558c2ecf20Sopenharmony_ci int orientation = wide; 10568c2ecf20Sopenharmony_ci int max_azimuth; 10578c2ecf20Sopenharmony_ci int azimuth; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (slot->a != DEFAULT_ZERO) { 10608c2ecf20Sopenharmony_ci /* 10618c2ecf20Sopenharmony_ci * Azimuth is counter-clockwise and ranges from [0, MAX) 10628c2ecf20Sopenharmony_ci * (a full revolution). Convert it to clockwise ranging 10638c2ecf20Sopenharmony_ci * [-MAX/2, MAX/2]. 10648c2ecf20Sopenharmony_ci * 10658c2ecf20Sopenharmony_ci * Note that ABS_MT_ORIENTATION require us to report 10668c2ecf20Sopenharmony_ci * the limit of [-MAX/4, MAX/4], but the value can go 10678c2ecf20Sopenharmony_ci * out of range to [-MAX/2, MAX/2] to report an upside 10688c2ecf20Sopenharmony_ci * down ellipsis. 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_ci azimuth = *slot->a; 10718c2ecf20Sopenharmony_ci max_azimuth = input_abs_get_max(input, 10728c2ecf20Sopenharmony_ci ABS_MT_ORIENTATION); 10738c2ecf20Sopenharmony_ci if (azimuth > max_azimuth * 2) 10748c2ecf20Sopenharmony_ci azimuth -= max_azimuth * 4; 10758c2ecf20Sopenharmony_ci orientation = -azimuth; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { 10798c2ecf20Sopenharmony_ci /* 10808c2ecf20Sopenharmony_ci * divided by two to match visual scale of touch 10818c2ecf20Sopenharmony_ci * for devices with this quirk 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_ci major = major >> 1; 10848c2ecf20Sopenharmony_ci minor = minor >> 1; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x); 10888c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y); 10898c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx); 10908c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy); 10918c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state); 10928c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation); 10938c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p); 10948c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 10958c2ecf20Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci return 0; 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic void mt_process_mt_event(struct hid_device *hid, 11048c2ecf20Sopenharmony_ci struct mt_application *app, 11058c2ecf20Sopenharmony_ci struct hid_field *field, 11068c2ecf20Sopenharmony_ci struct hid_usage *usage, 11078c2ecf20Sopenharmony_ci __s32 value, 11088c2ecf20Sopenharmony_ci bool first_packet) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci __s32 quirks = app->quirks; 11118c2ecf20Sopenharmony_ci struct input_dev *input = field->hidinput->input; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (!usage->type || !(hid->claimed & HID_CLAIMED_INPUT)) 11148c2ecf20Sopenharmony_ci return; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (quirks & MT_QUIRK_WIN8_PTP_BUTTONS) { 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* 11198c2ecf20Sopenharmony_ci * For Win8 PTP touchpads we should only look at 11208c2ecf20Sopenharmony_ci * non finger/touch events in the first_packet of a 11218c2ecf20Sopenharmony_ci * (possible) multi-packet frame. 11228c2ecf20Sopenharmony_ci */ 11238c2ecf20Sopenharmony_ci if (!first_packet) 11248c2ecf20Sopenharmony_ci return; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* 11278c2ecf20Sopenharmony_ci * For Win8 PTP touchpads we map both the clickpad click 11288c2ecf20Sopenharmony_ci * and any "external" left buttons to BTN_LEFT if a 11298c2ecf20Sopenharmony_ci * device claims to have both we need to report 1 for 11308c2ecf20Sopenharmony_ci * BTN_LEFT if either is pressed, so we or all values 11318c2ecf20Sopenharmony_ci * together and report the result in mt_sync_frame(). 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_ci if (usage->type == EV_KEY && usage->code == BTN_LEFT) { 11348c2ecf20Sopenharmony_ci app->left_button_state |= value; 11358c2ecf20Sopenharmony_ci return; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci input_event(input, usage->type, usage->code, value); 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cistatic void mt_touch_report(struct hid_device *hid, 11438c2ecf20Sopenharmony_ci struct mt_report_data *rdata) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 11468c2ecf20Sopenharmony_ci struct hid_report *report = rdata->report; 11478c2ecf20Sopenharmony_ci struct mt_application *app = rdata->application; 11488c2ecf20Sopenharmony_ci struct hid_field *field; 11498c2ecf20Sopenharmony_ci struct input_dev *input; 11508c2ecf20Sopenharmony_ci struct mt_usages *slot; 11518c2ecf20Sopenharmony_ci bool first_packet; 11528c2ecf20Sopenharmony_ci unsigned count; 11538c2ecf20Sopenharmony_ci int r, n; 11548c2ecf20Sopenharmony_ci int scantime = 0; 11558c2ecf20Sopenharmony_ci int contact_count = -1; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* sticky fingers release in progress, abort */ 11588c2ecf20Sopenharmony_ci if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 11598c2ecf20Sopenharmony_ci return; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci scantime = *app->scantime; 11628c2ecf20Sopenharmony_ci app->timestamp = mt_compute_timestamp(app, scantime); 11638c2ecf20Sopenharmony_ci if (app->raw_cc != DEFAULT_ZERO) 11648c2ecf20Sopenharmony_ci contact_count = *app->raw_cc; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* 11678c2ecf20Sopenharmony_ci * Includes multi-packet support where subsequent 11688c2ecf20Sopenharmony_ci * packets are sent with zero contactcount. 11698c2ecf20Sopenharmony_ci */ 11708c2ecf20Sopenharmony_ci if (contact_count >= 0) { 11718c2ecf20Sopenharmony_ci /* 11728c2ecf20Sopenharmony_ci * For Win8 PTPs the first packet (td->num_received == 0) may 11738c2ecf20Sopenharmony_ci * have a contactcount of 0 if there only is a button event. 11748c2ecf20Sopenharmony_ci * We double check that this is not a continuation packet 11758c2ecf20Sopenharmony_ci * of a possible multi-packet frame be checking that the 11768c2ecf20Sopenharmony_ci * timestamp has changed. 11778c2ecf20Sopenharmony_ci */ 11788c2ecf20Sopenharmony_ci if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && 11798c2ecf20Sopenharmony_ci app->num_received == 0 && 11808c2ecf20Sopenharmony_ci app->prev_scantime != scantime) 11818c2ecf20Sopenharmony_ci app->num_expected = contact_count; 11828c2ecf20Sopenharmony_ci /* A non 0 contact count always indicates a first packet */ 11838c2ecf20Sopenharmony_ci else if (contact_count) 11848c2ecf20Sopenharmony_ci app->num_expected = contact_count; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci app->prev_scantime = scantime; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci first_packet = app->num_received == 0; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci input = report->field[0]->hidinput->input; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci list_for_each_entry(slot, &app->mt_usages, list) { 11938c2ecf20Sopenharmony_ci if (!mt_process_slot(td, input, app, slot)) 11948c2ecf20Sopenharmony_ci app->num_received++; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci for (r = 0; r < report->maxfield; r++) { 11988c2ecf20Sopenharmony_ci field = report->field[r]; 11998c2ecf20Sopenharmony_ci count = field->report_count; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) 12028c2ecf20Sopenharmony_ci continue; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci for (n = 0; n < count; n++) 12058c2ecf20Sopenharmony_ci mt_process_mt_event(hid, app, field, 12068c2ecf20Sopenharmony_ci &field->usage[n], field->value[n], 12078c2ecf20Sopenharmony_ci first_packet); 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (app->num_received >= app->num_expected) 12118c2ecf20Sopenharmony_ci mt_sync_frame(td, app, input); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* 12148c2ecf20Sopenharmony_ci * Windows 8 specs says 2 things: 12158c2ecf20Sopenharmony_ci * - once a contact has been reported, it has to be reported in each 12168c2ecf20Sopenharmony_ci * subsequent report 12178c2ecf20Sopenharmony_ci * - the report rate when fingers are present has to be at least 12188c2ecf20Sopenharmony_ci * the refresh rate of the screen, 60 or 120 Hz 12198c2ecf20Sopenharmony_ci * 12208c2ecf20Sopenharmony_ci * I interprete this that the specification forces a report rate of 12218c2ecf20Sopenharmony_ci * at least 60 Hz for a touchscreen to be certified. 12228c2ecf20Sopenharmony_ci * Which means that if we do not get a report whithin 16 ms, either 12238c2ecf20Sopenharmony_ci * something wrong happens, either the touchscreen forgets to send 12248c2ecf20Sopenharmony_ci * a release. Taking a reasonable margin allows to remove issues 12258c2ecf20Sopenharmony_ci * with USB communication or the load of the machine. 12268c2ecf20Sopenharmony_ci * 12278c2ecf20Sopenharmony_ci * Given that Win 8 devices are forced to send a release, this will 12288c2ecf20Sopenharmony_ci * only affect laggish machines and the ones that have a firmware 12298c2ecf20Sopenharmony_ci * defect. 12308c2ecf20Sopenharmony_ci */ 12318c2ecf20Sopenharmony_ci if (app->quirks & MT_QUIRK_STICKY_FINGERS) { 12328c2ecf20Sopenharmony_ci if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 12338c2ecf20Sopenharmony_ci mod_timer(&td->release_timer, 12348c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(100)); 12358c2ecf20Sopenharmony_ci else 12368c2ecf20Sopenharmony_ci del_timer(&td->release_timer); 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cistatic int mt_touch_input_configured(struct hid_device *hdev, 12438c2ecf20Sopenharmony_ci struct hid_input *hi, 12448c2ecf20Sopenharmony_ci struct mt_application *app) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 12478c2ecf20Sopenharmony_ci struct mt_class *cls = &td->mtclass; 12488c2ecf20Sopenharmony_ci struct input_dev *input = hi->input; 12498c2ecf20Sopenharmony_ci int ret; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci if (!td->maxcontacts) 12528c2ecf20Sopenharmony_ci td->maxcontacts = MT_DEFAULT_MAXCONTACT; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci mt_post_parse(td, app); 12558c2ecf20Sopenharmony_ci if (td->serial_maybe) 12568c2ecf20Sopenharmony_ci mt_post_parse_default_settings(td, app); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (cls->is_indirect) 12598c2ecf20Sopenharmony_ci app->mt_flags |= INPUT_MT_POINTER; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 12628c2ecf20Sopenharmony_ci app->mt_flags |= INPUT_MT_DROP_UNUSED; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci /* check for clickpads */ 12658c2ecf20Sopenharmony_ci if ((app->mt_flags & INPUT_MT_POINTER) && 12668c2ecf20Sopenharmony_ci (app->buttons_count == 1)) 12678c2ecf20Sopenharmony_ci td->is_buttonpad = true; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (td->is_buttonpad) 12708c2ecf20Sopenharmony_ci __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci app->pending_palm_slots = devm_kcalloc(&hi->input->dev, 12738c2ecf20Sopenharmony_ci BITS_TO_LONGS(td->maxcontacts), 12748c2ecf20Sopenharmony_ci sizeof(long), 12758c2ecf20Sopenharmony_ci GFP_KERNEL); 12768c2ecf20Sopenharmony_ci if (!app->pending_palm_slots) 12778c2ecf20Sopenharmony_ci return -ENOMEM; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags); 12808c2ecf20Sopenharmony_ci if (ret) 12818c2ecf20Sopenharmony_ci return ret; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci app->mt_flags = 0; 12848c2ecf20Sopenharmony_ci return 0; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci#define mt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \ 12888c2ecf20Sopenharmony_ci max, EV_KEY, (c)) 12898c2ecf20Sopenharmony_cistatic int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 12908c2ecf20Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 12918c2ecf20Sopenharmony_ci unsigned long **bit, int *max) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 12948c2ecf20Sopenharmony_ci struct mt_application *application; 12958c2ecf20Sopenharmony_ci struct mt_report_data *rdata; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci rdata = mt_find_report_data(td, field->report); 12988c2ecf20Sopenharmony_ci if (!rdata) { 12998c2ecf20Sopenharmony_ci hid_err(hdev, "failed to allocate data for report\n"); 13008c2ecf20Sopenharmony_ci return 0; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci application = rdata->application; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* 13068c2ecf20Sopenharmony_ci * If mtclass.export_all_inputs is not set, only map fields from 13078c2ecf20Sopenharmony_ci * TouchScreen or TouchPad collections. We need to ignore fields 13088c2ecf20Sopenharmony_ci * that belong to other collections such as Mouse that might have 13098c2ecf20Sopenharmony_ci * the same GenericDesktop usages. 13108c2ecf20Sopenharmony_ci */ 13118c2ecf20Sopenharmony_ci if (!td->mtclass.export_all_inputs && 13128c2ecf20Sopenharmony_ci field->application != HID_DG_TOUCHSCREEN && 13138c2ecf20Sopenharmony_ci field->application != HID_DG_PEN && 13148c2ecf20Sopenharmony_ci field->application != HID_DG_TOUCHPAD && 13158c2ecf20Sopenharmony_ci field->application != HID_GD_KEYBOARD && 13168c2ecf20Sopenharmony_ci field->application != HID_GD_SYSTEM_CONTROL && 13178c2ecf20Sopenharmony_ci field->application != HID_CP_CONSUMER_CONTROL && 13188c2ecf20Sopenharmony_ci field->application != HID_GD_WIRELESS_RADIO_CTLS && 13198c2ecf20Sopenharmony_ci field->application != HID_GD_SYSTEM_MULTIAXIS && 13208c2ecf20Sopenharmony_ci !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 13218c2ecf20Sopenharmony_ci application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) 13228c2ecf20Sopenharmony_ci return -1; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci /* 13258c2ecf20Sopenharmony_ci * Some Asus keyboard+touchpad devices have the hotkeys defined in the 13268c2ecf20Sopenharmony_ci * touchpad report descriptor. We need to treat these as an array to 13278c2ecf20Sopenharmony_ci * map usages to input keys. 13288c2ecf20Sopenharmony_ci */ 13298c2ecf20Sopenharmony_ci if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 13308c2ecf20Sopenharmony_ci application->quirks & MT_QUIRK_ASUS_CUSTOM_UP && 13318c2ecf20Sopenharmony_ci (usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) { 13328c2ecf20Sopenharmony_ci set_bit(EV_REP, hi->input->evbit); 13338c2ecf20Sopenharmony_ci if (field->flags & HID_MAIN_ITEM_VARIABLE) 13348c2ecf20Sopenharmony_ci field->flags &= ~HID_MAIN_ITEM_VARIABLE; 13358c2ecf20Sopenharmony_ci switch (usage->hid & HID_USAGE) { 13368c2ecf20Sopenharmony_ci case 0x10: mt_map_key_clear(KEY_BRIGHTNESSDOWN); break; 13378c2ecf20Sopenharmony_ci case 0x20: mt_map_key_clear(KEY_BRIGHTNESSUP); break; 13388c2ecf20Sopenharmony_ci case 0x35: mt_map_key_clear(KEY_DISPLAY_OFF); break; 13398c2ecf20Sopenharmony_ci case 0x6b: mt_map_key_clear(KEY_F21); break; 13408c2ecf20Sopenharmony_ci case 0x6c: mt_map_key_clear(KEY_SLEEP); break; 13418c2ecf20Sopenharmony_ci default: 13428c2ecf20Sopenharmony_ci return -1; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci return 1; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (rdata->is_mt_collection) 13488c2ecf20Sopenharmony_ci return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, 13498c2ecf20Sopenharmony_ci application); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci /* 13528c2ecf20Sopenharmony_ci * some egalax touchscreens have "application == DG_TOUCHSCREEN" 13538c2ecf20Sopenharmony_ci * for the stylus. Overwrite the hid_input application 13548c2ecf20Sopenharmony_ci */ 13558c2ecf20Sopenharmony_ci if (field->physical == HID_DG_STYLUS) 13568c2ecf20Sopenharmony_ci hi->application = HID_DG_STYLUS; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci /* let hid-core decide for the others */ 13598c2ecf20Sopenharmony_ci return 0; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, 13638c2ecf20Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 13648c2ecf20Sopenharmony_ci unsigned long **bit, int *max) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 13678c2ecf20Sopenharmony_ci struct mt_report_data *rdata; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci rdata = mt_find_report_data(td, field->report); 13708c2ecf20Sopenharmony_ci if (rdata && rdata->is_mt_collection) { 13718c2ecf20Sopenharmony_ci /* We own these mappings, tell hid-input to ignore them */ 13728c2ecf20Sopenharmony_ci return -1; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci /* let hid-core decide for the others */ 13768c2ecf20Sopenharmony_ci return 0; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_cistatic int mt_event(struct hid_device *hid, struct hid_field *field, 13808c2ecf20Sopenharmony_ci struct hid_usage *usage, __s32 value) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 13838c2ecf20Sopenharmony_ci struct mt_report_data *rdata; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci rdata = mt_find_report_data(td, field->report); 13868c2ecf20Sopenharmony_ci if (rdata && rdata->is_mt_collection) 13878c2ecf20Sopenharmony_ci return mt_touch_event(hid, field, usage, value); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci return 0; 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic void mt_report(struct hid_device *hid, struct hid_report *report) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 13958c2ecf20Sopenharmony_ci struct hid_field *field = report->field[0]; 13968c2ecf20Sopenharmony_ci struct mt_report_data *rdata; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (!(hid->claimed & HID_CLAIMED_INPUT)) 13998c2ecf20Sopenharmony_ci return; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci rdata = mt_find_report_data(td, report); 14028c2ecf20Sopenharmony_ci if (rdata && rdata->is_mt_collection) 14038c2ecf20Sopenharmony_ci return mt_touch_report(hid, rdata); 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (field && field->hidinput && field->hidinput->input) 14068c2ecf20Sopenharmony_ci input_sync(field->hidinput->input); 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic bool mt_need_to_apply_feature(struct hid_device *hdev, 14108c2ecf20Sopenharmony_ci struct hid_field *field, 14118c2ecf20Sopenharmony_ci struct hid_usage *usage, 14128c2ecf20Sopenharmony_ci enum latency_mode latency, 14138c2ecf20Sopenharmony_ci bool surface_switch, 14148c2ecf20Sopenharmony_ci bool button_switch, 14158c2ecf20Sopenharmony_ci bool *inputmode_found) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 14188c2ecf20Sopenharmony_ci struct mt_class *cls = &td->mtclass; 14198c2ecf20Sopenharmony_ci struct hid_report *report = field->report; 14208c2ecf20Sopenharmony_ci unsigned int index = usage->usage_index; 14218c2ecf20Sopenharmony_ci char *buf; 14228c2ecf20Sopenharmony_ci u32 report_len; 14238c2ecf20Sopenharmony_ci int max; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci switch (usage->hid) { 14268c2ecf20Sopenharmony_ci case HID_DG_INPUTMODE: 14278c2ecf20Sopenharmony_ci /* 14288c2ecf20Sopenharmony_ci * Some elan panels wrongly declare 2 input mode features, 14298c2ecf20Sopenharmony_ci * and silently ignore when we set the value in the second 14308c2ecf20Sopenharmony_ci * field. Skip the second feature and hope for the best. 14318c2ecf20Sopenharmony_ci */ 14328c2ecf20Sopenharmony_ci if (*inputmode_found) 14338c2ecf20Sopenharmony_ci return false; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) { 14368c2ecf20Sopenharmony_ci report_len = hid_report_len(report); 14378c2ecf20Sopenharmony_ci buf = hid_alloc_report_buf(report, GFP_KERNEL); 14388c2ecf20Sopenharmony_ci if (!buf) { 14398c2ecf20Sopenharmony_ci hid_err(hdev, 14408c2ecf20Sopenharmony_ci "failed to allocate buffer for report\n"); 14418c2ecf20Sopenharmony_ci return false; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci hid_hw_raw_request(hdev, report->id, buf, report_len, 14448c2ecf20Sopenharmony_ci HID_FEATURE_REPORT, 14458c2ecf20Sopenharmony_ci HID_REQ_GET_REPORT); 14468c2ecf20Sopenharmony_ci kfree(buf); 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci field->value[index] = td->inputmode_value; 14508c2ecf20Sopenharmony_ci *inputmode_found = true; 14518c2ecf20Sopenharmony_ci return true; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci case HID_DG_CONTACTMAX: 14548c2ecf20Sopenharmony_ci if (cls->maxcontacts) { 14558c2ecf20Sopenharmony_ci max = min_t(int, field->logical_maximum, 14568c2ecf20Sopenharmony_ci cls->maxcontacts); 14578c2ecf20Sopenharmony_ci if (field->value[index] != max) { 14588c2ecf20Sopenharmony_ci field->value[index] = max; 14598c2ecf20Sopenharmony_ci return true; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci case HID_DG_LATENCYMODE: 14658c2ecf20Sopenharmony_ci field->value[index] = latency; 14668c2ecf20Sopenharmony_ci return true; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci case HID_DG_SURFACESWITCH: 14698c2ecf20Sopenharmony_ci field->value[index] = surface_switch; 14708c2ecf20Sopenharmony_ci return true; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci case HID_DG_BUTTONSWITCH: 14738c2ecf20Sopenharmony_ci field->value[index] = button_switch; 14748c2ecf20Sopenharmony_ci return true; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci return false; /* no need to update the report */ 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_cistatic void mt_set_modes(struct hid_device *hdev, enum latency_mode latency, 14818c2ecf20Sopenharmony_ci bool surface_switch, bool button_switch) 14828c2ecf20Sopenharmony_ci{ 14838c2ecf20Sopenharmony_ci struct hid_report_enum *rep_enum; 14848c2ecf20Sopenharmony_ci struct hid_report *rep; 14858c2ecf20Sopenharmony_ci struct hid_usage *usage; 14868c2ecf20Sopenharmony_ci int i, j; 14878c2ecf20Sopenharmony_ci bool update_report; 14888c2ecf20Sopenharmony_ci bool inputmode_found = false; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; 14918c2ecf20Sopenharmony_ci list_for_each_entry(rep, &rep_enum->report_list, list) { 14928c2ecf20Sopenharmony_ci update_report = false; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci for (i = 0; i < rep->maxfield; i++) { 14958c2ecf20Sopenharmony_ci /* Ignore if report count is out of bounds. */ 14968c2ecf20Sopenharmony_ci if (rep->field[i]->report_count < 1) 14978c2ecf20Sopenharmony_ci continue; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci for (j = 0; j < rep->field[i]->maxusage; j++) { 15008c2ecf20Sopenharmony_ci usage = &rep->field[i]->usage[j]; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (mt_need_to_apply_feature(hdev, 15038c2ecf20Sopenharmony_ci rep->field[i], 15048c2ecf20Sopenharmony_ci usage, 15058c2ecf20Sopenharmony_ci latency, 15068c2ecf20Sopenharmony_ci surface_switch, 15078c2ecf20Sopenharmony_ci button_switch, 15088c2ecf20Sopenharmony_ci &inputmode_found)) 15098c2ecf20Sopenharmony_ci update_report = true; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if (update_report) 15148c2ecf20Sopenharmony_ci hid_hw_request(hdev, rep, HID_REQ_SET_REPORT); 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_cistatic void mt_post_parse_default_settings(struct mt_device *td, 15198c2ecf20Sopenharmony_ci struct mt_application *app) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci __s32 quirks = app->quirks; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* unknown serial device needs special quirks */ 15248c2ecf20Sopenharmony_ci if (list_is_singular(&app->mt_usages)) { 15258c2ecf20Sopenharmony_ci quirks |= MT_QUIRK_ALWAYS_VALID; 15268c2ecf20Sopenharmony_ci quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; 15278c2ecf20Sopenharmony_ci quirks &= ~MT_QUIRK_VALID_IS_INRANGE; 15288c2ecf20Sopenharmony_ci quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; 15298c2ecf20Sopenharmony_ci quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci app->quirks = quirks; 15338c2ecf20Sopenharmony_ci} 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_cistatic void mt_post_parse(struct mt_device *td, struct mt_application *app) 15368c2ecf20Sopenharmony_ci{ 15378c2ecf20Sopenharmony_ci if (!app->have_contact_count) 15388c2ecf20Sopenharmony_ci app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 15448c2ecf20Sopenharmony_ci const char *suffix = NULL; 15458c2ecf20Sopenharmony_ci struct mt_report_data *rdata; 15468c2ecf20Sopenharmony_ci struct mt_application *mt_application = NULL; 15478c2ecf20Sopenharmony_ci struct hid_report *report; 15488c2ecf20Sopenharmony_ci int ret; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci list_for_each_entry(report, &hi->reports, hidinput_list) { 15518c2ecf20Sopenharmony_ci rdata = mt_find_report_data(td, report); 15528c2ecf20Sopenharmony_ci if (!rdata) { 15538c2ecf20Sopenharmony_ci hid_err(hdev, "failed to allocate data for report\n"); 15548c2ecf20Sopenharmony_ci return -ENOMEM; 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci mt_application = rdata->application; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (rdata->is_mt_collection) { 15608c2ecf20Sopenharmony_ci ret = mt_touch_input_configured(hdev, hi, 15618c2ecf20Sopenharmony_ci mt_application); 15628c2ecf20Sopenharmony_ci if (ret) 15638c2ecf20Sopenharmony_ci return ret; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci switch (hi->application) { 15688c2ecf20Sopenharmony_ci case HID_GD_KEYBOARD: 15698c2ecf20Sopenharmony_ci case HID_GD_KEYPAD: 15708c2ecf20Sopenharmony_ci case HID_GD_MOUSE: 15718c2ecf20Sopenharmony_ci case HID_DG_TOUCHPAD: 15728c2ecf20Sopenharmony_ci case HID_GD_SYSTEM_CONTROL: 15738c2ecf20Sopenharmony_ci case HID_CP_CONSUMER_CONTROL: 15748c2ecf20Sopenharmony_ci case HID_GD_WIRELESS_RADIO_CTLS: 15758c2ecf20Sopenharmony_ci case HID_GD_SYSTEM_MULTIAXIS: 15768c2ecf20Sopenharmony_ci /* already handled by hid core */ 15778c2ecf20Sopenharmony_ci break; 15788c2ecf20Sopenharmony_ci case HID_DG_TOUCHSCREEN: 15798c2ecf20Sopenharmony_ci /* we do not set suffix = "Touchscreen" */ 15808c2ecf20Sopenharmony_ci hi->input->name = hdev->name; 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: 15838c2ecf20Sopenharmony_ci suffix = "Custom Media Keys"; 15848c2ecf20Sopenharmony_ci break; 15858c2ecf20Sopenharmony_ci case HID_DG_STYLUS: 15868c2ecf20Sopenharmony_ci /* force BTN_STYLUS to allow tablet matching in udev */ 15878c2ecf20Sopenharmony_ci __set_bit(BTN_STYLUS, hi->input->keybit); 15888c2ecf20Sopenharmony_ci fallthrough; 15898c2ecf20Sopenharmony_ci case HID_DG_PEN: 15908c2ecf20Sopenharmony_ci suffix = "Stylus"; 15918c2ecf20Sopenharmony_ci break; 15928c2ecf20Sopenharmony_ci default: 15938c2ecf20Sopenharmony_ci suffix = "UNKNOWN"; 15948c2ecf20Sopenharmony_ci break; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (suffix) 15988c2ecf20Sopenharmony_ci hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, 15998c2ecf20Sopenharmony_ci "%s %s", hdev->name, suffix); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci return 0; 16028c2ecf20Sopenharmony_ci} 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_cistatic void mt_fix_const_field(struct hid_field *field, unsigned int usage) 16058c2ecf20Sopenharmony_ci{ 16068c2ecf20Sopenharmony_ci if (field->usage[0].hid != usage || 16078c2ecf20Sopenharmony_ci !(field->flags & HID_MAIN_ITEM_CONSTANT)) 16088c2ecf20Sopenharmony_ci return; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci field->flags &= ~HID_MAIN_ITEM_CONSTANT; 16118c2ecf20Sopenharmony_ci field->flags |= HID_MAIN_ITEM_VARIABLE; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct hid_report *report; 16178c2ecf20Sopenharmony_ci int i; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci list_for_each_entry(report, 16208c2ecf20Sopenharmony_ci &hdev->report_enum[HID_INPUT_REPORT].report_list, 16218c2ecf20Sopenharmony_ci list) { 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (!report->maxfield) 16248c2ecf20Sopenharmony_ci continue; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci for (i = 0; i < report->maxfield; i++) 16278c2ecf20Sopenharmony_ci if (report->field[i]->maxusage >= 1) 16288c2ecf20Sopenharmony_ci mt_fix_const_field(report->field[i], usage); 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic void mt_release_contacts(struct hid_device *hid) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct hid_input *hidinput; 16358c2ecf20Sopenharmony_ci struct mt_application *application; 16368c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci list_for_each_entry(hidinput, &hid->inputs, list) { 16398c2ecf20Sopenharmony_ci struct input_dev *input_dev = hidinput->input; 16408c2ecf20Sopenharmony_ci struct input_mt *mt = input_dev->mt; 16418c2ecf20Sopenharmony_ci int i; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci if (mt) { 16448c2ecf20Sopenharmony_ci for (i = 0; i < mt->num_slots; i++) { 16458c2ecf20Sopenharmony_ci input_mt_slot(input_dev, i); 16468c2ecf20Sopenharmony_ci input_mt_report_slot_inactive(input_dev); 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci input_mt_sync_frame(input_dev); 16498c2ecf20Sopenharmony_ci input_sync(input_dev); 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci list_for_each_entry(application, &td->applications, list) { 16548c2ecf20Sopenharmony_ci application->num_received = 0; 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic void mt_expired_timeout(struct timer_list *t) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci struct mt_device *td = from_timer(td, t, release_timer); 16618c2ecf20Sopenharmony_ci struct hid_device *hdev = td->hdev; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci /* 16648c2ecf20Sopenharmony_ci * An input report came in just before we release the sticky fingers, 16658c2ecf20Sopenharmony_ci * it will take care of the sticky fingers. 16668c2ecf20Sopenharmony_ci */ 16678c2ecf20Sopenharmony_ci if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 16688c2ecf20Sopenharmony_ci return; 16698c2ecf20Sopenharmony_ci if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 16708c2ecf20Sopenharmony_ci mt_release_contacts(hdev); 16718c2ecf20Sopenharmony_ci clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 16728c2ecf20Sopenharmony_ci} 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_cistatic int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 16758c2ecf20Sopenharmony_ci{ 16768c2ecf20Sopenharmony_ci int ret, i; 16778c2ecf20Sopenharmony_ci struct mt_device *td; 16788c2ecf20Sopenharmony_ci const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci for (i = 0; mt_classes[i].name ; i++) { 16818c2ecf20Sopenharmony_ci if (id->driver_data == mt_classes[i].name) { 16828c2ecf20Sopenharmony_ci mtclass = &(mt_classes[i]); 16838c2ecf20Sopenharmony_ci break; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); 16888c2ecf20Sopenharmony_ci if (!td) { 16898c2ecf20Sopenharmony_ci dev_err(&hdev->dev, "cannot allocate multitouch data\n"); 16908c2ecf20Sopenharmony_ci return -ENOMEM; 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci td->hdev = hdev; 16938c2ecf20Sopenharmony_ci td->mtclass = *mtclass; 16948c2ecf20Sopenharmony_ci td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; 16958c2ecf20Sopenharmony_ci hid_set_drvdata(hdev, td); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&td->applications); 16988c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&td->reports); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) 17018c2ecf20Sopenharmony_ci td->serial_maybe = true; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci /* This allows the driver to correctly support devices 17048c2ecf20Sopenharmony_ci * that emit events over several HID messages. 17058c2ecf20Sopenharmony_ci */ 17068c2ecf20Sopenharmony_ci hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* 17098c2ecf20Sopenharmony_ci * This allows the driver to handle different input sensors 17108c2ecf20Sopenharmony_ci * that emits events through different applications on the same HID 17118c2ecf20Sopenharmony_ci * device. 17128c2ecf20Sopenharmony_ci */ 17138c2ecf20Sopenharmony_ci hdev->quirks |= HID_QUIRK_INPUT_PER_APP; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (id->group != HID_GROUP_MULTITOUCH_WIN_8) 17168c2ecf20Sopenharmony_ci hdev->quirks |= HID_QUIRK_MULTI_INPUT; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (mtclass->quirks & MT_QUIRK_FORCE_MULTI_INPUT) { 17198c2ecf20Sopenharmony_ci hdev->quirks &= ~HID_QUIRK_INPUT_PER_APP; 17208c2ecf20Sopenharmony_ci hdev->quirks |= HID_QUIRK_MULTI_INPUT; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci timer_setup(&td->release_timer, mt_expired_timeout, 0); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci ret = hid_parse(hdev); 17268c2ecf20Sopenharmony_ci if (ret != 0) 17278c2ecf20Sopenharmony_ci return ret; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) 17308c2ecf20Sopenharmony_ci mt_fix_const_fields(hdev, HID_DG_CONTACTID); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 17338c2ecf20Sopenharmony_ci if (ret) 17348c2ecf20Sopenharmony_ci return ret; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); 17378c2ecf20Sopenharmony_ci if (ret) 17388c2ecf20Sopenharmony_ci dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n", 17398c2ecf20Sopenharmony_ci hdev->name); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci return 0; 17448c2ecf20Sopenharmony_ci} 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 17478c2ecf20Sopenharmony_cistatic int mt_reset_resume(struct hid_device *hdev) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci mt_release_contacts(hdev); 17508c2ecf20Sopenharmony_ci mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 17518c2ecf20Sopenharmony_ci return 0; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic int mt_resume(struct hid_device *hdev) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci /* Some Elan legacy devices require SET_IDLE to be set on resume. 17578c2ecf20Sopenharmony_ci * It should be safe to send it to other devices too. 17588c2ecf20Sopenharmony_ci * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci return 0; 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci#endif 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic void mt_remove(struct hid_device *hdev) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci del_timer_sync(&td->release_timer); 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); 17738c2ecf20Sopenharmony_ci hid_hw_stop(hdev); 17748c2ecf20Sopenharmony_ci} 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci/* 17778c2ecf20Sopenharmony_ci * This list contains only: 17788c2ecf20Sopenharmony_ci * - VID/PID of products not working with the default multitouch handling 17798c2ecf20Sopenharmony_ci * - 2 generic rules. 17808c2ecf20Sopenharmony_ci * So there is no point in adding here any device with MT_CLS_DEFAULT. 17818c2ecf20Sopenharmony_ci */ 17828c2ecf20Sopenharmony_cistatic const struct hid_device_id mt_devices[] = { 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci /* 3M panels */ 17858c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_3M, 17868c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_3M, 17878c2ecf20Sopenharmony_ci USB_DEVICE_ID_3M1968) }, 17888c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_3M, 17898c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_3M, 17908c2ecf20Sopenharmony_ci USB_DEVICE_ID_3M2256) }, 17918c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_3M, 17928c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_3M, 17938c2ecf20Sopenharmony_ci USB_DEVICE_ID_3M3266) }, 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci /* Anton devices */ 17968c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, 17978c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ANTON, 17988c2ecf20Sopenharmony_ci USB_DEVICE_ID_ANTON_TOUCH_PAD) }, 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci /* Asus T304UA */ 18018c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_ASUS, 18028c2ecf20Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 18038c2ecf20Sopenharmony_ci USB_VENDOR_ID_ASUSTEK, 18048c2ecf20Sopenharmony_ci USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD) }, 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci /* Atmel panels */ 18078c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_SERIAL, 18088c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 18098c2ecf20Sopenharmony_ci USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* Baanto multitouch devices */ 18128c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 18138c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, 18148c2ecf20Sopenharmony_ci USB_DEVICE_ID_BAANTO_MT_190W2) }, 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* Cando panels */ 18178c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 18188c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 18198c2ecf20Sopenharmony_ci USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, 18208c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 18218c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 18228c2ecf20Sopenharmony_ci USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci /* Chunghwa Telecom touch panels */ 18258c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 18268c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, 18278c2ecf20Sopenharmony_ci USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci /* CJTouch panels */ 18308c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 18318c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 18328c2ecf20Sopenharmony_ci USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) }, 18338c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 18348c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 18358c2ecf20Sopenharmony_ci USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) }, 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci /* CVTouch panels */ 18388c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 18398c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, 18408c2ecf20Sopenharmony_ci USB_DEVICE_ID_CVTOUCH_SCREEN) }, 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* eGalax devices (resistive) */ 18438c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18448c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18458c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, 18468c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18478c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18488c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci /* eGalax devices (capacitive) */ 18518c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18528c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18538c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) }, 18548c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18558c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18568c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, 18578c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18588c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18598c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, 18608c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18618c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18628c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) }, 18638c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18648c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18658c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) }, 18668c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18678c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18688c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) }, 18698c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18708c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18718c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, 18728c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18738c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18748c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, 18758c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18768c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18778c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) }, 18788c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18798c2ecf20Sopenharmony_ci HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 18808c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) }, 18818c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18828c2ecf20Sopenharmony_ci HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 18838c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) }, 18848c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18858c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18868c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, 18878c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 18888c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18898c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, 18908c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18918c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18928c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, 18938c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18948c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18958c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) }, 18968c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 18978c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 18988c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, 18998c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 19008c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 19018c2ecf20Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) }, 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci /* Elan devices */ 19048c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 19058c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 19068c2ecf20Sopenharmony_ci USB_VENDOR_ID_ELAN, 0x313a) }, 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 19098c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 19108c2ecf20Sopenharmony_ci USB_VENDOR_ID_ELAN, 0x3148) }, 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci /* Elitegroup panel */ 19138c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_SERIAL, 19148c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP, 19158c2ecf20Sopenharmony_ci USB_DEVICE_ID_ELITEGROUP_05D8) }, 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci /* Flatfrog Panels */ 19188c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_FLATFROG, 19198c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, 19208c2ecf20Sopenharmony_ci USB_DEVICE_ID_MULTITOUCH_3200) }, 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci /* FocalTech Panels */ 19238c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_SERIAL, 19248c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL, 19258c2ecf20Sopenharmony_ci USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) }, 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* GeneralTouch panel */ 19288c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 19298c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19308c2ecf20Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, 19318c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19328c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19338c2ecf20Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, 19348c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 19358c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19368c2ecf20Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101) }, 19378c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19388c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19398c2ecf20Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102) }, 19408c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19418c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19428c2ecf20Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106) }, 19438c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19448c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19458c2ecf20Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A) }, 19468c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 19478c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 19488c2ecf20Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100) }, 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci /* Gametel game controller */ 19518c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 19528c2ecf20Sopenharmony_ci MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL, 19538c2ecf20Sopenharmony_ci USB_DEVICE_ID_GAMETEL_MT_MODE) }, 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci /* GoodTouch panels */ 19568c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 19578c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, 19588c2ecf20Sopenharmony_ci USB_DEVICE_ID_GOODTOUCH_000f) }, 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci /* Hanvon panels */ 19618c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 19628c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, 19638c2ecf20Sopenharmony_ci USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci /* HONOR GLO-GXXX panel */ 19668c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_VTL, 19678c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 19688c2ecf20Sopenharmony_ci 0x347d, 0x7853) }, 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci /* Ilitek dual touch panel */ 19718c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 19728c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, 19738c2ecf20Sopenharmony_ci USB_DEVICE_ID_ILITEK_MULTITOUCH) }, 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci /* LG Melfas panel */ 19768c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_LG, 19778c2ecf20Sopenharmony_ci HID_USB_DEVICE(USB_VENDOR_ID_LG, 19788c2ecf20Sopenharmony_ci USB_DEVICE_ID_LG_MELFAS_MT) }, 19798c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_LG, 19808c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_GENERIC, 19818c2ecf20Sopenharmony_ci USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_7010) }, 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci /* Lenovo X1 TAB Gen 2 */ 19848c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 19858c2ecf20Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 19868c2ecf20Sopenharmony_ci USB_VENDOR_ID_LENOVO, 19878c2ecf20Sopenharmony_ci USB_DEVICE_ID_LENOVO_X1_TAB) }, 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci /* Lenovo X1 TAB Gen 3 */ 19908c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 19918c2ecf20Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 19928c2ecf20Sopenharmony_ci USB_VENDOR_ID_LENOVO, 19938c2ecf20Sopenharmony_ci USB_DEVICE_ID_LENOVO_X1_TAB3) }, 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci /* Lenovo X12 TAB Gen 1 */ 19968c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 19978c2ecf20Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 19988c2ecf20Sopenharmony_ci USB_VENDOR_ID_LENOVO, 19998c2ecf20Sopenharmony_ci USB_DEVICE_ID_LENOVO_X12_TAB) }, 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci /* MosArt panels */ 20028c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 20038c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 20048c2ecf20Sopenharmony_ci USB_DEVICE_ID_ASUS_T91MT)}, 20058c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 20068c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 20078c2ecf20Sopenharmony_ci USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 20088c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 20098c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, 20108c2ecf20Sopenharmony_ci USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci /* Novatek Panel */ 20138c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 20148c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, 20158c2ecf20Sopenharmony_ci USB_DEVICE_ID_NOVATEK_PCT) }, 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci /* Ntrig Panel */ 20188c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 20198c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 20208c2ecf20Sopenharmony_ci USB_VENDOR_ID_NTRIG, 0x1b05) }, 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* Panasonic panels */ 20238c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_PANASONIC, 20248c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 20258c2ecf20Sopenharmony_ci USB_DEVICE_ID_PANABOARD_UBT780) }, 20268c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_PANASONIC, 20278c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 20288c2ecf20Sopenharmony_ci USB_DEVICE_ID_PANABOARD_UBT880) }, 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci /* PixArt optical touch screen */ 20318c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 20328c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 20338c2ecf20Sopenharmony_ci USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) }, 20348c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 20358c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 20368c2ecf20Sopenharmony_ci USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) }, 20378c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 20388c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 20398c2ecf20Sopenharmony_ci USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) }, 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci /* PixCir-based panels */ 20428c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 20438c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 20448c2ecf20Sopenharmony_ci USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci /* Quanta-based panels */ 20478c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 20488c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 20498c2ecf20Sopenharmony_ci USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci /* Razer touchpads */ 20528c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_RAZER_BLADE_STEALTH, 20538c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 20548c2ecf20Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0x8323) }, 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci /* Smart Tech panels */ 20578c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_SMART_TECH, 20588c2ecf20Sopenharmony_ci MT_USB_DEVICE(0x0b8c, 0x0092)}, 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* Stantum panels */ 20618c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE, 20628c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, 20638c2ecf20Sopenharmony_ci USB_DEVICE_ID_MTP_STM)}, 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci /* Synaptics devices */ 20668c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 20678c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 20688c2ecf20Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0xcd7e) }, 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 20718c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 20728c2ecf20Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0xce08) }, 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 20758c2ecf20Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 20768c2ecf20Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0xce09) }, 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci /* TopSeed panels */ 20798c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_TOPSEED, 20808c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, 20818c2ecf20Sopenharmony_ci USB_DEVICE_ID_TOPSEED2_PERIPAD_701) }, 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci /* Touch International panels */ 20848c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 20858c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, 20868c2ecf20Sopenharmony_ci USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci /* Unitec panels */ 20898c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 20908c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 20918c2ecf20Sopenharmony_ci USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, 20928c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 20938c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 20948c2ecf20Sopenharmony_ci USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci /* VTL panels */ 20978c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_VTL, 20988c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_VTL, 20998c2ecf20Sopenharmony_ci USB_DEVICE_ID_VTL_MULTITOUCH_FF3F) }, 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci /* Wistron panels */ 21028c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21038c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_WISTRON, 21048c2ecf20Sopenharmony_ci USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH) }, 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci /* XAT */ 21078c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21088c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XAT, 21098c2ecf20Sopenharmony_ci USB_DEVICE_ID_XAT_CSR) }, 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci /* Xiroku */ 21128c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21138c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21148c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_SPX) }, 21158c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21168c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21178c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_MPX) }, 21188c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21198c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21208c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_CSR) }, 21218c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21228c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21238c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_SPX1) }, 21248c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21258c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21268c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_MPX1) }, 21278c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21288c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21298c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_CSR1) }, 21308c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21318c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21328c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_SPX2) }, 21338c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21348c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21358c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_MPX2) }, 21368c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 21378c2ecf20Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 21388c2ecf20Sopenharmony_ci USB_DEVICE_ID_XIROKU_CSR2) }, 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci /* Google MT devices */ 21418c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GOOGLE, 21428c2ecf20Sopenharmony_ci HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, 21438c2ecf20Sopenharmony_ci USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) }, 21448c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_GOOGLE, 21458c2ecf20Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_GOOGLE, 21468c2ecf20Sopenharmony_ci USB_DEVICE_ID_GOOGLE_WHISKERS) }, 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci /* Generic MT device */ 21498c2ecf20Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci /* Generic Win 8 certified MT device */ 21528c2ecf20Sopenharmony_ci { .driver_data = MT_CLS_WIN_8, 21538c2ecf20Sopenharmony_ci HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8, 21548c2ecf20Sopenharmony_ci HID_ANY_ID, HID_ANY_ID) }, 21558c2ecf20Sopenharmony_ci { } 21568c2ecf20Sopenharmony_ci}; 21578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(hid, mt_devices); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_cistatic const struct hid_usage_id mt_grabbed_usages[] = { 21608c2ecf20Sopenharmony_ci { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 21618c2ecf20Sopenharmony_ci { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 21628c2ecf20Sopenharmony_ci}; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_cistatic struct hid_driver mt_driver = { 21658c2ecf20Sopenharmony_ci .name = "hid-multitouch", 21668c2ecf20Sopenharmony_ci .id_table = mt_devices, 21678c2ecf20Sopenharmony_ci .probe = mt_probe, 21688c2ecf20Sopenharmony_ci .remove = mt_remove, 21698c2ecf20Sopenharmony_ci .input_mapping = mt_input_mapping, 21708c2ecf20Sopenharmony_ci .input_mapped = mt_input_mapped, 21718c2ecf20Sopenharmony_ci .input_configured = mt_input_configured, 21728c2ecf20Sopenharmony_ci .feature_mapping = mt_feature_mapping, 21738c2ecf20Sopenharmony_ci .usage_table = mt_grabbed_usages, 21748c2ecf20Sopenharmony_ci .event = mt_event, 21758c2ecf20Sopenharmony_ci .report = mt_report, 21768c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 21778c2ecf20Sopenharmony_ci .reset_resume = mt_reset_resume, 21788c2ecf20Sopenharmony_ci .resume = mt_resume, 21798c2ecf20Sopenharmony_ci#endif 21808c2ecf20Sopenharmony_ci}; 21818c2ecf20Sopenharmony_cimodule_hid_driver(mt_driver); 2182