162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * HID driver for multitouch panels 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> 662306a36Sopenharmony_ci * Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com> 762306a36Sopenharmony_ci * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France 862306a36Sopenharmony_ci * Copyright (c) 2012-2013 Red Hat, Inc 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This code is partly based on hid-egalax.c: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> 1362306a36Sopenharmony_ci * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 1462306a36Sopenharmony_ci * Copyright (c) 2010 Canonical, Ltd. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * This code is partly based on hid-3m-pct.c: 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> 1962306a36Sopenharmony_ci * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 2062306a36Sopenharmony_ci * Copyright (c) 2010 Canonical, Ltd. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * This driver is regularly tested thanks to the test suite in hid-tools[1]. 2862306a36Sopenharmony_ci * Please run these regression tests before patching this module so that 2962306a36Sopenharmony_ci * your patch won't break existing known devices. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * [1] https://gitlab.freedesktop.org/libevdev/hid-tools 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/device.h> 3562306a36Sopenharmony_ci#include <linux/hid.h> 3662306a36Sopenharmony_ci#include <linux/module.h> 3762306a36Sopenharmony_ci#include <linux/slab.h> 3862306a36Sopenharmony_ci#include <linux/input/mt.h> 3962306a36Sopenharmony_ci#include <linux/jiffies.h> 4062306a36Sopenharmony_ci#include <linux/string.h> 4162306a36Sopenharmony_ci#include <linux/timer.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciMODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); 4562306a36Sopenharmony_ciMODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 4662306a36Sopenharmony_ciMODULE_DESCRIPTION("HID multitouch panels"); 4762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include "hid-ids.h" 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* quirks to control the device */ 5262306a36Sopenharmony_ci#define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) 5362306a36Sopenharmony_ci#define MT_QUIRK_SLOT_IS_CONTACTID BIT(1) 5462306a36Sopenharmony_ci#define MT_QUIRK_CYPRESS BIT(2) 5562306a36Sopenharmony_ci#define MT_QUIRK_SLOT_IS_CONTACTNUMBER BIT(3) 5662306a36Sopenharmony_ci#define MT_QUIRK_ALWAYS_VALID BIT(4) 5762306a36Sopenharmony_ci#define MT_QUIRK_VALID_IS_INRANGE BIT(5) 5862306a36Sopenharmony_ci#define MT_QUIRK_VALID_IS_CONFIDENCE BIT(6) 5962306a36Sopenharmony_ci#define MT_QUIRK_CONFIDENCE BIT(7) 6062306a36Sopenharmony_ci#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE BIT(8) 6162306a36Sopenharmony_ci#define MT_QUIRK_NO_AREA BIT(9) 6262306a36Sopenharmony_ci#define MT_QUIRK_IGNORE_DUPLICATES BIT(10) 6362306a36Sopenharmony_ci#define MT_QUIRK_HOVERING BIT(11) 6462306a36Sopenharmony_ci#define MT_QUIRK_CONTACT_CNT_ACCURATE BIT(12) 6562306a36Sopenharmony_ci#define MT_QUIRK_FORCE_GET_FEATURE BIT(13) 6662306a36Sopenharmony_ci#define MT_QUIRK_FIX_CONST_CONTACT_ID BIT(14) 6762306a36Sopenharmony_ci#define MT_QUIRK_TOUCH_SIZE_SCALING BIT(15) 6862306a36Sopenharmony_ci#define MT_QUIRK_STICKY_FINGERS BIT(16) 6962306a36Sopenharmony_ci#define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) 7062306a36Sopenharmony_ci#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18) 7162306a36Sopenharmony_ci#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19) 7262306a36Sopenharmony_ci#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) 7362306a36Sopenharmony_ci#define MT_QUIRK_DISABLE_WAKEUP BIT(21) 7462306a36Sopenharmony_ci#define MT_QUIRK_ORIENTATION_INVERT BIT(22) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define MT_INPUTMODE_TOUCHSCREEN 0x02 7762306a36Sopenharmony_ci#define MT_INPUTMODE_TOUCHPAD 0x03 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define MT_BUTTONTYPE_CLICKPAD 0 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cienum latency_mode { 8262306a36Sopenharmony_ci HID_LATENCY_NORMAL = 0, 8362306a36Sopenharmony_ci HID_LATENCY_HIGH = 1, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define MT_IO_FLAGS_RUNNING 0 8762306a36Sopenharmony_ci#define MT_IO_FLAGS_ACTIVE_SLOTS 1 8862306a36Sopenharmony_ci#define MT_IO_FLAGS_PENDING_SLOTS 2 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic const bool mtrue = true; /* default for true */ 9162306a36Sopenharmony_cistatic const bool mfalse; /* default for false */ 9262306a36Sopenharmony_cistatic const __s32 mzero; /* default for 0 */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define DEFAULT_TRUE ((void *)&mtrue) 9562306a36Sopenharmony_ci#define DEFAULT_FALSE ((void *)&mfalse) 9662306a36Sopenharmony_ci#define DEFAULT_ZERO ((void *)&mzero) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistruct mt_usages { 9962306a36Sopenharmony_ci struct list_head list; 10062306a36Sopenharmony_ci __s32 *x, *y, *cx, *cy, *p, *w, *h, *a; 10162306a36Sopenharmony_ci __s32 *contactid; /* the device ContactID assigned to this slot */ 10262306a36Sopenharmony_ci bool *tip_state; /* is the touch valid? */ 10362306a36Sopenharmony_ci bool *inrange_state; /* is the finger in proximity of the sensor? */ 10462306a36Sopenharmony_ci bool *confidence_state; /* is the touch made by a finger? */ 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistruct mt_application { 10862306a36Sopenharmony_ci struct list_head list; 10962306a36Sopenharmony_ci unsigned int application; 11062306a36Sopenharmony_ci unsigned int report_id; 11162306a36Sopenharmony_ci struct list_head mt_usages; /* mt usages list */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci __s32 quirks; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci __s32 *scantime; /* scantime reported */ 11662306a36Sopenharmony_ci __s32 scantime_logical_max; /* max value for raw scantime */ 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci __s32 *raw_cc; /* contact count in the report */ 11962306a36Sopenharmony_ci int left_button_state; /* left button state */ 12062306a36Sopenharmony_ci unsigned int mt_flags; /* flags to pass to input-mt */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci unsigned long *pending_palm_slots; /* slots where we reported palm 12362306a36Sopenharmony_ci * and need to release */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci __u8 num_received; /* how many contacts we received */ 12662306a36Sopenharmony_ci __u8 num_expected; /* expected last contact index */ 12762306a36Sopenharmony_ci __u8 buttons_count; /* number of physical buttons per touchpad */ 12862306a36Sopenharmony_ci __u8 touches_by_report; /* how many touches are present in one report: 12962306a36Sopenharmony_ci * 1 means we should use a serial protocol 13062306a36Sopenharmony_ci * > 1 means hybrid (multitouch) protocol 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci __s32 dev_time; /* the scan time provided by the device */ 13462306a36Sopenharmony_ci unsigned long jiffies; /* the frame's jiffies */ 13562306a36Sopenharmony_ci int timestamp; /* the timestamp to be sent */ 13662306a36Sopenharmony_ci int prev_scantime; /* scantime reported previously */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci bool have_contact_count; 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistruct mt_class { 14262306a36Sopenharmony_ci __s32 name; /* MT_CLS */ 14362306a36Sopenharmony_ci __s32 quirks; 14462306a36Sopenharmony_ci __s32 sn_move; /* Signal/noise ratio for move events */ 14562306a36Sopenharmony_ci __s32 sn_width; /* Signal/noise ratio for width events */ 14662306a36Sopenharmony_ci __s32 sn_height; /* Signal/noise ratio for height events */ 14762306a36Sopenharmony_ci __s32 sn_pressure; /* Signal/noise ratio for pressure events */ 14862306a36Sopenharmony_ci __u8 maxcontacts; 14962306a36Sopenharmony_ci bool is_indirect; /* true for touchpads */ 15062306a36Sopenharmony_ci bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */ 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistruct mt_report_data { 15462306a36Sopenharmony_ci struct list_head list; 15562306a36Sopenharmony_ci struct hid_report *report; 15662306a36Sopenharmony_ci struct mt_application *application; 15762306a36Sopenharmony_ci bool is_mt_collection; 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistruct mt_device { 16162306a36Sopenharmony_ci struct mt_class mtclass; /* our mt device class */ 16262306a36Sopenharmony_ci struct timer_list release_timer; /* to release sticky fingers */ 16362306a36Sopenharmony_ci struct hid_device *hdev; /* hid_device we're attached to */ 16462306a36Sopenharmony_ci unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ 16562306a36Sopenharmony_ci __u8 inputmode_value; /* InputMode HID feature value */ 16662306a36Sopenharmony_ci __u8 maxcontacts; 16762306a36Sopenharmony_ci bool is_buttonpad; /* is this device a button pad? */ 16862306a36Sopenharmony_ci bool serial_maybe; /* need to check for serial protocol */ 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci struct list_head applications; 17162306a36Sopenharmony_ci struct list_head reports; 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void mt_post_parse_default_settings(struct mt_device *td, 17562306a36Sopenharmony_ci struct mt_application *app); 17662306a36Sopenharmony_cistatic void mt_post_parse(struct mt_device *td, struct mt_application *app); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* classes of device behavior */ 17962306a36Sopenharmony_ci#define MT_CLS_DEFAULT 0x0001 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#define MT_CLS_SERIAL 0x0002 18262306a36Sopenharmony_ci#define MT_CLS_CONFIDENCE 0x0003 18362306a36Sopenharmony_ci#define MT_CLS_CONFIDENCE_CONTACT_ID 0x0004 18462306a36Sopenharmony_ci#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 18562306a36Sopenharmony_ci#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 18662306a36Sopenharmony_ci#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 18762306a36Sopenharmony_ci/* reserved 0x0008 */ 18862306a36Sopenharmony_ci#define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 18962306a36Sopenharmony_ci#define MT_CLS_NSMU 0x000a 19062306a36Sopenharmony_ci/* reserved 0x0010 */ 19162306a36Sopenharmony_ci/* reserved 0x0011 */ 19262306a36Sopenharmony_ci#define MT_CLS_WIN_8 0x0012 19362306a36Sopenharmony_ci#define MT_CLS_EXPORT_ALL_INPUTS 0x0013 19462306a36Sopenharmony_ci/* reserved 0x0014 */ 19562306a36Sopenharmony_ci#define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015 19662306a36Sopenharmony_ci#define MT_CLS_WIN_8_DISABLE_WAKEUP 0x0016 19762306a36Sopenharmony_ci#define MT_CLS_WIN_8_NO_STICKY_FINGERS 0x0017 19862306a36Sopenharmony_ci#define MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU 0x0018 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* vendor specific classes */ 20162306a36Sopenharmony_ci#define MT_CLS_3M 0x0101 20262306a36Sopenharmony_ci/* reserved 0x0102 */ 20362306a36Sopenharmony_ci#define MT_CLS_EGALAX 0x0103 20462306a36Sopenharmony_ci#define MT_CLS_EGALAX_SERIAL 0x0104 20562306a36Sopenharmony_ci#define MT_CLS_TOPSEED 0x0105 20662306a36Sopenharmony_ci#define MT_CLS_PANASONIC 0x0106 20762306a36Sopenharmony_ci#define MT_CLS_FLATFROG 0x0107 20862306a36Sopenharmony_ci#define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 20962306a36Sopenharmony_ci#define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 21062306a36Sopenharmony_ci#define MT_CLS_LG 0x010a 21162306a36Sopenharmony_ci#define MT_CLS_ASUS 0x010b 21262306a36Sopenharmony_ci#define MT_CLS_VTL 0x0110 21362306a36Sopenharmony_ci#define MT_CLS_GOOGLE 0x0111 21462306a36Sopenharmony_ci#define MT_CLS_RAZER_BLADE_STEALTH 0x0112 21562306a36Sopenharmony_ci#define MT_CLS_SMART_TECH 0x0113 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci#define MT_DEFAULT_MAXCONTACT 10 21862306a36Sopenharmony_ci#define MT_MAX_MAXCONTACT 250 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* 22162306a36Sopenharmony_ci * Resync device and local timestamps after that many microseconds without 22262306a36Sopenharmony_ci * receiving data. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci#define MAX_TIMESTAMP_INTERVAL 1000000 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci#define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) 22762306a36Sopenharmony_ci#define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* 23062306a36Sopenharmony_ci * these device-dependent functions determine what slot corresponds 23162306a36Sopenharmony_ci * to a valid contact that was just read. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int cypress_compute_slot(struct mt_application *application, 23562306a36Sopenharmony_ci struct mt_usages *slot) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci if (*slot->contactid != 0 || application->num_received == 0) 23862306a36Sopenharmony_ci return *slot->contactid; 23962306a36Sopenharmony_ci else 24062306a36Sopenharmony_ci return -1; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic const struct mt_class mt_classes[] = { 24462306a36Sopenharmony_ci { .name = MT_CLS_DEFAULT, 24562306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 24662306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE }, 24762306a36Sopenharmony_ci { .name = MT_CLS_NSMU, 24862306a36Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, 24962306a36Sopenharmony_ci { .name = MT_CLS_SERIAL, 25062306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID}, 25162306a36Sopenharmony_ci { .name = MT_CLS_CONFIDENCE, 25262306a36Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, 25362306a36Sopenharmony_ci { .name = MT_CLS_CONFIDENCE_CONTACT_ID, 25462306a36Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 25562306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID }, 25662306a36Sopenharmony_ci { .name = MT_CLS_CONFIDENCE_MINUS_ONE, 25762306a36Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 25862306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, 25962306a36Sopenharmony_ci { .name = MT_CLS_DUAL_INRANGE_CONTACTID, 26062306a36Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_INRANGE | 26162306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID, 26262306a36Sopenharmony_ci .maxcontacts = 2 }, 26362306a36Sopenharmony_ci { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 26462306a36Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_INRANGE | 26562306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTNUMBER, 26662306a36Sopenharmony_ci .maxcontacts = 2 }, 26762306a36Sopenharmony_ci { .name = MT_CLS_INRANGE_CONTACTNUMBER, 26862306a36Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_INRANGE | 26962306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTNUMBER }, 27062306a36Sopenharmony_ci { .name = MT_CLS_WIN_8, 27162306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 27262306a36Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 27362306a36Sopenharmony_ci MT_QUIRK_HOVERING | 27462306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 27562306a36Sopenharmony_ci MT_QUIRK_STICKY_FINGERS | 27662306a36Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS, 27762306a36Sopenharmony_ci .export_all_inputs = true }, 27862306a36Sopenharmony_ci { .name = MT_CLS_EXPORT_ALL_INPUTS, 27962306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 28062306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE, 28162306a36Sopenharmony_ci .export_all_inputs = true }, 28262306a36Sopenharmony_ci { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 28362306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 28462306a36Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 28562306a36Sopenharmony_ci MT_QUIRK_HOVERING | 28662306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 28762306a36Sopenharmony_ci MT_QUIRK_STICKY_FINGERS | 28862306a36Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS | 28962306a36Sopenharmony_ci MT_QUIRK_FORCE_MULTI_INPUT, 29062306a36Sopenharmony_ci .export_all_inputs = true }, 29162306a36Sopenharmony_ci { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, 29262306a36Sopenharmony_ci .quirks = MT_QUIRK_IGNORE_DUPLICATES | 29362306a36Sopenharmony_ci MT_QUIRK_HOVERING | 29462306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 29562306a36Sopenharmony_ci MT_QUIRK_STICKY_FINGERS | 29662306a36Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS | 29762306a36Sopenharmony_ci MT_QUIRK_FORCE_MULTI_INPUT | 29862306a36Sopenharmony_ci MT_QUIRK_NOT_SEEN_MEANS_UP, 29962306a36Sopenharmony_ci .export_all_inputs = true }, 30062306a36Sopenharmony_ci { .name = MT_CLS_WIN_8_DISABLE_WAKEUP, 30162306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 30262306a36Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 30362306a36Sopenharmony_ci MT_QUIRK_HOVERING | 30462306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 30562306a36Sopenharmony_ci MT_QUIRK_STICKY_FINGERS | 30662306a36Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS | 30762306a36Sopenharmony_ci MT_QUIRK_DISABLE_WAKEUP, 30862306a36Sopenharmony_ci .export_all_inputs = true }, 30962306a36Sopenharmony_ci { .name = MT_CLS_WIN_8_NO_STICKY_FINGERS, 31062306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 31162306a36Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 31262306a36Sopenharmony_ci MT_QUIRK_HOVERING | 31362306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 31462306a36Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS, 31562306a36Sopenharmony_ci .export_all_inputs = true }, 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * vendor specific classes 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci { .name = MT_CLS_3M, 32162306a36Sopenharmony_ci .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 32262306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID | 32362306a36Sopenharmony_ci MT_QUIRK_TOUCH_SIZE_SCALING, 32462306a36Sopenharmony_ci .sn_move = 2048, 32562306a36Sopenharmony_ci .sn_width = 128, 32662306a36Sopenharmony_ci .sn_height = 128, 32762306a36Sopenharmony_ci .maxcontacts = 60, 32862306a36Sopenharmony_ci }, 32962306a36Sopenharmony_ci { .name = MT_CLS_EGALAX, 33062306a36Sopenharmony_ci .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 33162306a36Sopenharmony_ci MT_QUIRK_VALID_IS_INRANGE, 33262306a36Sopenharmony_ci .sn_move = 4096, 33362306a36Sopenharmony_ci .sn_pressure = 32, 33462306a36Sopenharmony_ci }, 33562306a36Sopenharmony_ci { .name = MT_CLS_EGALAX_SERIAL, 33662306a36Sopenharmony_ci .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 33762306a36Sopenharmony_ci MT_QUIRK_ALWAYS_VALID, 33862306a36Sopenharmony_ci .sn_move = 4096, 33962306a36Sopenharmony_ci .sn_pressure = 32, 34062306a36Sopenharmony_ci }, 34162306a36Sopenharmony_ci { .name = MT_CLS_TOPSEED, 34262306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID, 34362306a36Sopenharmony_ci .is_indirect = true, 34462306a36Sopenharmony_ci .maxcontacts = 2, 34562306a36Sopenharmony_ci }, 34662306a36Sopenharmony_ci { .name = MT_CLS_PANASONIC, 34762306a36Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, 34862306a36Sopenharmony_ci .maxcontacts = 4 }, 34962306a36Sopenharmony_ci { .name = MT_CLS_GENERALTOUCH_TWOFINGERS, 35062306a36Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 35162306a36Sopenharmony_ci MT_QUIRK_VALID_IS_INRANGE | 35262306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID, 35362306a36Sopenharmony_ci .maxcontacts = 2 35462306a36Sopenharmony_ci }, 35562306a36Sopenharmony_ci { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 35662306a36Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 35762306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID 35862306a36Sopenharmony_ci }, 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci { .name = MT_CLS_FLATFROG, 36162306a36Sopenharmony_ci .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 36262306a36Sopenharmony_ci MT_QUIRK_NO_AREA, 36362306a36Sopenharmony_ci .sn_move = 2048, 36462306a36Sopenharmony_ci .maxcontacts = 40, 36562306a36Sopenharmony_ci }, 36662306a36Sopenharmony_ci { .name = MT_CLS_LG, 36762306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 36862306a36Sopenharmony_ci MT_QUIRK_FIX_CONST_CONTACT_ID | 36962306a36Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 37062306a36Sopenharmony_ci MT_QUIRK_HOVERING | 37162306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE }, 37262306a36Sopenharmony_ci { .name = MT_CLS_ASUS, 37362306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 37462306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 37562306a36Sopenharmony_ci MT_QUIRK_ASUS_CUSTOM_UP }, 37662306a36Sopenharmony_ci { .name = MT_CLS_VTL, 37762306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 37862306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 37962306a36Sopenharmony_ci MT_QUIRK_FORCE_GET_FEATURE, 38062306a36Sopenharmony_ci }, 38162306a36Sopenharmony_ci { .name = MT_CLS_GOOGLE, 38262306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 38362306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 38462306a36Sopenharmony_ci MT_QUIRK_SLOT_IS_CONTACTID | 38562306a36Sopenharmony_ci MT_QUIRK_HOVERING 38662306a36Sopenharmony_ci }, 38762306a36Sopenharmony_ci { .name = MT_CLS_RAZER_BLADE_STEALTH, 38862306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 38962306a36Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 39062306a36Sopenharmony_ci MT_QUIRK_HOVERING | 39162306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 39262306a36Sopenharmony_ci MT_QUIRK_WIN8_PTP_BUTTONS, 39362306a36Sopenharmony_ci }, 39462306a36Sopenharmony_ci { .name = MT_CLS_SMART_TECH, 39562306a36Sopenharmony_ci .quirks = MT_QUIRK_ALWAYS_VALID | 39662306a36Sopenharmony_ci MT_QUIRK_IGNORE_DUPLICATES | 39762306a36Sopenharmony_ci MT_QUIRK_CONTACT_CNT_ACCURATE | 39862306a36Sopenharmony_ci MT_QUIRK_SEPARATE_APP_REPORT, 39962306a36Sopenharmony_ci }, 40062306a36Sopenharmony_ci { } 40162306a36Sopenharmony_ci}; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic ssize_t mt_show_quirks(struct device *dev, 40462306a36Sopenharmony_ci struct device_attribute *attr, 40562306a36Sopenharmony_ci char *buf) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct hid_device *hdev = to_hid_device(dev); 40862306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return sprintf(buf, "%u\n", td->mtclass.quirks); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic ssize_t mt_set_quirks(struct device *dev, 41462306a36Sopenharmony_ci struct device_attribute *attr, 41562306a36Sopenharmony_ci const char *buf, size_t count) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct hid_device *hdev = to_hid_device(dev); 41862306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 41962306a36Sopenharmony_ci struct mt_application *application; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci unsigned long val; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (kstrtoul(buf, 0, &val)) 42462306a36Sopenharmony_ci return -EINVAL; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci td->mtclass.quirks = val; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci list_for_each_entry(application, &td->applications, list) { 42962306a36Sopenharmony_ci application->quirks = val; 43062306a36Sopenharmony_ci if (!application->have_contact_count) 43162306a36Sopenharmony_ci application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return count; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic struct attribute *sysfs_attrs[] = { 44062306a36Sopenharmony_ci &dev_attr_quirks.attr, 44162306a36Sopenharmony_ci NULL 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic const struct attribute_group mt_attribute_group = { 44562306a36Sopenharmony_ci .attrs = sysfs_attrs 44662306a36Sopenharmony_ci}; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void mt_get_feature(struct hid_device *hdev, struct hid_report *report) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci int ret; 45162306a36Sopenharmony_ci u32 size = hid_report_len(report); 45262306a36Sopenharmony_ci u8 *buf; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* 45562306a36Sopenharmony_ci * Do not fetch the feature report if the device has been explicitly 45662306a36Sopenharmony_ci * marked as non-capable. 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci if (hdev->quirks & HID_QUIRK_NO_INIT_REPORTS) 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci buf = hid_alloc_report_buf(report, GFP_KERNEL); 46262306a36Sopenharmony_ci if (!buf) 46362306a36Sopenharmony_ci return; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci ret = hid_hw_raw_request(hdev, report->id, buf, size, 46662306a36Sopenharmony_ci HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 46762306a36Sopenharmony_ci if (ret < 0) { 46862306a36Sopenharmony_ci dev_warn(&hdev->dev, "failed to fetch feature %d\n", 46962306a36Sopenharmony_ci report->id); 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, 47262306a36Sopenharmony_ci size, 0); 47362306a36Sopenharmony_ci if (ret) 47462306a36Sopenharmony_ci dev_warn(&hdev->dev, "failed to report feature\n"); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci kfree(buf); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void mt_feature_mapping(struct hid_device *hdev, 48162306a36Sopenharmony_ci struct hid_field *field, struct hid_usage *usage) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci switch (usage->hid) { 48662306a36Sopenharmony_ci case HID_DG_CONTACTMAX: 48762306a36Sopenharmony_ci mt_get_feature(hdev, field->report); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci td->maxcontacts = field->value[0]; 49062306a36Sopenharmony_ci if (!td->maxcontacts && 49162306a36Sopenharmony_ci field->logical_maximum <= MT_MAX_MAXCONTACT) 49262306a36Sopenharmony_ci td->maxcontacts = field->logical_maximum; 49362306a36Sopenharmony_ci if (td->mtclass.maxcontacts) 49462306a36Sopenharmony_ci /* check if the maxcontacts is given by the class */ 49562306a36Sopenharmony_ci td->maxcontacts = td->mtclass.maxcontacts; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci case HID_DG_BUTTONTYPE: 49962306a36Sopenharmony_ci if (usage->usage_index >= field->report_count) { 50062306a36Sopenharmony_ci dev_err(&hdev->dev, "HID_DG_BUTTONTYPE out of range\n"); 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci mt_get_feature(hdev, field->report); 50562306a36Sopenharmony_ci if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD) 50662306a36Sopenharmony_ci td->is_buttonpad = true; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci case 0xff0000c5: 51062306a36Sopenharmony_ci /* Retrieve the Win8 blob once to enable some devices */ 51162306a36Sopenharmony_ci if (usage->usage_index == 0) 51262306a36Sopenharmony_ci mt_get_feature(hdev, field->report); 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic void set_abs(struct input_dev *input, unsigned int code, 51862306a36Sopenharmony_ci struct hid_field *field, int snratio) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci int fmin = field->logical_minimum; 52162306a36Sopenharmony_ci int fmax = field->logical_maximum; 52262306a36Sopenharmony_ci int fuzz = snratio ? (fmax - fmin) / snratio : 0; 52362306a36Sopenharmony_ci input_set_abs_params(input, code, fmin, fmax, fuzz, 0); 52462306a36Sopenharmony_ci input_abs_set_res(input, code, hidinput_calc_abs_res(field, code)); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic struct mt_usages *mt_allocate_usage(struct hid_device *hdev, 52862306a36Sopenharmony_ci struct mt_application *application) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct mt_usages *usage; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci usage = devm_kzalloc(&hdev->dev, sizeof(*usage), GFP_KERNEL); 53362306a36Sopenharmony_ci if (!usage) 53462306a36Sopenharmony_ci return NULL; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* set some defaults so we do not need to check for null pointers */ 53762306a36Sopenharmony_ci usage->x = DEFAULT_ZERO; 53862306a36Sopenharmony_ci usage->y = DEFAULT_ZERO; 53962306a36Sopenharmony_ci usage->cx = DEFAULT_ZERO; 54062306a36Sopenharmony_ci usage->cy = DEFAULT_ZERO; 54162306a36Sopenharmony_ci usage->p = DEFAULT_ZERO; 54262306a36Sopenharmony_ci usage->w = DEFAULT_ZERO; 54362306a36Sopenharmony_ci usage->h = DEFAULT_ZERO; 54462306a36Sopenharmony_ci usage->a = DEFAULT_ZERO; 54562306a36Sopenharmony_ci usage->contactid = DEFAULT_ZERO; 54662306a36Sopenharmony_ci usage->tip_state = DEFAULT_FALSE; 54762306a36Sopenharmony_ci usage->inrange_state = DEFAULT_FALSE; 54862306a36Sopenharmony_ci usage->confidence_state = DEFAULT_TRUE; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci list_add_tail(&usage->list, &application->mt_usages); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return usage; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic struct mt_application *mt_allocate_application(struct mt_device *td, 55662306a36Sopenharmony_ci struct hid_report *report) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci unsigned int application = report->application; 55962306a36Sopenharmony_ci struct mt_application *mt_application; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application), 56262306a36Sopenharmony_ci GFP_KERNEL); 56362306a36Sopenharmony_ci if (!mt_application) 56462306a36Sopenharmony_ci return NULL; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci mt_application->application = application; 56762306a36Sopenharmony_ci INIT_LIST_HEAD(&mt_application->mt_usages); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (application == HID_DG_TOUCHSCREEN) 57062306a36Sopenharmony_ci mt_application->mt_flags |= INPUT_MT_DIRECT; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* 57362306a36Sopenharmony_ci * Model touchscreens providing buttons as touchpads. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_ci if (application == HID_DG_TOUCHPAD) { 57662306a36Sopenharmony_ci mt_application->mt_flags |= INPUT_MT_POINTER; 57762306a36Sopenharmony_ci td->inputmode_value = MT_INPUTMODE_TOUCHPAD; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci mt_application->scantime = DEFAULT_ZERO; 58162306a36Sopenharmony_ci mt_application->raw_cc = DEFAULT_ZERO; 58262306a36Sopenharmony_ci mt_application->quirks = td->mtclass.quirks; 58362306a36Sopenharmony_ci mt_application->report_id = report->id; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci list_add_tail(&mt_application->list, &td->applications); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return mt_application; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic struct mt_application *mt_find_application(struct mt_device *td, 59162306a36Sopenharmony_ci struct hid_report *report) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci unsigned int application = report->application; 59462306a36Sopenharmony_ci struct mt_application *tmp, *mt_application = NULL; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci list_for_each_entry(tmp, &td->applications, list) { 59762306a36Sopenharmony_ci if (application == tmp->application) { 59862306a36Sopenharmony_ci if (!(td->mtclass.quirks & MT_QUIRK_SEPARATE_APP_REPORT) || 59962306a36Sopenharmony_ci tmp->report_id == report->id) { 60062306a36Sopenharmony_ci mt_application = tmp; 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (!mt_application) 60762306a36Sopenharmony_ci mt_application = mt_allocate_application(td, report); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return mt_application; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic struct mt_report_data *mt_allocate_report_data(struct mt_device *td, 61362306a36Sopenharmony_ci struct hid_report *report) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct mt_report_data *rdata; 61662306a36Sopenharmony_ci struct hid_field *field; 61762306a36Sopenharmony_ci int r, n; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL); 62062306a36Sopenharmony_ci if (!rdata) 62162306a36Sopenharmony_ci return NULL; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci rdata->report = report; 62462306a36Sopenharmony_ci rdata->application = mt_find_application(td, report); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (!rdata->application) { 62762306a36Sopenharmony_ci devm_kfree(&td->hdev->dev, rdata); 62862306a36Sopenharmony_ci return NULL; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci for (r = 0; r < report->maxfield; r++) { 63262306a36Sopenharmony_ci field = report->field[r]; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) 63562306a36Sopenharmony_ci continue; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (field->logical == HID_DG_FINGER || td->hdev->group != HID_GROUP_MULTITOUCH_WIN_8) { 63862306a36Sopenharmony_ci for (n = 0; n < field->report_count; n++) { 63962306a36Sopenharmony_ci if (field->usage[n].hid == HID_DG_CONTACTID) { 64062306a36Sopenharmony_ci rdata->is_mt_collection = true; 64162306a36Sopenharmony_ci break; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci list_add_tail(&rdata->list, &td->reports); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return rdata; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic struct mt_report_data *mt_find_report_data(struct mt_device *td, 65362306a36Sopenharmony_ci struct hid_report *report) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct mt_report_data *tmp, *rdata = NULL; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci list_for_each_entry(tmp, &td->reports, list) { 65862306a36Sopenharmony_ci if (report == tmp->report) { 65962306a36Sopenharmony_ci rdata = tmp; 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (!rdata) 66562306a36Sopenharmony_ci rdata = mt_allocate_report_data(td, report); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return rdata; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic void mt_store_field(struct hid_device *hdev, 67162306a36Sopenharmony_ci struct mt_application *application, 67262306a36Sopenharmony_ci __s32 *value, 67362306a36Sopenharmony_ci size_t offset) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct mt_usages *usage; 67662306a36Sopenharmony_ci __s32 **target; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (list_empty(&application->mt_usages)) 67962306a36Sopenharmony_ci usage = mt_allocate_usage(hdev, application); 68062306a36Sopenharmony_ci else 68162306a36Sopenharmony_ci usage = list_last_entry(&application->mt_usages, 68262306a36Sopenharmony_ci struct mt_usages, 68362306a36Sopenharmony_ci list); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (!usage) 68662306a36Sopenharmony_ci return; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci target = (__s32 **)((char *)usage + offset); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* the value has already been filled, create a new slot */ 69162306a36Sopenharmony_ci if (*target != DEFAULT_TRUE && 69262306a36Sopenharmony_ci *target != DEFAULT_FALSE && 69362306a36Sopenharmony_ci *target != DEFAULT_ZERO) { 69462306a36Sopenharmony_ci if (usage->contactid == DEFAULT_ZERO || 69562306a36Sopenharmony_ci usage->x == DEFAULT_ZERO || 69662306a36Sopenharmony_ci usage->y == DEFAULT_ZERO) { 69762306a36Sopenharmony_ci hid_dbg(hdev, 69862306a36Sopenharmony_ci "ignoring duplicate usage on incomplete"); 69962306a36Sopenharmony_ci return; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci usage = mt_allocate_usage(hdev, application); 70262306a36Sopenharmony_ci if (!usage) 70362306a36Sopenharmony_ci return; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci target = (__s32 **)((char *)usage + offset); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci *target = value; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci#define MT_STORE_FIELD(__name) \ 71262306a36Sopenharmony_ci mt_store_field(hdev, app, \ 71362306a36Sopenharmony_ci &field->value[usage->usage_index], \ 71462306a36Sopenharmony_ci offsetof(struct mt_usages, __name)) 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, 71762306a36Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 71862306a36Sopenharmony_ci unsigned long **bit, int *max, struct mt_application *app) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 72162306a36Sopenharmony_ci struct mt_class *cls = &td->mtclass; 72262306a36Sopenharmony_ci int code; 72362306a36Sopenharmony_ci struct hid_usage *prev_usage = NULL; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* 72662306a36Sopenharmony_ci * Model touchscreens providing buttons as touchpads. 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_ci if (field->application == HID_DG_TOUCHSCREEN && 72962306a36Sopenharmony_ci (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { 73062306a36Sopenharmony_ci app->mt_flags |= INPUT_MT_POINTER; 73162306a36Sopenharmony_ci td->inputmode_value = MT_INPUTMODE_TOUCHPAD; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* count the buttons on touchpads */ 73562306a36Sopenharmony_ci if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) 73662306a36Sopenharmony_ci app->buttons_count++; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (usage->usage_index) 73962306a36Sopenharmony_ci prev_usage = &field->usage[usage->usage_index - 1]; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci switch (usage->hid & HID_USAGE_PAGE) { 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci case HID_UP_GENDESK: 74462306a36Sopenharmony_ci switch (usage->hid) { 74562306a36Sopenharmony_ci case HID_GD_X: 74662306a36Sopenharmony_ci if (prev_usage && (prev_usage->hid == usage->hid)) { 74762306a36Sopenharmony_ci code = ABS_MT_TOOL_X; 74862306a36Sopenharmony_ci MT_STORE_FIELD(cx); 74962306a36Sopenharmony_ci } else { 75062306a36Sopenharmony_ci code = ABS_MT_POSITION_X; 75162306a36Sopenharmony_ci MT_STORE_FIELD(x); 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci set_abs(hi->input, code, field, cls->sn_move); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* 75762306a36Sopenharmony_ci * A system multi-axis that exports X and Y has a high 75862306a36Sopenharmony_ci * chance of being used directly on a surface 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci if (field->application == HID_GD_SYSTEM_MULTIAXIS) { 76162306a36Sopenharmony_ci __set_bit(INPUT_PROP_DIRECT, 76262306a36Sopenharmony_ci hi->input->propbit); 76362306a36Sopenharmony_ci input_set_abs_params(hi->input, 76462306a36Sopenharmony_ci ABS_MT_TOOL_TYPE, 76562306a36Sopenharmony_ci MT_TOOL_DIAL, 76662306a36Sopenharmony_ci MT_TOOL_DIAL, 0, 0); 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci return 1; 77062306a36Sopenharmony_ci case HID_GD_Y: 77162306a36Sopenharmony_ci if (prev_usage && (prev_usage->hid == usage->hid)) { 77262306a36Sopenharmony_ci code = ABS_MT_TOOL_Y; 77362306a36Sopenharmony_ci MT_STORE_FIELD(cy); 77462306a36Sopenharmony_ci } else { 77562306a36Sopenharmony_ci code = ABS_MT_POSITION_Y; 77662306a36Sopenharmony_ci MT_STORE_FIELD(y); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci set_abs(hi->input, code, field, cls->sn_move); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return 1; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci case HID_UP_DIGITIZER: 78662306a36Sopenharmony_ci switch (usage->hid) { 78762306a36Sopenharmony_ci case HID_DG_INRANGE: 78862306a36Sopenharmony_ci if (app->quirks & MT_QUIRK_HOVERING) { 78962306a36Sopenharmony_ci input_set_abs_params(hi->input, 79062306a36Sopenharmony_ci ABS_MT_DISTANCE, 0, 1, 0, 0); 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci MT_STORE_FIELD(inrange_state); 79362306a36Sopenharmony_ci return 1; 79462306a36Sopenharmony_ci case HID_DG_CONFIDENCE: 79562306a36Sopenharmony_ci if ((cls->name == MT_CLS_WIN_8 || 79662306a36Sopenharmony_ci cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT || 79762306a36Sopenharmony_ci cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU || 79862306a36Sopenharmony_ci cls->name == MT_CLS_WIN_8_DISABLE_WAKEUP) && 79962306a36Sopenharmony_ci (field->application == HID_DG_TOUCHPAD || 80062306a36Sopenharmony_ci field->application == HID_DG_TOUCHSCREEN)) 80162306a36Sopenharmony_ci app->quirks |= MT_QUIRK_CONFIDENCE; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (app->quirks & MT_QUIRK_CONFIDENCE) 80462306a36Sopenharmony_ci input_set_abs_params(hi->input, 80562306a36Sopenharmony_ci ABS_MT_TOOL_TYPE, 80662306a36Sopenharmony_ci MT_TOOL_FINGER, 80762306a36Sopenharmony_ci MT_TOOL_PALM, 0, 0); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci MT_STORE_FIELD(confidence_state); 81062306a36Sopenharmony_ci return 1; 81162306a36Sopenharmony_ci case HID_DG_TIPSWITCH: 81262306a36Sopenharmony_ci if (field->application != HID_GD_SYSTEM_MULTIAXIS) 81362306a36Sopenharmony_ci input_set_capability(hi->input, 81462306a36Sopenharmony_ci EV_KEY, BTN_TOUCH); 81562306a36Sopenharmony_ci MT_STORE_FIELD(tip_state); 81662306a36Sopenharmony_ci return 1; 81762306a36Sopenharmony_ci case HID_DG_CONTACTID: 81862306a36Sopenharmony_ci MT_STORE_FIELD(contactid); 81962306a36Sopenharmony_ci app->touches_by_report++; 82062306a36Sopenharmony_ci return 1; 82162306a36Sopenharmony_ci case HID_DG_WIDTH: 82262306a36Sopenharmony_ci if (!(app->quirks & MT_QUIRK_NO_AREA)) 82362306a36Sopenharmony_ci set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, 82462306a36Sopenharmony_ci cls->sn_width); 82562306a36Sopenharmony_ci MT_STORE_FIELD(w); 82662306a36Sopenharmony_ci return 1; 82762306a36Sopenharmony_ci case HID_DG_HEIGHT: 82862306a36Sopenharmony_ci if (!(app->quirks & MT_QUIRK_NO_AREA)) { 82962306a36Sopenharmony_ci set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, 83062306a36Sopenharmony_ci cls->sn_height); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * Only set ABS_MT_ORIENTATION if it is not 83462306a36Sopenharmony_ci * already set by the HID_DG_AZIMUTH usage. 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_ci if (!test_bit(ABS_MT_ORIENTATION, 83762306a36Sopenharmony_ci hi->input->absbit)) 83862306a36Sopenharmony_ci input_set_abs_params(hi->input, 83962306a36Sopenharmony_ci ABS_MT_ORIENTATION, 0, 1, 0, 0); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci MT_STORE_FIELD(h); 84262306a36Sopenharmony_ci return 1; 84362306a36Sopenharmony_ci case HID_DG_TIPPRESSURE: 84462306a36Sopenharmony_ci set_abs(hi->input, ABS_MT_PRESSURE, field, 84562306a36Sopenharmony_ci cls->sn_pressure); 84662306a36Sopenharmony_ci MT_STORE_FIELD(p); 84762306a36Sopenharmony_ci return 1; 84862306a36Sopenharmony_ci case HID_DG_SCANTIME: 84962306a36Sopenharmony_ci input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); 85062306a36Sopenharmony_ci app->scantime = &field->value[usage->usage_index]; 85162306a36Sopenharmony_ci app->scantime_logical_max = field->logical_maximum; 85262306a36Sopenharmony_ci return 1; 85362306a36Sopenharmony_ci case HID_DG_CONTACTCOUNT: 85462306a36Sopenharmony_ci app->have_contact_count = true; 85562306a36Sopenharmony_ci app->raw_cc = &field->value[usage->usage_index]; 85662306a36Sopenharmony_ci return 1; 85762306a36Sopenharmony_ci case HID_DG_AZIMUTH: 85862306a36Sopenharmony_ci /* 85962306a36Sopenharmony_ci * Azimuth has the range of [0, MAX) representing a full 86062306a36Sopenharmony_ci * revolution. Set ABS_MT_ORIENTATION to a quarter of 86162306a36Sopenharmony_ci * MAX according the definition of ABS_MT_ORIENTATION 86262306a36Sopenharmony_ci */ 86362306a36Sopenharmony_ci input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 86462306a36Sopenharmony_ci -field->logical_maximum / 4, 86562306a36Sopenharmony_ci field->logical_maximum / 4, 86662306a36Sopenharmony_ci cls->sn_move ? 86762306a36Sopenharmony_ci field->logical_maximum / cls->sn_move : 0, 0); 86862306a36Sopenharmony_ci MT_STORE_FIELD(a); 86962306a36Sopenharmony_ci return 1; 87062306a36Sopenharmony_ci case HID_DG_CONTACTMAX: 87162306a36Sopenharmony_ci /* contact max are global to the report */ 87262306a36Sopenharmony_ci return -1; 87362306a36Sopenharmony_ci case HID_DG_TOUCH: 87462306a36Sopenharmony_ci /* Legacy devices use TIPSWITCH and not TOUCH. 87562306a36Sopenharmony_ci * Let's just ignore this field. */ 87662306a36Sopenharmony_ci return -1; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci /* let hid-input decide for the others */ 87962306a36Sopenharmony_ci return 0; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci case HID_UP_BUTTON: 88262306a36Sopenharmony_ci code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); 88362306a36Sopenharmony_ci /* 88462306a36Sopenharmony_ci * MS PTP spec says that external buttons left and right have 88562306a36Sopenharmony_ci * usages 2 and 3. 88662306a36Sopenharmony_ci */ 88762306a36Sopenharmony_ci if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && 88862306a36Sopenharmony_ci field->application == HID_DG_TOUCHPAD && 88962306a36Sopenharmony_ci (usage->hid & HID_USAGE) > 1) 89062306a36Sopenharmony_ci code--; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (field->application == HID_GD_SYSTEM_MULTIAXIS) 89362306a36Sopenharmony_ci code = BTN_0 + ((usage->hid - 1) & HID_USAGE); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci hid_map_usage(hi, usage, bit, max, EV_KEY, code); 89662306a36Sopenharmony_ci if (!*bit) 89762306a36Sopenharmony_ci return -1; 89862306a36Sopenharmony_ci input_set_capability(hi->input, EV_KEY, code); 89962306a36Sopenharmony_ci return 1; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci case 0xff000000: 90262306a36Sopenharmony_ci /* we do not want to map these: no input-oriented meaning */ 90362306a36Sopenharmony_ci return -1; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci return 0; 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic int mt_compute_slot(struct mt_device *td, struct mt_application *app, 91062306a36Sopenharmony_ci struct mt_usages *slot, 91162306a36Sopenharmony_ci struct input_dev *input) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci __s32 quirks = app->quirks; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) 91662306a36Sopenharmony_ci return *slot->contactid; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (quirks & MT_QUIRK_CYPRESS) 91962306a36Sopenharmony_ci return cypress_compute_slot(app, slot); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) 92262306a36Sopenharmony_ci return app->num_received; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) 92562306a36Sopenharmony_ci return *slot->contactid - 1; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci return input_mt_get_slot_by_key(input, *slot->contactid); 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic void mt_release_pending_palms(struct mt_device *td, 93162306a36Sopenharmony_ci struct mt_application *app, 93262306a36Sopenharmony_ci struct input_dev *input) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci int slotnum; 93562306a36Sopenharmony_ci bool need_sync = false; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) { 93862306a36Sopenharmony_ci clear_bit(slotnum, app->pending_palm_slots); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci input_mt_slot(input, slotnum); 94162306a36Sopenharmony_ci input_mt_report_slot_inactive(input); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci need_sync = true; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (need_sync) { 94762306a36Sopenharmony_ci input_mt_sync_frame(input); 94862306a36Sopenharmony_ci input_sync(input); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci/* 95362306a36Sopenharmony_ci * this function is called when a whole packet has been received and processed, 95462306a36Sopenharmony_ci * so that it can decide what to send to the input layer. 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_cistatic void mt_sync_frame(struct mt_device *td, struct mt_application *app, 95762306a36Sopenharmony_ci struct input_dev *input) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci if (app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) 96062306a36Sopenharmony_ci input_event(input, EV_KEY, BTN_LEFT, app->left_button_state); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci input_mt_sync_frame(input); 96362306a36Sopenharmony_ci input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp); 96462306a36Sopenharmony_ci input_sync(input); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci mt_release_pending_palms(td, app, input); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci app->num_received = 0; 96962306a36Sopenharmony_ci app->left_button_state = 0; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) 97262306a36Sopenharmony_ci set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 97362306a36Sopenharmony_ci else 97462306a36Sopenharmony_ci clear_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); 97562306a36Sopenharmony_ci clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cistatic int mt_compute_timestamp(struct mt_application *app, __s32 value) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci long delta = value - app->prev_scantime; 98162306a36Sopenharmony_ci unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci app->jiffies = jiffies; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (delta < 0) 98662306a36Sopenharmony_ci delta += app->scantime_logical_max; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* HID_DG_SCANTIME is expressed in 100us, we want it in us. */ 98962306a36Sopenharmony_ci delta *= 100; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (jdelta > MAX_TIMESTAMP_INTERVAL) 99262306a36Sopenharmony_ci /* No data received for a while, resync the timestamp. */ 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci else 99562306a36Sopenharmony_ci return app->timestamp + delta; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int mt_touch_event(struct hid_device *hid, struct hid_field *field, 99962306a36Sopenharmony_ci struct hid_usage *usage, __s32 value) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci /* we will handle the hidinput part later, now remains hiddev */ 100262306a36Sopenharmony_ci if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 100362306a36Sopenharmony_ci hid->hiddev_hid_event(hid, field, usage, value); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci return 1; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic int mt_process_slot(struct mt_device *td, struct input_dev *input, 100962306a36Sopenharmony_ci struct mt_application *app, 101062306a36Sopenharmony_ci struct mt_usages *slot) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci struct input_mt *mt = input->mt; 101362306a36Sopenharmony_ci struct hid_device *hdev = td->hdev; 101462306a36Sopenharmony_ci __s32 quirks = app->quirks; 101562306a36Sopenharmony_ci bool valid = true; 101662306a36Sopenharmony_ci bool confidence_state = true; 101762306a36Sopenharmony_ci bool inrange_state = false; 101862306a36Sopenharmony_ci int active; 101962306a36Sopenharmony_ci int slotnum; 102062306a36Sopenharmony_ci int tool = MT_TOOL_FINGER; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (!slot) 102362306a36Sopenharmony_ci return -EINVAL; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) && 102662306a36Sopenharmony_ci app->num_received >= app->num_expected) 102762306a36Sopenharmony_ci return -EAGAIN; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (!(quirks & MT_QUIRK_ALWAYS_VALID)) { 103062306a36Sopenharmony_ci if (quirks & MT_QUIRK_VALID_IS_INRANGE) 103162306a36Sopenharmony_ci valid = *slot->inrange_state; 103262306a36Sopenharmony_ci if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 103362306a36Sopenharmony_ci valid = *slot->tip_state; 103462306a36Sopenharmony_ci if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) 103562306a36Sopenharmony_ci valid = *slot->confidence_state; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (!valid) 103862306a36Sopenharmony_ci return 0; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci slotnum = mt_compute_slot(td, app, slot, input); 104262306a36Sopenharmony_ci if (slotnum < 0 || slotnum >= td->maxcontacts) 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) { 104662306a36Sopenharmony_ci struct input_mt_slot *i_slot = &mt->slots[slotnum]; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (input_mt_is_active(i_slot) && 104962306a36Sopenharmony_ci input_mt_is_used(mt, i_slot)) 105062306a36Sopenharmony_ci return -EAGAIN; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (quirks & MT_QUIRK_CONFIDENCE) 105462306a36Sopenharmony_ci confidence_state = *slot->confidence_state; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (quirks & MT_QUIRK_HOVERING) 105762306a36Sopenharmony_ci inrange_state = *slot->inrange_state; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci active = *slot->tip_state || inrange_state; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (app->application == HID_GD_SYSTEM_MULTIAXIS) 106262306a36Sopenharmony_ci tool = MT_TOOL_DIAL; 106362306a36Sopenharmony_ci else if (unlikely(!confidence_state)) { 106462306a36Sopenharmony_ci tool = MT_TOOL_PALM; 106562306a36Sopenharmony_ci if (!active && mt && 106662306a36Sopenharmony_ci input_mt_is_active(&mt->slots[slotnum])) { 106762306a36Sopenharmony_ci /* 106862306a36Sopenharmony_ci * The non-confidence was reported for 106962306a36Sopenharmony_ci * previously valid contact that is also no 107062306a36Sopenharmony_ci * longer valid. We can't simply report 107162306a36Sopenharmony_ci * lift-off as userspace will not be aware 107262306a36Sopenharmony_ci * of non-confidence, so we need to split 107362306a36Sopenharmony_ci * it into 2 events: active MT_TOOL_PALM 107462306a36Sopenharmony_ci * and a separate liftoff. 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ci active = true; 107762306a36Sopenharmony_ci set_bit(slotnum, app->pending_palm_slots); 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci input_mt_slot(input, slotnum); 108262306a36Sopenharmony_ci input_mt_report_slot_state(input, tool, active); 108362306a36Sopenharmony_ci if (active) { 108462306a36Sopenharmony_ci /* this finger is in proximity of the sensor */ 108562306a36Sopenharmony_ci int wide = (*slot->w > *slot->h); 108662306a36Sopenharmony_ci int major = max(*slot->w, *slot->h); 108762306a36Sopenharmony_ci int minor = min(*slot->w, *slot->h); 108862306a36Sopenharmony_ci int orientation = wide; 108962306a36Sopenharmony_ci int max_azimuth; 109062306a36Sopenharmony_ci int azimuth; 109162306a36Sopenharmony_ci int x; 109262306a36Sopenharmony_ci int y; 109362306a36Sopenharmony_ci int cx; 109462306a36Sopenharmony_ci int cy; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (slot->a != DEFAULT_ZERO) { 109762306a36Sopenharmony_ci /* 109862306a36Sopenharmony_ci * Azimuth is counter-clockwise and ranges from [0, MAX) 109962306a36Sopenharmony_ci * (a full revolution). Convert it to clockwise ranging 110062306a36Sopenharmony_ci * [-MAX/2, MAX/2]. 110162306a36Sopenharmony_ci * 110262306a36Sopenharmony_ci * Note that ABS_MT_ORIENTATION require us to report 110362306a36Sopenharmony_ci * the limit of [-MAX/4, MAX/4], but the value can go 110462306a36Sopenharmony_ci * out of range to [-MAX/2, MAX/2] to report an upside 110562306a36Sopenharmony_ci * down ellipsis. 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ci azimuth = *slot->a; 110862306a36Sopenharmony_ci max_azimuth = input_abs_get_max(input, 110962306a36Sopenharmony_ci ABS_MT_ORIENTATION); 111062306a36Sopenharmony_ci if (azimuth > max_azimuth * 2) 111162306a36Sopenharmony_ci azimuth -= max_azimuth * 4; 111262306a36Sopenharmony_ci orientation = -azimuth; 111362306a36Sopenharmony_ci if (quirks & MT_QUIRK_ORIENTATION_INVERT) 111462306a36Sopenharmony_ci orientation = -orientation; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { 111962306a36Sopenharmony_ci /* 112062306a36Sopenharmony_ci * divided by two to match visual scale of touch 112162306a36Sopenharmony_ci * for devices with this quirk 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_ci major = major >> 1; 112462306a36Sopenharmony_ci minor = minor >> 1; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci x = hdev->quirks & HID_QUIRK_X_INVERT ? 112862306a36Sopenharmony_ci input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x : 112962306a36Sopenharmony_ci *slot->x; 113062306a36Sopenharmony_ci y = hdev->quirks & HID_QUIRK_Y_INVERT ? 113162306a36Sopenharmony_ci input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->y : 113262306a36Sopenharmony_ci *slot->y; 113362306a36Sopenharmony_ci cx = hdev->quirks & HID_QUIRK_X_INVERT ? 113462306a36Sopenharmony_ci input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->cx : 113562306a36Sopenharmony_ci *slot->cx; 113662306a36Sopenharmony_ci cy = hdev->quirks & HID_QUIRK_Y_INVERT ? 113762306a36Sopenharmony_ci input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->cy : 113862306a36Sopenharmony_ci *slot->cy; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_POSITION_X, x); 114162306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); 114262306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOOL_X, cx); 114362306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOOL_Y, cy); 114462306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state); 114562306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation); 114662306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p); 114762306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 114862306a36Sopenharmony_ci input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci return 0; 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic void mt_process_mt_event(struct hid_device *hid, 115762306a36Sopenharmony_ci struct mt_application *app, 115862306a36Sopenharmony_ci struct hid_field *field, 115962306a36Sopenharmony_ci struct hid_usage *usage, 116062306a36Sopenharmony_ci __s32 value, 116162306a36Sopenharmony_ci bool first_packet) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci __s32 quirks = app->quirks; 116462306a36Sopenharmony_ci struct input_dev *input = field->hidinput->input; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (!usage->type || !(hid->claimed & HID_CLAIMED_INPUT)) 116762306a36Sopenharmony_ci return; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci if (quirks & MT_QUIRK_WIN8_PTP_BUTTONS) { 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci /* 117262306a36Sopenharmony_ci * For Win8 PTP touchpads we should only look at 117362306a36Sopenharmony_ci * non finger/touch events in the first_packet of a 117462306a36Sopenharmony_ci * (possible) multi-packet frame. 117562306a36Sopenharmony_ci */ 117662306a36Sopenharmony_ci if (!first_packet) 117762306a36Sopenharmony_ci return; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* 118062306a36Sopenharmony_ci * For Win8 PTP touchpads we map both the clickpad click 118162306a36Sopenharmony_ci * and any "external" left buttons to BTN_LEFT if a 118262306a36Sopenharmony_ci * device claims to have both we need to report 1 for 118362306a36Sopenharmony_ci * BTN_LEFT if either is pressed, so we or all values 118462306a36Sopenharmony_ci * together and report the result in mt_sync_frame(). 118562306a36Sopenharmony_ci */ 118662306a36Sopenharmony_ci if (usage->type == EV_KEY && usage->code == BTN_LEFT) { 118762306a36Sopenharmony_ci app->left_button_state |= value; 118862306a36Sopenharmony_ci return; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci input_event(input, usage->type, usage->code, value); 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic void mt_touch_report(struct hid_device *hid, 119662306a36Sopenharmony_ci struct mt_report_data *rdata) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 119962306a36Sopenharmony_ci struct hid_report *report = rdata->report; 120062306a36Sopenharmony_ci struct mt_application *app = rdata->application; 120162306a36Sopenharmony_ci struct hid_field *field; 120262306a36Sopenharmony_ci struct input_dev *input; 120362306a36Sopenharmony_ci struct mt_usages *slot; 120462306a36Sopenharmony_ci bool first_packet; 120562306a36Sopenharmony_ci unsigned count; 120662306a36Sopenharmony_ci int r, n; 120762306a36Sopenharmony_ci int scantime = 0; 120862306a36Sopenharmony_ci int contact_count = -1; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* sticky fingers release in progress, abort */ 121162306a36Sopenharmony_ci if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 121262306a36Sopenharmony_ci return; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci scantime = *app->scantime; 121562306a36Sopenharmony_ci app->timestamp = mt_compute_timestamp(app, scantime); 121662306a36Sopenharmony_ci if (app->raw_cc != DEFAULT_ZERO) 121762306a36Sopenharmony_ci contact_count = *app->raw_cc; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* 122062306a36Sopenharmony_ci * Includes multi-packet support where subsequent 122162306a36Sopenharmony_ci * packets are sent with zero contactcount. 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_ci if (contact_count >= 0) { 122462306a36Sopenharmony_ci /* 122562306a36Sopenharmony_ci * For Win8 PTPs the first packet (td->num_received == 0) may 122662306a36Sopenharmony_ci * have a contactcount of 0 if there only is a button event. 122762306a36Sopenharmony_ci * We double check that this is not a continuation packet 122862306a36Sopenharmony_ci * of a possible multi-packet frame be checking that the 122962306a36Sopenharmony_ci * timestamp has changed. 123062306a36Sopenharmony_ci */ 123162306a36Sopenharmony_ci if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && 123262306a36Sopenharmony_ci app->num_received == 0 && 123362306a36Sopenharmony_ci app->prev_scantime != scantime) 123462306a36Sopenharmony_ci app->num_expected = contact_count; 123562306a36Sopenharmony_ci /* A non 0 contact count always indicates a first packet */ 123662306a36Sopenharmony_ci else if (contact_count) 123762306a36Sopenharmony_ci app->num_expected = contact_count; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci app->prev_scantime = scantime; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci first_packet = app->num_received == 0; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci input = report->field[0]->hidinput->input; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci list_for_each_entry(slot, &app->mt_usages, list) { 124662306a36Sopenharmony_ci if (!mt_process_slot(td, input, app, slot)) 124762306a36Sopenharmony_ci app->num_received++; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci for (r = 0; r < report->maxfield; r++) { 125162306a36Sopenharmony_ci field = report->field[r]; 125262306a36Sopenharmony_ci count = field->report_count; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) 125562306a36Sopenharmony_ci continue; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci for (n = 0; n < count; n++) 125862306a36Sopenharmony_ci mt_process_mt_event(hid, app, field, 125962306a36Sopenharmony_ci &field->usage[n], field->value[n], 126062306a36Sopenharmony_ci first_packet); 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (app->num_received >= app->num_expected) 126462306a36Sopenharmony_ci mt_sync_frame(td, app, input); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* 126762306a36Sopenharmony_ci * Windows 8 specs says 2 things: 126862306a36Sopenharmony_ci * - once a contact has been reported, it has to be reported in each 126962306a36Sopenharmony_ci * subsequent report 127062306a36Sopenharmony_ci * - the report rate when fingers are present has to be at least 127162306a36Sopenharmony_ci * the refresh rate of the screen, 60 or 120 Hz 127262306a36Sopenharmony_ci * 127362306a36Sopenharmony_ci * I interprete this that the specification forces a report rate of 127462306a36Sopenharmony_ci * at least 60 Hz for a touchscreen to be certified. 127562306a36Sopenharmony_ci * Which means that if we do not get a report whithin 16 ms, either 127662306a36Sopenharmony_ci * something wrong happens, either the touchscreen forgets to send 127762306a36Sopenharmony_ci * a release. Taking a reasonable margin allows to remove issues 127862306a36Sopenharmony_ci * with USB communication or the load of the machine. 127962306a36Sopenharmony_ci * 128062306a36Sopenharmony_ci * Given that Win 8 devices are forced to send a release, this will 128162306a36Sopenharmony_ci * only affect laggish machines and the ones that have a firmware 128262306a36Sopenharmony_ci * defect. 128362306a36Sopenharmony_ci */ 128462306a36Sopenharmony_ci if (app->quirks & MT_QUIRK_STICKY_FINGERS) { 128562306a36Sopenharmony_ci if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 128662306a36Sopenharmony_ci mod_timer(&td->release_timer, 128762306a36Sopenharmony_ci jiffies + msecs_to_jiffies(100)); 128862306a36Sopenharmony_ci else 128962306a36Sopenharmony_ci del_timer(&td->release_timer); 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic int mt_touch_input_configured(struct hid_device *hdev, 129662306a36Sopenharmony_ci struct hid_input *hi, 129762306a36Sopenharmony_ci struct mt_application *app) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 130062306a36Sopenharmony_ci struct mt_class *cls = &td->mtclass; 130162306a36Sopenharmony_ci struct input_dev *input = hi->input; 130262306a36Sopenharmony_ci int ret; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (!td->maxcontacts) 130562306a36Sopenharmony_ci td->maxcontacts = MT_DEFAULT_MAXCONTACT; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci mt_post_parse(td, app); 130862306a36Sopenharmony_ci if (td->serial_maybe) 130962306a36Sopenharmony_ci mt_post_parse_default_settings(td, app); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (cls->is_indirect) 131262306a36Sopenharmony_ci app->mt_flags |= INPUT_MT_POINTER; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 131562306a36Sopenharmony_ci app->mt_flags |= INPUT_MT_DROP_UNUSED; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci /* check for clickpads */ 131862306a36Sopenharmony_ci if ((app->mt_flags & INPUT_MT_POINTER) && 131962306a36Sopenharmony_ci (app->buttons_count == 1)) 132062306a36Sopenharmony_ci td->is_buttonpad = true; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (td->is_buttonpad) 132362306a36Sopenharmony_ci __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci app->pending_palm_slots = devm_kcalloc(&hi->input->dev, 132662306a36Sopenharmony_ci BITS_TO_LONGS(td->maxcontacts), 132762306a36Sopenharmony_ci sizeof(long), 132862306a36Sopenharmony_ci GFP_KERNEL); 132962306a36Sopenharmony_ci if (!app->pending_palm_slots) 133062306a36Sopenharmony_ci return -ENOMEM; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags); 133362306a36Sopenharmony_ci if (ret) 133462306a36Sopenharmony_ci return ret; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci app->mt_flags = 0; 133762306a36Sopenharmony_ci return 0; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci#define mt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \ 134162306a36Sopenharmony_ci max, EV_KEY, (c)) 134262306a36Sopenharmony_cistatic int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 134362306a36Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 134462306a36Sopenharmony_ci unsigned long **bit, int *max) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 134762306a36Sopenharmony_ci struct mt_application *application; 134862306a36Sopenharmony_ci struct mt_report_data *rdata; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci rdata = mt_find_report_data(td, field->report); 135162306a36Sopenharmony_ci if (!rdata) { 135262306a36Sopenharmony_ci hid_err(hdev, "failed to allocate data for report\n"); 135362306a36Sopenharmony_ci return 0; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci application = rdata->application; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci /* 135962306a36Sopenharmony_ci * If mtclass.export_all_inputs is not set, only map fields from 136062306a36Sopenharmony_ci * TouchScreen or TouchPad collections. We need to ignore fields 136162306a36Sopenharmony_ci * that belong to other collections such as Mouse that might have 136262306a36Sopenharmony_ci * the same GenericDesktop usages. 136362306a36Sopenharmony_ci */ 136462306a36Sopenharmony_ci if (!td->mtclass.export_all_inputs && 136562306a36Sopenharmony_ci field->application != HID_DG_TOUCHSCREEN && 136662306a36Sopenharmony_ci field->application != HID_DG_PEN && 136762306a36Sopenharmony_ci field->application != HID_DG_TOUCHPAD && 136862306a36Sopenharmony_ci field->application != HID_GD_KEYBOARD && 136962306a36Sopenharmony_ci field->application != HID_GD_SYSTEM_CONTROL && 137062306a36Sopenharmony_ci field->application != HID_CP_CONSUMER_CONTROL && 137162306a36Sopenharmony_ci field->application != HID_GD_WIRELESS_RADIO_CTLS && 137262306a36Sopenharmony_ci field->application != HID_GD_SYSTEM_MULTIAXIS && 137362306a36Sopenharmony_ci !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 137462306a36Sopenharmony_ci application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) 137562306a36Sopenharmony_ci return -1; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci /* 137862306a36Sopenharmony_ci * Some Asus keyboard+touchpad devices have the hotkeys defined in the 137962306a36Sopenharmony_ci * touchpad report descriptor. We need to treat these as an array to 138062306a36Sopenharmony_ci * map usages to input keys. 138162306a36Sopenharmony_ci */ 138262306a36Sopenharmony_ci if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && 138362306a36Sopenharmony_ci application->quirks & MT_QUIRK_ASUS_CUSTOM_UP && 138462306a36Sopenharmony_ci (usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) { 138562306a36Sopenharmony_ci set_bit(EV_REP, hi->input->evbit); 138662306a36Sopenharmony_ci if (field->flags & HID_MAIN_ITEM_VARIABLE) 138762306a36Sopenharmony_ci field->flags &= ~HID_MAIN_ITEM_VARIABLE; 138862306a36Sopenharmony_ci switch (usage->hid & HID_USAGE) { 138962306a36Sopenharmony_ci case 0x10: mt_map_key_clear(KEY_BRIGHTNESSDOWN); break; 139062306a36Sopenharmony_ci case 0x20: mt_map_key_clear(KEY_BRIGHTNESSUP); break; 139162306a36Sopenharmony_ci case 0x35: mt_map_key_clear(KEY_DISPLAY_OFF); break; 139262306a36Sopenharmony_ci case 0x6b: mt_map_key_clear(KEY_F21); break; 139362306a36Sopenharmony_ci case 0x6c: mt_map_key_clear(KEY_SLEEP); break; 139462306a36Sopenharmony_ci default: 139562306a36Sopenharmony_ci return -1; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci return 1; 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (rdata->is_mt_collection) 140162306a36Sopenharmony_ci return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, 140262306a36Sopenharmony_ci application); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci /* 140562306a36Sopenharmony_ci * some egalax touchscreens have "application == DG_TOUCHSCREEN" 140662306a36Sopenharmony_ci * for the stylus. Overwrite the hid_input application 140762306a36Sopenharmony_ci */ 140862306a36Sopenharmony_ci if (field->physical == HID_DG_STYLUS) 140962306a36Sopenharmony_ci hi->application = HID_DG_STYLUS; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* let hid-core decide for the others */ 141262306a36Sopenharmony_ci return 0; 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, 141662306a36Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 141762306a36Sopenharmony_ci unsigned long **bit, int *max) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 142062306a36Sopenharmony_ci struct mt_report_data *rdata; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci rdata = mt_find_report_data(td, field->report); 142362306a36Sopenharmony_ci if (rdata && rdata->is_mt_collection) { 142462306a36Sopenharmony_ci /* We own these mappings, tell hid-input to ignore them */ 142562306a36Sopenharmony_ci return -1; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* let hid-core decide for the others */ 142962306a36Sopenharmony_ci return 0; 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cistatic int mt_event(struct hid_device *hid, struct hid_field *field, 143362306a36Sopenharmony_ci struct hid_usage *usage, __s32 value) 143462306a36Sopenharmony_ci{ 143562306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 143662306a36Sopenharmony_ci struct mt_report_data *rdata; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci rdata = mt_find_report_data(td, field->report); 143962306a36Sopenharmony_ci if (rdata && rdata->is_mt_collection) 144062306a36Sopenharmony_ci return mt_touch_event(hid, field, usage, value); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci return 0; 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic void mt_report(struct hid_device *hid, struct hid_report *report) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 144862306a36Sopenharmony_ci struct hid_field *field = report->field[0]; 144962306a36Sopenharmony_ci struct mt_report_data *rdata; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (!(hid->claimed & HID_CLAIMED_INPUT)) 145262306a36Sopenharmony_ci return; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci rdata = mt_find_report_data(td, report); 145562306a36Sopenharmony_ci if (rdata && rdata->is_mt_collection) 145662306a36Sopenharmony_ci return mt_touch_report(hid, rdata); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci if (field && field->hidinput && field->hidinput->input) 145962306a36Sopenharmony_ci input_sync(field->hidinput->input); 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic bool mt_need_to_apply_feature(struct hid_device *hdev, 146362306a36Sopenharmony_ci struct hid_field *field, 146462306a36Sopenharmony_ci struct hid_usage *usage, 146562306a36Sopenharmony_ci enum latency_mode latency, 146662306a36Sopenharmony_ci bool surface_switch, 146762306a36Sopenharmony_ci bool button_switch, 146862306a36Sopenharmony_ci bool *inputmode_found) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 147162306a36Sopenharmony_ci struct mt_class *cls = &td->mtclass; 147262306a36Sopenharmony_ci struct hid_report *report = field->report; 147362306a36Sopenharmony_ci unsigned int index = usage->usage_index; 147462306a36Sopenharmony_ci char *buf; 147562306a36Sopenharmony_ci u32 report_len; 147662306a36Sopenharmony_ci int max; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci switch (usage->hid) { 147962306a36Sopenharmony_ci case HID_DG_INPUTMODE: 148062306a36Sopenharmony_ci /* 148162306a36Sopenharmony_ci * Some elan panels wrongly declare 2 input mode features, 148262306a36Sopenharmony_ci * and silently ignore when we set the value in the second 148362306a36Sopenharmony_ci * field. Skip the second feature and hope for the best. 148462306a36Sopenharmony_ci */ 148562306a36Sopenharmony_ci if (*inputmode_found) 148662306a36Sopenharmony_ci return false; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) { 148962306a36Sopenharmony_ci report_len = hid_report_len(report); 149062306a36Sopenharmony_ci buf = hid_alloc_report_buf(report, GFP_KERNEL); 149162306a36Sopenharmony_ci if (!buf) { 149262306a36Sopenharmony_ci hid_err(hdev, 149362306a36Sopenharmony_ci "failed to allocate buffer for report\n"); 149462306a36Sopenharmony_ci return false; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci hid_hw_raw_request(hdev, report->id, buf, report_len, 149762306a36Sopenharmony_ci HID_FEATURE_REPORT, 149862306a36Sopenharmony_ci HID_REQ_GET_REPORT); 149962306a36Sopenharmony_ci kfree(buf); 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci field->value[index] = td->inputmode_value; 150362306a36Sopenharmony_ci *inputmode_found = true; 150462306a36Sopenharmony_ci return true; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci case HID_DG_CONTACTMAX: 150762306a36Sopenharmony_ci if (cls->maxcontacts) { 150862306a36Sopenharmony_ci max = min_t(int, field->logical_maximum, 150962306a36Sopenharmony_ci cls->maxcontacts); 151062306a36Sopenharmony_ci if (field->value[index] != max) { 151162306a36Sopenharmony_ci field->value[index] = max; 151262306a36Sopenharmony_ci return true; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci break; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci case HID_DG_LATENCYMODE: 151862306a36Sopenharmony_ci field->value[index] = latency; 151962306a36Sopenharmony_ci return true; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci case HID_DG_SURFACESWITCH: 152262306a36Sopenharmony_ci field->value[index] = surface_switch; 152362306a36Sopenharmony_ci return true; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci case HID_DG_BUTTONSWITCH: 152662306a36Sopenharmony_ci field->value[index] = button_switch; 152762306a36Sopenharmony_ci return true; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci return false; /* no need to update the report */ 153162306a36Sopenharmony_ci} 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_cistatic void mt_set_modes(struct hid_device *hdev, enum latency_mode latency, 153462306a36Sopenharmony_ci bool surface_switch, bool button_switch) 153562306a36Sopenharmony_ci{ 153662306a36Sopenharmony_ci struct hid_report_enum *rep_enum; 153762306a36Sopenharmony_ci struct hid_report *rep; 153862306a36Sopenharmony_ci struct hid_usage *usage; 153962306a36Sopenharmony_ci int i, j; 154062306a36Sopenharmony_ci bool update_report; 154162306a36Sopenharmony_ci bool inputmode_found = false; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; 154462306a36Sopenharmony_ci list_for_each_entry(rep, &rep_enum->report_list, list) { 154562306a36Sopenharmony_ci update_report = false; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci for (i = 0; i < rep->maxfield; i++) { 154862306a36Sopenharmony_ci /* Ignore if report count is out of bounds. */ 154962306a36Sopenharmony_ci if (rep->field[i]->report_count < 1) 155062306a36Sopenharmony_ci continue; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci for (j = 0; j < rep->field[i]->maxusage; j++) { 155362306a36Sopenharmony_ci usage = &rep->field[i]->usage[j]; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (mt_need_to_apply_feature(hdev, 155662306a36Sopenharmony_ci rep->field[i], 155762306a36Sopenharmony_ci usage, 155862306a36Sopenharmony_ci latency, 155962306a36Sopenharmony_ci surface_switch, 156062306a36Sopenharmony_ci button_switch, 156162306a36Sopenharmony_ci &inputmode_found)) 156262306a36Sopenharmony_ci update_report = true; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (update_report) 156762306a36Sopenharmony_ci hid_hw_request(hdev, rep, HID_REQ_SET_REPORT); 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic void mt_post_parse_default_settings(struct mt_device *td, 157262306a36Sopenharmony_ci struct mt_application *app) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci __s32 quirks = app->quirks; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci /* unknown serial device needs special quirks */ 157762306a36Sopenharmony_ci if (list_is_singular(&app->mt_usages)) { 157862306a36Sopenharmony_ci quirks |= MT_QUIRK_ALWAYS_VALID; 157962306a36Sopenharmony_ci quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; 158062306a36Sopenharmony_ci quirks &= ~MT_QUIRK_VALID_IS_INRANGE; 158162306a36Sopenharmony_ci quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; 158262306a36Sopenharmony_ci quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci app->quirks = quirks; 158662306a36Sopenharmony_ci} 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_cistatic void mt_post_parse(struct mt_device *td, struct mt_application *app) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci if (!app->have_contact_count) 159162306a36Sopenharmony_ci app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 159762306a36Sopenharmony_ci const char *suffix = NULL; 159862306a36Sopenharmony_ci struct mt_report_data *rdata; 159962306a36Sopenharmony_ci struct mt_application *mt_application = NULL; 160062306a36Sopenharmony_ci struct hid_report *report; 160162306a36Sopenharmony_ci int ret; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci list_for_each_entry(report, &hi->reports, hidinput_list) { 160462306a36Sopenharmony_ci rdata = mt_find_report_data(td, report); 160562306a36Sopenharmony_ci if (!rdata) { 160662306a36Sopenharmony_ci hid_err(hdev, "failed to allocate data for report\n"); 160762306a36Sopenharmony_ci return -ENOMEM; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci mt_application = rdata->application; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (rdata->is_mt_collection) { 161362306a36Sopenharmony_ci ret = mt_touch_input_configured(hdev, hi, 161462306a36Sopenharmony_ci mt_application); 161562306a36Sopenharmony_ci if (ret) 161662306a36Sopenharmony_ci return ret; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci switch (hi->application) { 162162306a36Sopenharmony_ci case HID_GD_KEYBOARD: 162262306a36Sopenharmony_ci case HID_GD_KEYPAD: 162362306a36Sopenharmony_ci case HID_GD_MOUSE: 162462306a36Sopenharmony_ci case HID_DG_TOUCHPAD: 162562306a36Sopenharmony_ci case HID_GD_SYSTEM_CONTROL: 162662306a36Sopenharmony_ci case HID_CP_CONSUMER_CONTROL: 162762306a36Sopenharmony_ci case HID_GD_WIRELESS_RADIO_CTLS: 162862306a36Sopenharmony_ci case HID_GD_SYSTEM_MULTIAXIS: 162962306a36Sopenharmony_ci /* already handled by hid core */ 163062306a36Sopenharmony_ci break; 163162306a36Sopenharmony_ci case HID_DG_TOUCHSCREEN: 163262306a36Sopenharmony_ci /* we do not set suffix = "Touchscreen" */ 163362306a36Sopenharmony_ci hi->input->name = hdev->name; 163462306a36Sopenharmony_ci break; 163562306a36Sopenharmony_ci case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: 163662306a36Sopenharmony_ci suffix = "Custom Media Keys"; 163762306a36Sopenharmony_ci break; 163862306a36Sopenharmony_ci case HID_DG_STYLUS: 163962306a36Sopenharmony_ci /* force BTN_STYLUS to allow tablet matching in udev */ 164062306a36Sopenharmony_ci __set_bit(BTN_STYLUS, hi->input->keybit); 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci default: 164362306a36Sopenharmony_ci suffix = "UNKNOWN"; 164462306a36Sopenharmony_ci break; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci if (suffix) 164862306a36Sopenharmony_ci hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, 164962306a36Sopenharmony_ci "%s %s", hdev->name, suffix); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci return 0; 165262306a36Sopenharmony_ci} 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_cistatic void mt_fix_const_field(struct hid_field *field, unsigned int usage) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci if (field->usage[0].hid != usage || 165762306a36Sopenharmony_ci !(field->flags & HID_MAIN_ITEM_CONSTANT)) 165862306a36Sopenharmony_ci return; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci field->flags &= ~HID_MAIN_ITEM_CONSTANT; 166162306a36Sopenharmony_ci field->flags |= HID_MAIN_ITEM_VARIABLE; 166262306a36Sopenharmony_ci} 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_cistatic void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage) 166562306a36Sopenharmony_ci{ 166662306a36Sopenharmony_ci struct hid_report *report; 166762306a36Sopenharmony_ci int i; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci list_for_each_entry(report, 167062306a36Sopenharmony_ci &hdev->report_enum[HID_INPUT_REPORT].report_list, 167162306a36Sopenharmony_ci list) { 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (!report->maxfield) 167462306a36Sopenharmony_ci continue; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci for (i = 0; i < report->maxfield; i++) 167762306a36Sopenharmony_ci if (report->field[i]->maxusage >= 1) 167862306a36Sopenharmony_ci mt_fix_const_field(report->field[i], usage); 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_cistatic void mt_release_contacts(struct hid_device *hid) 168362306a36Sopenharmony_ci{ 168462306a36Sopenharmony_ci struct hid_input *hidinput; 168562306a36Sopenharmony_ci struct mt_application *application; 168662306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hid); 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci list_for_each_entry(hidinput, &hid->inputs, list) { 168962306a36Sopenharmony_ci struct input_dev *input_dev = hidinput->input; 169062306a36Sopenharmony_ci struct input_mt *mt = input_dev->mt; 169162306a36Sopenharmony_ci int i; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci if (mt) { 169462306a36Sopenharmony_ci for (i = 0; i < mt->num_slots; i++) { 169562306a36Sopenharmony_ci input_mt_slot(input_dev, i); 169662306a36Sopenharmony_ci input_mt_report_slot_inactive(input_dev); 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci input_mt_sync_frame(input_dev); 169962306a36Sopenharmony_ci input_sync(input_dev); 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci list_for_each_entry(application, &td->applications, list) { 170462306a36Sopenharmony_ci application->num_received = 0; 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cistatic void mt_expired_timeout(struct timer_list *t) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci struct mt_device *td = from_timer(td, t, release_timer); 171162306a36Sopenharmony_ci struct hid_device *hdev = td->hdev; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci /* 171462306a36Sopenharmony_ci * An input report came in just before we release the sticky fingers, 171562306a36Sopenharmony_ci * it will take care of the sticky fingers. 171662306a36Sopenharmony_ci */ 171762306a36Sopenharmony_ci if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) 171862306a36Sopenharmony_ci return; 171962306a36Sopenharmony_ci if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) 172062306a36Sopenharmony_ci mt_release_contacts(hdev); 172162306a36Sopenharmony_ci clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); 172262306a36Sopenharmony_ci} 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_cistatic int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci int ret, i; 172762306a36Sopenharmony_ci struct mt_device *td; 172862306a36Sopenharmony_ci const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci for (i = 0; mt_classes[i].name ; i++) { 173162306a36Sopenharmony_ci if (id->driver_data == mt_classes[i].name) { 173262306a36Sopenharmony_ci mtclass = &(mt_classes[i]); 173362306a36Sopenharmony_ci break; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); 173862306a36Sopenharmony_ci if (!td) { 173962306a36Sopenharmony_ci dev_err(&hdev->dev, "cannot allocate multitouch data\n"); 174062306a36Sopenharmony_ci return -ENOMEM; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci td->hdev = hdev; 174362306a36Sopenharmony_ci td->mtclass = *mtclass; 174462306a36Sopenharmony_ci td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; 174562306a36Sopenharmony_ci hid_set_drvdata(hdev, td); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci INIT_LIST_HEAD(&td->applications); 174862306a36Sopenharmony_ci INIT_LIST_HEAD(&td->reports); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) 175162306a36Sopenharmony_ci td->serial_maybe = true; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci /* Orientation is inverted if the X or Y axes are 175562306a36Sopenharmony_ci * flipped, but normalized if both are inverted. 175662306a36Sopenharmony_ci */ 175762306a36Sopenharmony_ci if (hdev->quirks & (HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT) && 175862306a36Sopenharmony_ci !((hdev->quirks & HID_QUIRK_X_INVERT) 175962306a36Sopenharmony_ci && (hdev->quirks & HID_QUIRK_Y_INVERT))) 176062306a36Sopenharmony_ci td->mtclass.quirks = MT_QUIRK_ORIENTATION_INVERT; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* This allows the driver to correctly support devices 176362306a36Sopenharmony_ci * that emit events over several HID messages. 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_ci hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci /* 176862306a36Sopenharmony_ci * This allows the driver to handle different input sensors 176962306a36Sopenharmony_ci * that emits events through different applications on the same HID 177062306a36Sopenharmony_ci * device. 177162306a36Sopenharmony_ci */ 177262306a36Sopenharmony_ci hdev->quirks |= HID_QUIRK_INPUT_PER_APP; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci if (id->group != HID_GROUP_MULTITOUCH_WIN_8) 177562306a36Sopenharmony_ci hdev->quirks |= HID_QUIRK_MULTI_INPUT; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci if (mtclass->quirks & MT_QUIRK_FORCE_MULTI_INPUT) { 177862306a36Sopenharmony_ci hdev->quirks &= ~HID_QUIRK_INPUT_PER_APP; 177962306a36Sopenharmony_ci hdev->quirks |= HID_QUIRK_MULTI_INPUT; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci timer_setup(&td->release_timer, mt_expired_timeout, 0); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci ret = hid_parse(hdev); 178562306a36Sopenharmony_ci if (ret != 0) 178662306a36Sopenharmony_ci return ret; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) 178962306a36Sopenharmony_ci mt_fix_const_fields(hdev, HID_DG_CONTACTID); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 179262306a36Sopenharmony_ci if (ret) 179362306a36Sopenharmony_ci return ret; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); 179662306a36Sopenharmony_ci if (ret) 179762306a36Sopenharmony_ci dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n", 179862306a36Sopenharmony_ci hdev->name); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci return 0; 180362306a36Sopenharmony_ci} 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci#ifdef CONFIG_PM 180662306a36Sopenharmony_cistatic int mt_suspend(struct hid_device *hdev, pm_message_t state) 180762306a36Sopenharmony_ci{ 180862306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci /* High latency is desirable for power savings during S3/S0ix */ 181162306a36Sopenharmony_ci if ((td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP) || 181262306a36Sopenharmony_ci !hid_hw_may_wakeup(hdev)) 181362306a36Sopenharmony_ci mt_set_modes(hdev, HID_LATENCY_HIGH, false, false); 181462306a36Sopenharmony_ci else 181562306a36Sopenharmony_ci mt_set_modes(hdev, HID_LATENCY_HIGH, true, true); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci return 0; 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic int mt_reset_resume(struct hid_device *hdev) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci mt_release_contacts(hdev); 182362306a36Sopenharmony_ci mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 182462306a36Sopenharmony_ci return 0; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic int mt_resume(struct hid_device *hdev) 182862306a36Sopenharmony_ci{ 182962306a36Sopenharmony_ci /* Some Elan legacy devices require SET_IDLE to be set on resume. 183062306a36Sopenharmony_ci * It should be safe to send it to other devices too. 183162306a36Sopenharmony_ci * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci return 0; 183862306a36Sopenharmony_ci} 183962306a36Sopenharmony_ci#endif 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistatic void mt_remove(struct hid_device *hdev) 184262306a36Sopenharmony_ci{ 184362306a36Sopenharmony_ci struct mt_device *td = hid_get_drvdata(hdev); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci del_timer_sync(&td->release_timer); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); 184862306a36Sopenharmony_ci hid_hw_stop(hdev); 184962306a36Sopenharmony_ci} 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci/* 185262306a36Sopenharmony_ci * This list contains only: 185362306a36Sopenharmony_ci * - VID/PID of products not working with the default multitouch handling 185462306a36Sopenharmony_ci * - 2 generic rules. 185562306a36Sopenharmony_ci * So there is no point in adding here any device with MT_CLS_DEFAULT. 185662306a36Sopenharmony_ci */ 185762306a36Sopenharmony_cistatic const struct hid_device_id mt_devices[] = { 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci /* 3M panels */ 186062306a36Sopenharmony_ci { .driver_data = MT_CLS_3M, 186162306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_3M, 186262306a36Sopenharmony_ci USB_DEVICE_ID_3M1968) }, 186362306a36Sopenharmony_ci { .driver_data = MT_CLS_3M, 186462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_3M, 186562306a36Sopenharmony_ci USB_DEVICE_ID_3M2256) }, 186662306a36Sopenharmony_ci { .driver_data = MT_CLS_3M, 186762306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_3M, 186862306a36Sopenharmony_ci USB_DEVICE_ID_3M3266) }, 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci /* Anton devices */ 187162306a36Sopenharmony_ci { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, 187262306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ANTON, 187362306a36Sopenharmony_ci USB_DEVICE_ID_ANTON_TOUCH_PAD) }, 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci /* Asus T101HA */ 187662306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_DISABLE_WAKEUP, 187762306a36Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 187862306a36Sopenharmony_ci USB_VENDOR_ID_ASUSTEK, 187962306a36Sopenharmony_ci USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD) }, 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci /* Asus T304UA */ 188262306a36Sopenharmony_ci { .driver_data = MT_CLS_ASUS, 188362306a36Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 188462306a36Sopenharmony_ci USB_VENDOR_ID_ASUSTEK, 188562306a36Sopenharmony_ci USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD) }, 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* Atmel panels */ 188862306a36Sopenharmony_ci { .driver_data = MT_CLS_SERIAL, 188962306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 189062306a36Sopenharmony_ci USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci /* Baanto multitouch devices */ 189362306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 189462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, 189562306a36Sopenharmony_ci USB_DEVICE_ID_BAANTO_MT_190W2) }, 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci /* Cando panels */ 189862306a36Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 189962306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 190062306a36Sopenharmony_ci USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, 190162306a36Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 190262306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 190362306a36Sopenharmony_ci USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci /* Chunghwa Telecom touch panels */ 190662306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 190762306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, 190862306a36Sopenharmony_ci USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci /* CJTouch panels */ 191162306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 191262306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 191362306a36Sopenharmony_ci USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) }, 191462306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 191562306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, 191662306a36Sopenharmony_ci USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) }, 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci /* CVTouch panels */ 191962306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 192062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, 192162306a36Sopenharmony_ci USB_DEVICE_ID_CVTOUCH_SCREEN) }, 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* eGalax devices (SAW) */ 192462306a36Sopenharmony_ci { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, 192562306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 192662306a36Sopenharmony_ci USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER) }, 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci /* eGalax devices (resistive) */ 192962306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 193062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 193162306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, 193262306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 193362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 193462306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* eGalax devices (capacitive) */ 193762306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 193862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 193962306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) }, 194062306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 194162306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 194262306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, 194362306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 194462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 194562306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, 194662306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 194762306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 194862306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) }, 194962306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 195062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 195162306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) }, 195262306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 195362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 195462306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) }, 195562306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 195662306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 195762306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, 195862306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 195962306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 196062306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, 196162306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 196262306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 196362306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) }, 196462306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 196562306a36Sopenharmony_ci HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 196662306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) }, 196762306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 196862306a36Sopenharmony_ci HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 196962306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) }, 197062306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 197162306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 197262306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, 197362306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 197462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 197562306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, 197662306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 197762306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 197862306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, 197962306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 198062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 198162306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) }, 198262306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX_SERIAL, 198362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 198462306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, 198562306a36Sopenharmony_ci { .driver_data = MT_CLS_EGALAX, 198662306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 198762306a36Sopenharmony_ci USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) }, 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci /* Elan devices */ 199062306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 199162306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 199262306a36Sopenharmony_ci USB_VENDOR_ID_ELAN, 0x313a) }, 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 199562306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 199662306a36Sopenharmony_ci USB_VENDOR_ID_ELAN, 0x3148) }, 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci /* Elitegroup panel */ 199962306a36Sopenharmony_ci { .driver_data = MT_CLS_SERIAL, 200062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP, 200162306a36Sopenharmony_ci USB_DEVICE_ID_ELITEGROUP_05D8) }, 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci /* Flatfrog Panels */ 200462306a36Sopenharmony_ci { .driver_data = MT_CLS_FLATFROG, 200562306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, 200662306a36Sopenharmony_ci USB_DEVICE_ID_MULTITOUCH_3200) }, 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci /* FocalTech Panels */ 200962306a36Sopenharmony_ci { .driver_data = MT_CLS_SERIAL, 201062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL, 201162306a36Sopenharmony_ci USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) }, 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci /* GeneralTouch panel */ 201462306a36Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 201562306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 201662306a36Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, 201762306a36Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 201862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 201962306a36Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, 202062306a36Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 202162306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 202262306a36Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101) }, 202362306a36Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 202462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 202562306a36Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102) }, 202662306a36Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 202762306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 202862306a36Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106) }, 202962306a36Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 203062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 203162306a36Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A) }, 203262306a36Sopenharmony_ci { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 203362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 203462306a36Sopenharmony_ci USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100) }, 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci /* Gametel game controller */ 203762306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 203862306a36Sopenharmony_ci MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL, 203962306a36Sopenharmony_ci USB_DEVICE_ID_GAMETEL_MT_MODE) }, 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci /* GoodTouch panels */ 204262306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 204362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, 204462306a36Sopenharmony_ci USB_DEVICE_ID_GOODTOUCH_000f) }, 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* Hanvon panels */ 204762306a36Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 204862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, 204962306a36Sopenharmony_ci USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci /* HONOR GLO-GXXX panel */ 205262306a36Sopenharmony_ci { .driver_data = MT_CLS_VTL, 205362306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 205462306a36Sopenharmony_ci 0x347d, 0x7853) }, 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci /* Ilitek dual touch panel */ 205762306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 205862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, 205962306a36Sopenharmony_ci USB_DEVICE_ID_ILITEK_MULTITOUCH) }, 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci /* LG Melfas panel */ 206262306a36Sopenharmony_ci { .driver_data = MT_CLS_LG, 206362306a36Sopenharmony_ci HID_USB_DEVICE(USB_VENDOR_ID_LG, 206462306a36Sopenharmony_ci USB_DEVICE_ID_LG_MELFAS_MT) }, 206562306a36Sopenharmony_ci { .driver_data = MT_CLS_LG, 206662306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_GENERIC, 206762306a36Sopenharmony_ci USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_7010) }, 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci /* Lenovo X1 TAB Gen 2 */ 207062306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 207162306a36Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 207262306a36Sopenharmony_ci USB_VENDOR_ID_LENOVO, 207362306a36Sopenharmony_ci USB_DEVICE_ID_LENOVO_X1_TAB) }, 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci /* Lenovo X1 TAB Gen 3 */ 207662306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 207762306a36Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 207862306a36Sopenharmony_ci USB_VENDOR_ID_LENOVO, 207962306a36Sopenharmony_ci USB_DEVICE_ID_LENOVO_X1_TAB3) }, 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci /* Lenovo X12 TAB Gen 1 */ 208262306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, 208362306a36Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 208462306a36Sopenharmony_ci USB_VENDOR_ID_LENOVO, 208562306a36Sopenharmony_ci USB_DEVICE_ID_LENOVO_X12_TAB) }, 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci /* MosArt panels */ 208862306a36Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 208962306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 209062306a36Sopenharmony_ci USB_DEVICE_ID_ASUS_T91MT)}, 209162306a36Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 209262306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 209362306a36Sopenharmony_ci USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 209462306a36Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 209562306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, 209662306a36Sopenharmony_ci USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci /* Novatek Panel */ 209962306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 210062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, 210162306a36Sopenharmony_ci USB_DEVICE_ID_NOVATEK_PCT) }, 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci /* Ntrig Panel */ 210462306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 210562306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 210662306a36Sopenharmony_ci USB_VENDOR_ID_NTRIG, 0x1b05) }, 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci /* Panasonic panels */ 210962306a36Sopenharmony_ci { .driver_data = MT_CLS_PANASONIC, 211062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 211162306a36Sopenharmony_ci USB_DEVICE_ID_PANABOARD_UBT780) }, 211262306a36Sopenharmony_ci { .driver_data = MT_CLS_PANASONIC, 211362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 211462306a36Sopenharmony_ci USB_DEVICE_ID_PANABOARD_UBT880) }, 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* PixArt optical touch screen */ 211762306a36Sopenharmony_ci { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 211862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 211962306a36Sopenharmony_ci USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) }, 212062306a36Sopenharmony_ci { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 212162306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 212262306a36Sopenharmony_ci USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) }, 212362306a36Sopenharmony_ci { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 212462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 212562306a36Sopenharmony_ci USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) }, 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci /* PixCir-based panels */ 212862306a36Sopenharmony_ci { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 212962306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 213062306a36Sopenharmony_ci USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci /* Quanta-based panels */ 213362306a36Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 213462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 213562306a36Sopenharmony_ci USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci /* Razer touchpads */ 213862306a36Sopenharmony_ci { .driver_data = MT_CLS_RAZER_BLADE_STEALTH, 213962306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 214062306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0x8323) }, 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci /* Smart Tech panels */ 214362306a36Sopenharmony_ci { .driver_data = MT_CLS_SMART_TECH, 214462306a36Sopenharmony_ci MT_USB_DEVICE(0x0b8c, 0x0092)}, 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci /* Stantum panels */ 214762306a36Sopenharmony_ci { .driver_data = MT_CLS_CONFIDENCE, 214862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, 214962306a36Sopenharmony_ci USB_DEVICE_ID_MTP_STM)}, 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci /* Synaptics devices */ 215262306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 215362306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 215462306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0xcd7e) }, 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 215762306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 215862306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0xcddc) }, 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 216162306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 216262306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0xce08) }, 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 216562306a36Sopenharmony_ci HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, 216662306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 0xce09) }, 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci /* TopSeed panels */ 216962306a36Sopenharmony_ci { .driver_data = MT_CLS_TOPSEED, 217062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, 217162306a36Sopenharmony_ci USB_DEVICE_ID_TOPSEED2_PERIPAD_701) }, 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci /* Touch International panels */ 217462306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 217562306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, 217662306a36Sopenharmony_ci USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci /* Unitec panels */ 217962306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 218062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 218162306a36Sopenharmony_ci USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, 218262306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 218362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 218462306a36Sopenharmony_ci USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci /* VTL panels */ 218762306a36Sopenharmony_ci { .driver_data = MT_CLS_VTL, 218862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_VTL, 218962306a36Sopenharmony_ci USB_DEVICE_ID_VTL_MULTITOUCH_FF3F) }, 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci /* Winbond Electronics Corp. */ 219262306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8_NO_STICKY_FINGERS, 219362306a36Sopenharmony_ci HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8, 219462306a36Sopenharmony_ci USB_VENDOR_ID_WINBOND, USB_DEVICE_ID_TSTP_MTOUCH) }, 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci /* Wistron panels */ 219762306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 219862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_WISTRON, 219962306a36Sopenharmony_ci USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH) }, 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci /* XAT */ 220262306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 220362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XAT, 220462306a36Sopenharmony_ci USB_DEVICE_ID_XAT_CSR) }, 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci /* Xiroku */ 220762306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 220862306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 220962306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_SPX) }, 221062306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 221162306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 221262306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_MPX) }, 221362306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 221462306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 221562306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_CSR) }, 221662306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 221762306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 221862306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_SPX1) }, 221962306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 222062306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 222162306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_MPX1) }, 222262306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 222362306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 222462306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_CSR1) }, 222562306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 222662306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 222762306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_SPX2) }, 222862306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 222962306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 223062306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_MPX2) }, 223162306a36Sopenharmony_ci { .driver_data = MT_CLS_NSMU, 223262306a36Sopenharmony_ci MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 223362306a36Sopenharmony_ci USB_DEVICE_ID_XIROKU_CSR2) }, 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci /* Google MT devices */ 223662306a36Sopenharmony_ci { .driver_data = MT_CLS_GOOGLE, 223762306a36Sopenharmony_ci HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, 223862306a36Sopenharmony_ci USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) }, 223962306a36Sopenharmony_ci { .driver_data = MT_CLS_GOOGLE, 224062306a36Sopenharmony_ci HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_GOOGLE, 224162306a36Sopenharmony_ci USB_DEVICE_ID_GOOGLE_WHISKERS) }, 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci /* Generic MT device */ 224462306a36Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci /* Generic Win 8 certified MT device */ 224762306a36Sopenharmony_ci { .driver_data = MT_CLS_WIN_8, 224862306a36Sopenharmony_ci HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8, 224962306a36Sopenharmony_ci HID_ANY_ID, HID_ANY_ID) }, 225062306a36Sopenharmony_ci { } 225162306a36Sopenharmony_ci}; 225262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, mt_devices); 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_cistatic const struct hid_usage_id mt_grabbed_usages[] = { 225562306a36Sopenharmony_ci { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 225662306a36Sopenharmony_ci { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 225762306a36Sopenharmony_ci}; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_cistatic struct hid_driver mt_driver = { 226062306a36Sopenharmony_ci .name = "hid-multitouch", 226162306a36Sopenharmony_ci .id_table = mt_devices, 226262306a36Sopenharmony_ci .probe = mt_probe, 226362306a36Sopenharmony_ci .remove = mt_remove, 226462306a36Sopenharmony_ci .input_mapping = mt_input_mapping, 226562306a36Sopenharmony_ci .input_mapped = mt_input_mapped, 226662306a36Sopenharmony_ci .input_configured = mt_input_configured, 226762306a36Sopenharmony_ci .feature_mapping = mt_feature_mapping, 226862306a36Sopenharmony_ci .usage_table = mt_grabbed_usages, 226962306a36Sopenharmony_ci .event = mt_event, 227062306a36Sopenharmony_ci .report = mt_report, 227162306a36Sopenharmony_ci#ifdef CONFIG_PM 227262306a36Sopenharmony_ci .suspend = mt_suspend, 227362306a36Sopenharmony_ci .reset_resume = mt_reset_resume, 227462306a36Sopenharmony_ci .resume = mt_resume, 227562306a36Sopenharmony_ci#endif 227662306a36Sopenharmony_ci}; 227762306a36Sopenharmony_cimodule_hid_driver(mt_driver); 2278