15519cab4SBenjamin Tissoires /* 25519cab4SBenjamin Tissoires * HID driver for multitouch panels 35519cab4SBenjamin Tissoires * 4c2ef8f21SBenjamin Tissoires * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> 5c2ef8f21SBenjamin Tissoires * Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> 6c2ef8f21SBenjamin Tissoires * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France 75519cab4SBenjamin Tissoires * 84875ac11SRichard Nauber * This code is partly based on hid-egalax.c: 94875ac11SRichard Nauber * 104875ac11SRichard Nauber * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> 114875ac11SRichard Nauber * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 124875ac11SRichard Nauber * Copyright (c) 2010 Canonical, Ltd. 134875ac11SRichard Nauber * 14f786bba4SBenjamin Tissoires * This code is partly based on hid-3m-pct.c: 15f786bba4SBenjamin Tissoires * 16f786bba4SBenjamin Tissoires * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> 17f786bba4SBenjamin Tissoires * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> 18f786bba4SBenjamin Tissoires * Copyright (c) 2010 Canonical, Ltd. 19f786bba4SBenjamin Tissoires * 205519cab4SBenjamin Tissoires */ 215519cab4SBenjamin Tissoires 225519cab4SBenjamin Tissoires /* 235519cab4SBenjamin Tissoires * This program is free software; you can redistribute it and/or modify it 245519cab4SBenjamin Tissoires * under the terms of the GNU General Public License as published by the Free 255519cab4SBenjamin Tissoires * Software Foundation; either version 2 of the License, or (at your option) 265519cab4SBenjamin Tissoires * any later version. 275519cab4SBenjamin Tissoires */ 285519cab4SBenjamin Tissoires 295519cab4SBenjamin Tissoires #include <linux/device.h> 305519cab4SBenjamin Tissoires #include <linux/hid.h> 315519cab4SBenjamin Tissoires #include <linux/module.h> 325519cab4SBenjamin Tissoires #include <linux/slab.h> 335519cab4SBenjamin Tissoires #include <linux/usb.h> 345519cab4SBenjamin Tissoires #include <linux/input/mt.h> 355519cab4SBenjamin Tissoires #include "usbhid/usbhid.h" 365519cab4SBenjamin Tissoires 375519cab4SBenjamin Tissoires 385519cab4SBenjamin Tissoires MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); 39ef2fafb3SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 405519cab4SBenjamin Tissoires MODULE_DESCRIPTION("HID multitouch panels"); 415519cab4SBenjamin Tissoires MODULE_LICENSE("GPL"); 425519cab4SBenjamin Tissoires 435519cab4SBenjamin Tissoires #include "hid-ids.h" 445519cab4SBenjamin Tissoires 455519cab4SBenjamin Tissoires /* quirks to control the device */ 465519cab4SBenjamin Tissoires #define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0) 475519cab4SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1) 48a3b5e577SBenjamin Tissoires #define MT_QUIRK_CYPRESS (1 << 2) 495572da08SBenjamin Tissoires #define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) 50a062cc5aSStephane Chatty #define MT_QUIRK_ALWAYS_VALID (1 << 4) 51a062cc5aSStephane Chatty #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) 52a062cc5aSStephane Chatty #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) 53a062cc5aSStephane Chatty #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) 5477723e3bSHenrik Rydberg #define MT_QUIRK_NO_AREA (1 << 9) 555519cab4SBenjamin Tissoires 565519cab4SBenjamin Tissoires struct mt_slot { 57349fd670SBenjamin Tissoires __s32 x, y, cx, cy, p, w, h; 585519cab4SBenjamin Tissoires __s32 contactid; /* the device ContactID assigned to this slot */ 595519cab4SBenjamin Tissoires bool touch_state; /* is the touch valid? */ 605519cab4SBenjamin Tissoires }; 615519cab4SBenjamin Tissoires 625519cab4SBenjamin Tissoires struct mt_class { 632d93666eSBenjamin Tissoires __s32 name; /* MT_CLS */ 645519cab4SBenjamin Tissoires __s32 quirks; 655519cab4SBenjamin Tissoires __s32 sn_move; /* Signal/noise ratio for move events */ 66f786bba4SBenjamin Tissoires __s32 sn_width; /* Signal/noise ratio for width events */ 67f786bba4SBenjamin Tissoires __s32 sn_height; /* Signal/noise ratio for height events */ 685519cab4SBenjamin Tissoires __s32 sn_pressure; /* Signal/noise ratio for pressure events */ 695519cab4SBenjamin Tissoires __u8 maxcontacts; 70c2ef8f21SBenjamin Tissoires bool is_indirect; /* true for touchpads */ 715519cab4SBenjamin Tissoires }; 725519cab4SBenjamin Tissoires 733ac36d15SBenjamin Tissoires struct mt_fields { 743ac36d15SBenjamin Tissoires unsigned usages[HID_MAX_FIELDS]; 753ac36d15SBenjamin Tissoires unsigned int length; 763ac36d15SBenjamin Tissoires }; 773ac36d15SBenjamin Tissoires 785519cab4SBenjamin Tissoires struct mt_device { 795519cab4SBenjamin Tissoires struct mt_slot curdata; /* placeholder of incoming data */ 80eec29e3dSBenjamin Tissoires struct mt_class mtclass; /* our mt device class */ 813ac36d15SBenjamin Tissoires struct mt_fields *fields; /* temporary placeholder for storing the 823ac36d15SBenjamin Tissoires multitouch fields */ 835519cab4SBenjamin Tissoires unsigned last_field_index; /* last field index of the report */ 845519cab4SBenjamin Tissoires unsigned last_slot_field; /* the last field of a slot */ 855519cab4SBenjamin Tissoires __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ 864aceed37SBenjamin Tissoires __s8 inputmode_index; /* InputMode HID feature index in the report */ 8731ae9bddSBenjamin Tissoires __s8 maxcontact_report_id; /* Maximum Contact Number HID feature, 8831ae9bddSBenjamin Tissoires -1 if non-existent */ 895519cab4SBenjamin Tissoires __u8 num_received; /* how many contacts we received */ 905519cab4SBenjamin Tissoires __u8 num_expected; /* expected last contact index */ 915519cab4SBenjamin Tissoires __u8 maxcontacts; 929e87f22aSBenjamin Tissoires __u8 touches_by_report; /* how many touches are present in one report: 939e87f22aSBenjamin Tissoires * 1 means we should use a serial protocol 949e87f22aSBenjamin Tissoires * > 1 means hybrid (multitouch) protocol */ 9576f5902aSHenrik Rydberg bool serial_maybe; /* need to check for serial protocol */ 965519cab4SBenjamin Tissoires bool curvalid; /* is the current contact valid? */ 9776f5902aSHenrik Rydberg unsigned mt_flags; /* flags to pass to input-mt */ 985519cab4SBenjamin Tissoires }; 995519cab4SBenjamin Tissoires 1005519cab4SBenjamin Tissoires /* classes of device behavior */ 10122408283SBenjamin Tissoires #define MT_CLS_DEFAULT 0x0001 10222408283SBenjamin Tissoires 103a062cc5aSStephane Chatty #define MT_CLS_SERIAL 0x0002 104a062cc5aSStephane Chatty #define MT_CLS_CONFIDENCE 0x0003 1055e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_CONTACT_ID 0x0004 1065e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 1075e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 1085e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 1095e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_NSMU_CONTACTID 0x0008 110b7ea95ffSAaron Tian #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 11122408283SBenjamin Tissoires 11222408283SBenjamin Tissoires /* vendor specific classes */ 11322408283SBenjamin Tissoires #define MT_CLS_3M 0x0101 11422408283SBenjamin Tissoires #define MT_CLS_CYPRESS 0x0102 11522408283SBenjamin Tissoires #define MT_CLS_EGALAX 0x0103 1161b723e8dSBenjamin Tissoires #define MT_CLS_EGALAX_SERIAL 0x0104 117847672cdSBenjamin Tissoires #define MT_CLS_TOPSEED 0x0105 1182258e863SDenis Kovalev #define MT_CLS_PANASONIC 0x0106 11977723e3bSHenrik Rydberg #define MT_CLS_FLATFROG 0x0107 120cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 121cdcd3ac4SJiri Kosina #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 1225519cab4SBenjamin Tissoires 1239498f954SBenjamin Tissoires #define MT_DEFAULT_MAXCONTACT 10 124afbcb04cSBenjamin Tissoires #define MT_MAX_MAXCONTACT 250 1259498f954SBenjamin Tissoires 1262c2110e9SHenrik Rydberg #define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) 1272c2110e9SHenrik Rydberg #define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) 1282c2110e9SHenrik Rydberg 1295519cab4SBenjamin Tissoires /* 1305519cab4SBenjamin Tissoires * these device-dependent functions determine what slot corresponds 1315519cab4SBenjamin Tissoires * to a valid contact that was just read. 1325519cab4SBenjamin Tissoires */ 1335519cab4SBenjamin Tissoires 134a3b5e577SBenjamin Tissoires static int cypress_compute_slot(struct mt_device *td) 135a3b5e577SBenjamin Tissoires { 136a3b5e577SBenjamin Tissoires if (td->curdata.contactid != 0 || td->num_received == 0) 137a3b5e577SBenjamin Tissoires return td->curdata.contactid; 138a3b5e577SBenjamin Tissoires else 139a3b5e577SBenjamin Tissoires return -1; 140a3b5e577SBenjamin Tissoires } 141a3b5e577SBenjamin Tissoires 142b3c21d2cSJiri Kosina static struct mt_class mt_classes[] = { 1432d93666eSBenjamin Tissoires { .name = MT_CLS_DEFAULT, 1449498f954SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, 145a062cc5aSStephane Chatty { .name = MT_CLS_SERIAL, 146a062cc5aSStephane Chatty .quirks = MT_QUIRK_ALWAYS_VALID}, 14722408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE, 14822408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, 1495e7ea11fSBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_CONTACT_ID, 1505e7ea11fSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 1515e7ea11fSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID }, 15222408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_MINUS_ONE, 15322408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 15422408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, 1551e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTID, 1562d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 1572d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 1582d93666eSBenjamin Tissoires .maxcontacts = 2 }, 1591e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 1602d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 1612d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTNUMBER, 1622d93666eSBenjamin Tissoires .maxcontacts = 2 }, 16322408283SBenjamin Tissoires { .name = MT_CLS_DUAL_NSMU_CONTACTID, 16422408283SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 16522408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 16622408283SBenjamin Tissoires .maxcontacts = 2 }, 167b7ea95ffSAaron Tian { .name = MT_CLS_INRANGE_CONTACTNUMBER, 168b7ea95ffSAaron Tian .quirks = MT_QUIRK_VALID_IS_INRANGE | 169b7ea95ffSAaron Tian MT_QUIRK_SLOT_IS_CONTACTNUMBER }, 17022408283SBenjamin Tissoires 17122408283SBenjamin Tissoires /* 17222408283SBenjamin Tissoires * vendor specific classes 17322408283SBenjamin Tissoires */ 17422408283SBenjamin Tissoires { .name = MT_CLS_3M, 17522408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 17622408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 17722408283SBenjamin Tissoires .sn_move = 2048, 17822408283SBenjamin Tissoires .sn_width = 128, 179c5d40be5SHenrik Rydberg .sn_height = 128, 180c5d40be5SHenrik Rydberg .maxcontacts = 60, 181c5d40be5SHenrik Rydberg }, 1822d93666eSBenjamin Tissoires { .name = MT_CLS_CYPRESS, 1832d93666eSBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 1842d93666eSBenjamin Tissoires MT_QUIRK_CYPRESS, 1852d93666eSBenjamin Tissoires .maxcontacts = 10 }, 1864875ac11SRichard Nauber { .name = MT_CLS_EGALAX, 1874875ac11SRichard Nauber .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 1882261bb9fSBenjamin Tissoires MT_QUIRK_VALID_IS_INRANGE, 1894875ac11SRichard Nauber .sn_move = 4096, 1904875ac11SRichard Nauber .sn_pressure = 32, 1914875ac11SRichard Nauber }, 1921b723e8dSBenjamin Tissoires { .name = MT_CLS_EGALAX_SERIAL, 1931b723e8dSBenjamin Tissoires .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 1941b723e8dSBenjamin Tissoires MT_QUIRK_ALWAYS_VALID, 1952d93666eSBenjamin Tissoires .sn_move = 4096, 1962d93666eSBenjamin Tissoires .sn_pressure = 32, 1972d93666eSBenjamin Tissoires }, 198847672cdSBenjamin Tissoires { .name = MT_CLS_TOPSEED, 199847672cdSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID, 200847672cdSBenjamin Tissoires .is_indirect = true, 201847672cdSBenjamin Tissoires .maxcontacts = 2, 202847672cdSBenjamin Tissoires }, 2032258e863SDenis Kovalev { .name = MT_CLS_PANASONIC, 2042258e863SDenis Kovalev .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, 2052258e863SDenis Kovalev .maxcontacts = 4 }, 206f5ff4e1eSXianhan Yu { .name = MT_CLS_GENERALTOUCH_TWOFINGERS, 207f5ff4e1eSXianhan Yu .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 208f5ff4e1eSXianhan Yu MT_QUIRK_VALID_IS_INRANGE | 209f5ff4e1eSXianhan Yu MT_QUIRK_SLOT_IS_CONTACTNUMBER, 210f5ff4e1eSXianhan Yu .maxcontacts = 2 211f5ff4e1eSXianhan Yu }, 212f5ff4e1eSXianhan Yu { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 213f5ff4e1eSXianhan Yu .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 21458ad34bfSXianhan Yu MT_QUIRK_SLOT_IS_CONTACTNUMBER 215f5ff4e1eSXianhan Yu }, 216043b403aSBenjamin Tissoires 21777723e3bSHenrik Rydberg { .name = MT_CLS_FLATFROG, 21877723e3bSHenrik Rydberg .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 21977723e3bSHenrik Rydberg MT_QUIRK_NO_AREA, 22077723e3bSHenrik Rydberg .sn_move = 2048, 22177723e3bSHenrik Rydberg .maxcontacts = 40, 22277723e3bSHenrik Rydberg }, 2232d93666eSBenjamin Tissoires { } 2245519cab4SBenjamin Tissoires }; 2255519cab4SBenjamin Tissoires 226eec29e3dSBenjamin Tissoires static ssize_t mt_show_quirks(struct device *dev, 227eec29e3dSBenjamin Tissoires struct device_attribute *attr, 228eec29e3dSBenjamin Tissoires char *buf) 229eec29e3dSBenjamin Tissoires { 230eec29e3dSBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 231eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 232eec29e3dSBenjamin Tissoires 233eec29e3dSBenjamin Tissoires return sprintf(buf, "%u\n", td->mtclass.quirks); 234eec29e3dSBenjamin Tissoires } 235eec29e3dSBenjamin Tissoires 236eec29e3dSBenjamin Tissoires static ssize_t mt_set_quirks(struct device *dev, 237eec29e3dSBenjamin Tissoires struct device_attribute *attr, 238eec29e3dSBenjamin Tissoires const char *buf, size_t count) 239eec29e3dSBenjamin Tissoires { 240eec29e3dSBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 241eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 242eec29e3dSBenjamin Tissoires 243eec29e3dSBenjamin Tissoires unsigned long val; 244eec29e3dSBenjamin Tissoires 245eec29e3dSBenjamin Tissoires if (kstrtoul(buf, 0, &val)) 246eec29e3dSBenjamin Tissoires return -EINVAL; 247eec29e3dSBenjamin Tissoires 248eec29e3dSBenjamin Tissoires td->mtclass.quirks = val; 249eec29e3dSBenjamin Tissoires 250eec29e3dSBenjamin Tissoires return count; 251eec29e3dSBenjamin Tissoires } 252eec29e3dSBenjamin Tissoires 253eec29e3dSBenjamin Tissoires static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); 254eec29e3dSBenjamin Tissoires 255eec29e3dSBenjamin Tissoires static struct attribute *sysfs_attrs[] = { 256eec29e3dSBenjamin Tissoires &dev_attr_quirks.attr, 257eec29e3dSBenjamin Tissoires NULL 258eec29e3dSBenjamin Tissoires }; 259eec29e3dSBenjamin Tissoires 260eec29e3dSBenjamin Tissoires static struct attribute_group mt_attribute_group = { 261eec29e3dSBenjamin Tissoires .attrs = sysfs_attrs 262eec29e3dSBenjamin Tissoires }; 263eec29e3dSBenjamin Tissoires 264f635bd11SHenrik Rydberg static void mt_feature_mapping(struct hid_device *hdev, 2655519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage) 2665519cab4SBenjamin Tissoires { 2675519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 2684aceed37SBenjamin Tissoires int i; 2699498f954SBenjamin Tissoires 2709498f954SBenjamin Tissoires switch (usage->hid) { 2719498f954SBenjamin Tissoires case HID_DG_INPUTMODE: 2725519cab4SBenjamin Tissoires td->inputmode = field->report->id; 2734aceed37SBenjamin Tissoires td->inputmode_index = 0; /* has to be updated below */ 2744aceed37SBenjamin Tissoires 2754aceed37SBenjamin Tissoires for (i=0; i < field->maxusage; i++) { 2764aceed37SBenjamin Tissoires if (field->usage[i].hid == usage->hid) { 2774aceed37SBenjamin Tissoires td->inputmode_index = i; 2784aceed37SBenjamin Tissoires break; 2794aceed37SBenjamin Tissoires } 2804aceed37SBenjamin Tissoires } 2814aceed37SBenjamin Tissoires 2829498f954SBenjamin Tissoires break; 2839498f954SBenjamin Tissoires case HID_DG_CONTACTMAX: 28431ae9bddSBenjamin Tissoires td->maxcontact_report_id = field->report->id; 2859498f954SBenjamin Tissoires td->maxcontacts = field->value[0]; 286afbcb04cSBenjamin Tissoires if (!td->maxcontacts && 287afbcb04cSBenjamin Tissoires field->logical_maximum <= MT_MAX_MAXCONTACT) 288afbcb04cSBenjamin Tissoires td->maxcontacts = field->logical_maximum; 289eec29e3dSBenjamin Tissoires if (td->mtclass.maxcontacts) 2909498f954SBenjamin Tissoires /* check if the maxcontacts is given by the class */ 291eec29e3dSBenjamin Tissoires td->maxcontacts = td->mtclass.maxcontacts; 2929498f954SBenjamin Tissoires 2939498f954SBenjamin Tissoires break; 2945519cab4SBenjamin Tissoires } 2955519cab4SBenjamin Tissoires } 2965519cab4SBenjamin Tissoires 2975519cab4SBenjamin Tissoires static void set_abs(struct input_dev *input, unsigned int code, 2985519cab4SBenjamin Tissoires struct hid_field *field, int snratio) 2995519cab4SBenjamin Tissoires { 3005519cab4SBenjamin Tissoires int fmin = field->logical_minimum; 3015519cab4SBenjamin Tissoires int fmax = field->logical_maximum; 3025519cab4SBenjamin Tissoires int fuzz = snratio ? (fmax - fmin) / snratio : 0; 3035519cab4SBenjamin Tissoires input_set_abs_params(input, code, fmin, fmax, fuzz, 0); 30437cf6e6fSBenjamin Tissoires input_abs_set_res(input, code, hidinput_calc_abs_res(field, code)); 3055519cab4SBenjamin Tissoires } 3065519cab4SBenjamin Tissoires 3073ac36d15SBenjamin Tissoires static void mt_store_field(struct hid_usage *usage, struct mt_device *td, 308ed9d5c96SBenjamin Tissoires struct hid_input *hi) 309ed9d5c96SBenjamin Tissoires { 3103ac36d15SBenjamin Tissoires struct mt_fields *f = td->fields; 3113ac36d15SBenjamin Tissoires 3123ac36d15SBenjamin Tissoires if (f->length >= HID_MAX_FIELDS) 3133ac36d15SBenjamin Tissoires return; 3143ac36d15SBenjamin Tissoires 3153ac36d15SBenjamin Tissoires f->usages[f->length++] = usage->hid; 316ed9d5c96SBenjamin Tissoires } 317ed9d5c96SBenjamin Tissoires 3185519cab4SBenjamin Tissoires static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 3195519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 3205519cab4SBenjamin Tissoires unsigned long **bit, int *max) 3215519cab4SBenjamin Tissoires { 3225519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 323eec29e3dSBenjamin Tissoires struct mt_class *cls = &td->mtclass; 324c2ef8f21SBenjamin Tissoires int code; 325349fd670SBenjamin Tissoires struct hid_usage *prev_usage = NULL; 3264875ac11SRichard Nauber 327658d4aedSJeff Brown /* Only map fields from TouchScreen or TouchPad collections. 328658d4aedSJeff Brown * We need to ignore fields that belong to other collections 329658d4aedSJeff Brown * such as Mouse that might have the same GenericDesktop usages. */ 330658d4aedSJeff Brown if (field->application == HID_DG_TOUCHSCREEN) 33176f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_DIRECT; 332c2ef8f21SBenjamin Tissoires else if (field->application != HID_DG_TOUCHPAD) 333658d4aedSJeff Brown return 0; 334658d4aedSJeff Brown 33576f5902aSHenrik Rydberg /* 33676f5902aSHenrik Rydberg * Model touchscreens providing buttons as touchpads. 337c2ef8f21SBenjamin Tissoires */ 338c2ef8f21SBenjamin Tissoires if (field->application == HID_DG_TOUCHPAD || 33976f5902aSHenrik Rydberg (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) 34076f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_POINTER; 341c2ef8f21SBenjamin Tissoires 3422261bb9fSBenjamin Tissoires /* eGalax devices provide a Digitizer.Stylus input which overrides 3432261bb9fSBenjamin Tissoires * the correct Digitizers.Finger X/Y ranges. 3442261bb9fSBenjamin Tissoires * Let's just ignore this input. */ 3452261bb9fSBenjamin Tissoires if (field->physical == HID_DG_STYLUS) 3462261bb9fSBenjamin Tissoires return -1; 3472261bb9fSBenjamin Tissoires 348349fd670SBenjamin Tissoires if (usage->usage_index) 349349fd670SBenjamin Tissoires prev_usage = &field->usage[usage->usage_index - 1]; 350349fd670SBenjamin Tissoires 3515519cab4SBenjamin Tissoires switch (usage->hid & HID_USAGE_PAGE) { 3525519cab4SBenjamin Tissoires 3535519cab4SBenjamin Tissoires case HID_UP_GENDESK: 3545519cab4SBenjamin Tissoires switch (usage->hid) { 3555519cab4SBenjamin Tissoires case HID_GD_X: 356349fd670SBenjamin Tissoires if (prev_usage && (prev_usage->hid == usage->hid)) { 357349fd670SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 358349fd670SBenjamin Tissoires EV_ABS, ABS_MT_TOOL_X); 359349fd670SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOOL_X, field, 360349fd670SBenjamin Tissoires cls->sn_move); 361349fd670SBenjamin Tissoires } else { 3625519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3635519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_X); 3645519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_X, field, 3655519cab4SBenjamin Tissoires cls->sn_move); 366349fd670SBenjamin Tissoires } 367349fd670SBenjamin Tissoires 3683ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3692955caedSBenjamin Tissoires td->last_field_index = field->index; 3705519cab4SBenjamin Tissoires return 1; 3715519cab4SBenjamin Tissoires case HID_GD_Y: 372349fd670SBenjamin Tissoires if (prev_usage && (prev_usage->hid == usage->hid)) { 373349fd670SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 374349fd670SBenjamin Tissoires EV_ABS, ABS_MT_TOOL_Y); 375349fd670SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOOL_Y, field, 376349fd670SBenjamin Tissoires cls->sn_move); 377349fd670SBenjamin Tissoires } else { 3785519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3795519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_Y); 3805519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_Y, field, 3815519cab4SBenjamin Tissoires cls->sn_move); 382349fd670SBenjamin Tissoires } 383349fd670SBenjamin Tissoires 3843ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3852955caedSBenjamin Tissoires td->last_field_index = field->index; 3865519cab4SBenjamin Tissoires return 1; 3875519cab4SBenjamin Tissoires } 3885519cab4SBenjamin Tissoires return 0; 3895519cab4SBenjamin Tissoires 3905519cab4SBenjamin Tissoires case HID_UP_DIGITIZER: 3915519cab4SBenjamin Tissoires switch (usage->hid) { 3925519cab4SBenjamin Tissoires case HID_DG_INRANGE: 3933ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3942955caedSBenjamin Tissoires td->last_field_index = field->index; 3955519cab4SBenjamin Tissoires return 1; 3965519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 3973ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3982955caedSBenjamin Tissoires td->last_field_index = field->index; 3995519cab4SBenjamin Tissoires return 1; 4005519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 4015519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); 4025519cab4SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, BTN_TOUCH); 4033ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 4042955caedSBenjamin Tissoires td->last_field_index = field->index; 4055519cab4SBenjamin Tissoires return 1; 4065519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 4073ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 4082955caedSBenjamin Tissoires td->last_field_index = field->index; 4099e87f22aSBenjamin Tissoires td->touches_by_report++; 4105519cab4SBenjamin Tissoires return 1; 4115519cab4SBenjamin Tissoires case HID_DG_WIDTH: 4125519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 4135519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MAJOR); 41477723e3bSHenrik Rydberg if (!(cls->quirks & MT_QUIRK_NO_AREA)) 415f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, 416f786bba4SBenjamin Tissoires cls->sn_width); 4173ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 4182955caedSBenjamin Tissoires td->last_field_index = field->index; 4195519cab4SBenjamin Tissoires return 1; 4205519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 4215519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 4225519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MINOR); 42377723e3bSHenrik Rydberg if (!(cls->quirks & MT_QUIRK_NO_AREA)) { 424f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, 425f786bba4SBenjamin Tissoires cls->sn_height); 4261e648a13SBenjamin Tissoires input_set_abs_params(hi->input, 4271e648a13SBenjamin Tissoires ABS_MT_ORIENTATION, 0, 1, 0, 0); 42877723e3bSHenrik Rydberg } 4293ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 4302955caedSBenjamin Tissoires td->last_field_index = field->index; 4315519cab4SBenjamin Tissoires return 1; 4325519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 4335519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 4345519cab4SBenjamin Tissoires EV_ABS, ABS_MT_PRESSURE); 4355519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_PRESSURE, field, 4365519cab4SBenjamin Tissoires cls->sn_pressure); 4373ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 4382955caedSBenjamin Tissoires td->last_field_index = field->index; 4395519cab4SBenjamin Tissoires return 1; 4405519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 4412955caedSBenjamin Tissoires td->last_field_index = field->index; 4425519cab4SBenjamin Tissoires return 1; 4435519cab4SBenjamin Tissoires case HID_DG_CONTACTMAX: 4445519cab4SBenjamin Tissoires /* we don't set td->last_slot_field as contactcount and 4455519cab4SBenjamin Tissoires * contact max are global to the report */ 4462955caedSBenjamin Tissoires td->last_field_index = field->index; 4475519cab4SBenjamin Tissoires return -1; 448c2ef8f21SBenjamin Tissoires case HID_DG_TOUCH: 449c2ef8f21SBenjamin Tissoires /* Legacy devices use TIPSWITCH and not TOUCH. 450c2ef8f21SBenjamin Tissoires * Let's just ignore this field. */ 451c2ef8f21SBenjamin Tissoires return -1; 45265b258e9SAlan Cox } 4535519cab4SBenjamin Tissoires /* let hid-input decide for the others */ 4545519cab4SBenjamin Tissoires return 0; 4555519cab4SBenjamin Tissoires 456c2ef8f21SBenjamin Tissoires case HID_UP_BUTTON: 457c2ef8f21SBenjamin Tissoires code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); 458c2ef8f21SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, code); 459c2ef8f21SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, code); 460c2ef8f21SBenjamin Tissoires return 1; 461c2ef8f21SBenjamin Tissoires 4625519cab4SBenjamin Tissoires case 0xff000000: 4635519cab4SBenjamin Tissoires /* we do not want to map these: no input-oriented meaning */ 4645519cab4SBenjamin Tissoires return -1; 4655519cab4SBenjamin Tissoires } 4665519cab4SBenjamin Tissoires 4675519cab4SBenjamin Tissoires return 0; 4685519cab4SBenjamin Tissoires } 4695519cab4SBenjamin Tissoires 4705519cab4SBenjamin Tissoires static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, 4715519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 4725519cab4SBenjamin Tissoires unsigned long **bit, int *max) 4735519cab4SBenjamin Tissoires { 4745519cab4SBenjamin Tissoires if (usage->type == EV_KEY || usage->type == EV_ABS) 4755519cab4SBenjamin Tissoires set_bit(usage->type, hi->input->evbit); 4765519cab4SBenjamin Tissoires 4775519cab4SBenjamin Tissoires return -1; 4785519cab4SBenjamin Tissoires } 4795519cab4SBenjamin Tissoires 4803e1b5015SHenrik Rydberg static int mt_compute_slot(struct mt_device *td, struct input_dev *input) 4815519cab4SBenjamin Tissoires { 482eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 4835519cab4SBenjamin Tissoires 4842d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) 4852d93666eSBenjamin Tissoires return td->curdata.contactid; 4865519cab4SBenjamin Tissoires 4872d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_CYPRESS) 488a3b5e577SBenjamin Tissoires return cypress_compute_slot(td); 489a3b5e577SBenjamin Tissoires 4902d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) 4912d93666eSBenjamin Tissoires return td->num_received; 4925572da08SBenjamin Tissoires 4934a6ee685SBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) 4944a6ee685SBenjamin Tissoires return td->curdata.contactid - 1; 4954a6ee685SBenjamin Tissoires 4963e1b5015SHenrik Rydberg return input_mt_get_slot_by_key(input, td->curdata.contactid); 4975519cab4SBenjamin Tissoires } 4985519cab4SBenjamin Tissoires 4995519cab4SBenjamin Tissoires /* 5005519cab4SBenjamin Tissoires * this function is called when a whole contact has been processed, 5015519cab4SBenjamin Tissoires * so that it can assign it to a slot and store the data there 5025519cab4SBenjamin Tissoires */ 5033e1b5015SHenrik Rydberg static void mt_complete_slot(struct mt_device *td, struct input_dev *input) 5045519cab4SBenjamin Tissoires { 505*20b60e6dSBenjamin Tissoires if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) { 5063e1b5015SHenrik Rydberg int slotnum = mt_compute_slot(td, input); 5073e1b5015SHenrik Rydberg struct mt_slot *s = &td->curdata; 5085519cab4SBenjamin Tissoires 5093e1b5015SHenrik Rydberg if (slotnum < 0 || slotnum >= td->maxcontacts) 5103e1b5015SHenrik Rydberg return; 5115519cab4SBenjamin Tissoires 5123e1b5015SHenrik Rydberg input_mt_slot(input, slotnum); 5135519cab4SBenjamin Tissoires input_mt_report_slot_state(input, MT_TOOL_FINGER, 5145519cab4SBenjamin Tissoires s->touch_state); 5152d93666eSBenjamin Tissoires if (s->touch_state) { 516f786bba4SBenjamin Tissoires /* this finger is on the screen */ 517f786bba4SBenjamin Tissoires int wide = (s->w > s->h); 518f786bba4SBenjamin Tissoires /* divided by two to match visual scale of touch */ 519f786bba4SBenjamin Tissoires int major = max(s->w, s->h) >> 1; 520f786bba4SBenjamin Tissoires int minor = min(s->w, s->h) >> 1; 521f786bba4SBenjamin Tissoires 5225519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); 5235519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); 524349fd670SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx); 525349fd670SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy); 526f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); 5275519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); 528f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 529f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 5302d93666eSBenjamin Tissoires } 5315519cab4SBenjamin Tissoires } 5325519cab4SBenjamin Tissoires 5333e1b5015SHenrik Rydberg td->num_received++; 5343e1b5015SHenrik Rydberg } 5353e1b5015SHenrik Rydberg 5363e1b5015SHenrik Rydberg /* 5373e1b5015SHenrik Rydberg * this function is called when a whole packet has been received and processed, 5383e1b5015SHenrik Rydberg * so that it can decide what to send to the input layer. 5393e1b5015SHenrik Rydberg */ 5403e1b5015SHenrik Rydberg static void mt_sync_frame(struct mt_device *td, struct input_dev *input) 5413e1b5015SHenrik Rydberg { 54276f5902aSHenrik Rydberg input_mt_sync_frame(input); 5435519cab4SBenjamin Tissoires input_sync(input); 5445519cab4SBenjamin Tissoires td->num_received = 0; 5455519cab4SBenjamin Tissoires } 5465519cab4SBenjamin Tissoires 5475519cab4SBenjamin Tissoires static int mt_event(struct hid_device *hid, struct hid_field *field, 5485519cab4SBenjamin Tissoires struct hid_usage *usage, __s32 value) 5495519cab4SBenjamin Tissoires { 5505519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 551eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 5525519cab4SBenjamin Tissoires 5533e1b5015SHenrik Rydberg if (hid->claimed & HID_CLAIMED_INPUT) { 5545519cab4SBenjamin Tissoires switch (usage->hid) { 5555519cab4SBenjamin Tissoires case HID_DG_INRANGE: 556*20b60e6dSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_INRANGE) 5572d93666eSBenjamin Tissoires td->curvalid = value; 5585519cab4SBenjamin Tissoires break; 5595519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 5602d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 5615519cab4SBenjamin Tissoires td->curvalid = value; 5625519cab4SBenjamin Tissoires td->curdata.touch_state = value; 5635519cab4SBenjamin Tissoires break; 5645519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 5652d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) 5662d93666eSBenjamin Tissoires td->curvalid = value; 5675519cab4SBenjamin Tissoires break; 5685519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 5695519cab4SBenjamin Tissoires td->curdata.contactid = value; 5705519cab4SBenjamin Tissoires break; 5715519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 5725519cab4SBenjamin Tissoires td->curdata.p = value; 5735519cab4SBenjamin Tissoires break; 5745519cab4SBenjamin Tissoires case HID_GD_X: 575349fd670SBenjamin Tissoires if (usage->code == ABS_MT_TOOL_X) 576349fd670SBenjamin Tissoires td->curdata.cx = value; 577349fd670SBenjamin Tissoires else 5785519cab4SBenjamin Tissoires td->curdata.x = value; 5795519cab4SBenjamin Tissoires break; 5805519cab4SBenjamin Tissoires case HID_GD_Y: 581349fd670SBenjamin Tissoires if (usage->code == ABS_MT_TOOL_Y) 582349fd670SBenjamin Tissoires td->curdata.cy = value; 583349fd670SBenjamin Tissoires else 5845519cab4SBenjamin Tissoires td->curdata.y = value; 5855519cab4SBenjamin Tissoires break; 5865519cab4SBenjamin Tissoires case HID_DG_WIDTH: 5875519cab4SBenjamin Tissoires td->curdata.w = value; 5885519cab4SBenjamin Tissoires break; 5895519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 5905519cab4SBenjamin Tissoires td->curdata.h = value; 5915519cab4SBenjamin Tissoires break; 5925519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 5935519cab4SBenjamin Tissoires /* 5942d93666eSBenjamin Tissoires * Includes multi-packet support where subsequent 5952d93666eSBenjamin Tissoires * packets are sent with zero contactcount. 5965519cab4SBenjamin Tissoires */ 5975519cab4SBenjamin Tissoires if (value) 5982d93666eSBenjamin Tissoires td->num_expected = value; 5995519cab4SBenjamin Tissoires break; 600c2ef8f21SBenjamin Tissoires case HID_DG_TOUCH: 601c2ef8f21SBenjamin Tissoires /* do nothing */ 602c2ef8f21SBenjamin Tissoires break; 6035519cab4SBenjamin Tissoires 6045519cab4SBenjamin Tissoires default: 6055519cab4SBenjamin Tissoires /* fallback to the generic hidinput handling */ 6065519cab4SBenjamin Tissoires return 0; 6075519cab4SBenjamin Tissoires } 6085519cab4SBenjamin Tissoires 60954f4c0c3SBenjamin Tissoires if (usage->usage_index + 1 == field->report_count) { 61054f4c0c3SBenjamin Tissoires /* we only take into account the last report. */ 6112258e863SDenis Kovalev if (usage->hid == td->last_slot_field) 6123e1b5015SHenrik Rydberg mt_complete_slot(td, field->hidinput->input); 6135519cab4SBenjamin Tissoires 6145519cab4SBenjamin Tissoires if (field->index == td->last_field_index 6152d93666eSBenjamin Tissoires && td->num_received >= td->num_expected) 6163e1b5015SHenrik Rydberg mt_sync_frame(td, field->hidinput->input); 61754f4c0c3SBenjamin Tissoires } 6185519cab4SBenjamin Tissoires 6192d93666eSBenjamin Tissoires } 6202d93666eSBenjamin Tissoires 6215519cab4SBenjamin Tissoires /* we have handled the hidinput part, now remains hiddev */ 6225519cab4SBenjamin Tissoires if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 6235519cab4SBenjamin Tissoires hid->hiddev_hid_event(hid, field, usage, value); 6245519cab4SBenjamin Tissoires 6255519cab4SBenjamin Tissoires return 1; 6265519cab4SBenjamin Tissoires } 6275519cab4SBenjamin Tissoires 6285519cab4SBenjamin Tissoires static void mt_set_input_mode(struct hid_device *hdev) 6295519cab4SBenjamin Tissoires { 6305519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 6315519cab4SBenjamin Tissoires struct hid_report *r; 6325519cab4SBenjamin Tissoires struct hid_report_enum *re; 6335519cab4SBenjamin Tissoires 6345519cab4SBenjamin Tissoires if (td->inputmode < 0) 6355519cab4SBenjamin Tissoires return; 6365519cab4SBenjamin Tissoires 6375519cab4SBenjamin Tissoires re = &(hdev->report_enum[HID_FEATURE_REPORT]); 6385519cab4SBenjamin Tissoires r = re->report_id_hash[td->inputmode]; 6395519cab4SBenjamin Tissoires if (r) { 6404aceed37SBenjamin Tissoires r->field[0]->value[td->inputmode_index] = 0x02; 6415519cab4SBenjamin Tissoires usbhid_submit_report(hdev, r, USB_DIR_OUT); 6425519cab4SBenjamin Tissoires } 6435519cab4SBenjamin Tissoires } 6445519cab4SBenjamin Tissoires 64531ae9bddSBenjamin Tissoires static void mt_set_maxcontacts(struct hid_device *hdev) 64631ae9bddSBenjamin Tissoires { 64731ae9bddSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 64831ae9bddSBenjamin Tissoires struct hid_report *r; 64931ae9bddSBenjamin Tissoires struct hid_report_enum *re; 65031ae9bddSBenjamin Tissoires int fieldmax, max; 65131ae9bddSBenjamin Tissoires 65231ae9bddSBenjamin Tissoires if (td->maxcontact_report_id < 0) 65331ae9bddSBenjamin Tissoires return; 65431ae9bddSBenjamin Tissoires 65531ae9bddSBenjamin Tissoires if (!td->mtclass.maxcontacts) 65631ae9bddSBenjamin Tissoires return; 65731ae9bddSBenjamin Tissoires 65831ae9bddSBenjamin Tissoires re = &hdev->report_enum[HID_FEATURE_REPORT]; 65931ae9bddSBenjamin Tissoires r = re->report_id_hash[td->maxcontact_report_id]; 66031ae9bddSBenjamin Tissoires if (r) { 66131ae9bddSBenjamin Tissoires max = td->mtclass.maxcontacts; 66231ae9bddSBenjamin Tissoires fieldmax = r->field[0]->logical_maximum; 66331ae9bddSBenjamin Tissoires max = min(fieldmax, max); 66431ae9bddSBenjamin Tissoires if (r->field[0]->value[0] != max) { 66531ae9bddSBenjamin Tissoires r->field[0]->value[0] = max; 66631ae9bddSBenjamin Tissoires usbhid_submit_report(hdev, r, USB_DIR_OUT); 66731ae9bddSBenjamin Tissoires } 66831ae9bddSBenjamin Tissoires } 66931ae9bddSBenjamin Tissoires } 67031ae9bddSBenjamin Tissoires 6714fa3a583SHenrik Rydberg static void mt_post_parse_default_settings(struct mt_device *td) 6724fa3a583SHenrik Rydberg { 6734fa3a583SHenrik Rydberg __s32 quirks = td->mtclass.quirks; 6744fa3a583SHenrik Rydberg 6754fa3a583SHenrik Rydberg /* unknown serial device needs special quirks */ 6764fa3a583SHenrik Rydberg if (td->touches_by_report == 1) { 6774fa3a583SHenrik Rydberg quirks |= MT_QUIRK_ALWAYS_VALID; 6784fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; 6794fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_INRANGE; 6804fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; 6814fa3a583SHenrik Rydberg } 6824fa3a583SHenrik Rydberg 6834fa3a583SHenrik Rydberg td->mtclass.quirks = quirks; 6844fa3a583SHenrik Rydberg } 6854fa3a583SHenrik Rydberg 6863ac36d15SBenjamin Tissoires static void mt_post_parse(struct mt_device *td) 6873ac36d15SBenjamin Tissoires { 6883ac36d15SBenjamin Tissoires struct mt_fields *f = td->fields; 6893ac36d15SBenjamin Tissoires 6903ac36d15SBenjamin Tissoires if (td->touches_by_report > 0) { 6913ac36d15SBenjamin Tissoires int field_count_per_touch = f->length / td->touches_by_report; 6923ac36d15SBenjamin Tissoires td->last_slot_field = f->usages[field_count_per_touch - 1]; 6933ac36d15SBenjamin Tissoires } 6943ac36d15SBenjamin Tissoires } 6953ac36d15SBenjamin Tissoires 69676f5902aSHenrik Rydberg static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) 69776f5902aSHenrik Rydberg 69876f5902aSHenrik Rydberg { 69976f5902aSHenrik Rydberg struct mt_device *td = hid_get_drvdata(hdev); 70076f5902aSHenrik Rydberg struct mt_class *cls = &td->mtclass; 70176f5902aSHenrik Rydberg struct input_dev *input = hi->input; 70276f5902aSHenrik Rydberg 70376f5902aSHenrik Rydberg /* Only initialize slots for MT input devices */ 70476f5902aSHenrik Rydberg if (!test_bit(ABS_MT_POSITION_X, input->absbit)) 70576f5902aSHenrik Rydberg return; 70676f5902aSHenrik Rydberg 70776f5902aSHenrik Rydberg if (!td->maxcontacts) 70876f5902aSHenrik Rydberg td->maxcontacts = MT_DEFAULT_MAXCONTACT; 70976f5902aSHenrik Rydberg 71076f5902aSHenrik Rydberg mt_post_parse(td); 71176f5902aSHenrik Rydberg if (td->serial_maybe) 71276f5902aSHenrik Rydberg mt_post_parse_default_settings(td); 71376f5902aSHenrik Rydberg 71476f5902aSHenrik Rydberg if (cls->is_indirect) 71576f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_POINTER; 71676f5902aSHenrik Rydberg 7173e1b5015SHenrik Rydberg if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 7183e1b5015SHenrik Rydberg td->mt_flags |= INPUT_MT_DROP_UNUSED; 7193e1b5015SHenrik Rydberg 72076f5902aSHenrik Rydberg input_mt_init_slots(input, td->maxcontacts, td->mt_flags); 72176f5902aSHenrik Rydberg 72276f5902aSHenrik Rydberg td->mt_flags = 0; 72376f5902aSHenrik Rydberg } 72476f5902aSHenrik Rydberg 7255519cab4SBenjamin Tissoires static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 7265519cab4SBenjamin Tissoires { 7272d93666eSBenjamin Tissoires int ret, i; 7285519cab4SBenjamin Tissoires struct mt_device *td; 7292d93666eSBenjamin Tissoires struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ 7302d93666eSBenjamin Tissoires 7312d93666eSBenjamin Tissoires for (i = 0; mt_classes[i].name ; i++) { 7322d93666eSBenjamin Tissoires if (id->driver_data == mt_classes[i].name) { 7332d93666eSBenjamin Tissoires mtclass = &(mt_classes[i]); 7342d93666eSBenjamin Tissoires break; 7352d93666eSBenjamin Tissoires } 7362d93666eSBenjamin Tissoires } 7375519cab4SBenjamin Tissoires 738d682bd7fSHenrik Rydberg /* This allows the driver to correctly support devices 739d682bd7fSHenrik Rydberg * that emit events over several HID messages. 740d682bd7fSHenrik Rydberg */ 741d682bd7fSHenrik Rydberg hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 7425519cab4SBenjamin Tissoires 7439498f954SBenjamin Tissoires td = kzalloc(sizeof(struct mt_device), GFP_KERNEL); 7445519cab4SBenjamin Tissoires if (!td) { 7455519cab4SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch data\n"); 7465519cab4SBenjamin Tissoires return -ENOMEM; 7475519cab4SBenjamin Tissoires } 748eec29e3dSBenjamin Tissoires td->mtclass = *mtclass; 7495519cab4SBenjamin Tissoires td->inputmode = -1; 75031ae9bddSBenjamin Tissoires td->maxcontact_report_id = -1; 7515519cab4SBenjamin Tissoires hid_set_drvdata(hdev, td); 7525519cab4SBenjamin Tissoires 7533ac36d15SBenjamin Tissoires td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL); 7543ac36d15SBenjamin Tissoires if (!td->fields) { 7553ac36d15SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch fields data\n"); 7563ac36d15SBenjamin Tissoires ret = -ENOMEM; 7573ac36d15SBenjamin Tissoires goto fail; 7583ac36d15SBenjamin Tissoires } 7593ac36d15SBenjamin Tissoires 76076f5902aSHenrik Rydberg if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) 76176f5902aSHenrik Rydberg td->serial_maybe = true; 76276f5902aSHenrik Rydberg 7635519cab4SBenjamin Tissoires ret = hid_parse(hdev); 7645519cab4SBenjamin Tissoires if (ret != 0) 7655519cab4SBenjamin Tissoires goto fail; 7665519cab4SBenjamin Tissoires 7675519cab4SBenjamin Tissoires ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 7682d93666eSBenjamin Tissoires if (ret) 7695519cab4SBenjamin Tissoires goto fail; 7705519cab4SBenjamin Tissoires 771eec29e3dSBenjamin Tissoires ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); 772eec29e3dSBenjamin Tissoires 77331ae9bddSBenjamin Tissoires mt_set_maxcontacts(hdev); 7745519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 7755519cab4SBenjamin Tissoires 7763ac36d15SBenjamin Tissoires kfree(td->fields); 7773ac36d15SBenjamin Tissoires td->fields = NULL; 7783ac36d15SBenjamin Tissoires 7795519cab4SBenjamin Tissoires return 0; 7805519cab4SBenjamin Tissoires 7815519cab4SBenjamin Tissoires fail: 7823ac36d15SBenjamin Tissoires kfree(td->fields); 7835519cab4SBenjamin Tissoires kfree(td); 7845519cab4SBenjamin Tissoires return ret; 7855519cab4SBenjamin Tissoires } 7865519cab4SBenjamin Tissoires 7875519cab4SBenjamin Tissoires #ifdef CONFIG_PM 7885519cab4SBenjamin Tissoires static int mt_reset_resume(struct hid_device *hdev) 7895519cab4SBenjamin Tissoires { 79031ae9bddSBenjamin Tissoires mt_set_maxcontacts(hdev); 7915519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 7925519cab4SBenjamin Tissoires return 0; 7935519cab4SBenjamin Tissoires } 794dfeefd10SScott Liu 795dfeefd10SScott Liu static int mt_resume(struct hid_device *hdev) 796dfeefd10SScott Liu { 797dfeefd10SScott Liu struct usb_interface *intf; 798dfeefd10SScott Liu struct usb_host_interface *interface; 799dfeefd10SScott Liu struct usb_device *dev; 800dfeefd10SScott Liu 801dfeefd10SScott Liu if (hdev->bus != BUS_USB) 802dfeefd10SScott Liu return 0; 803dfeefd10SScott Liu 804dfeefd10SScott Liu intf = to_usb_interface(hdev->dev.parent); 805dfeefd10SScott Liu interface = intf->cur_altsetting; 806dfeefd10SScott Liu dev = hid_to_usb_dev(hdev); 807dfeefd10SScott Liu 808dfeefd10SScott Liu /* Some Elan legacy devices require SET_IDLE to be set on resume. 809dfeefd10SScott Liu * It should be safe to send it to other devices too. 810dfeefd10SScott Liu * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ 811dfeefd10SScott Liu 812dfeefd10SScott Liu usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 813dfeefd10SScott Liu HID_REQ_SET_IDLE, 814dfeefd10SScott Liu USB_TYPE_CLASS | USB_RECIP_INTERFACE, 815dfeefd10SScott Liu 0, interface->desc.bInterfaceNumber, 816dfeefd10SScott Liu NULL, 0, USB_CTRL_SET_TIMEOUT); 817dfeefd10SScott Liu 818dfeefd10SScott Liu return 0; 819dfeefd10SScott Liu } 8205519cab4SBenjamin Tissoires #endif 8215519cab4SBenjamin Tissoires 8225519cab4SBenjamin Tissoires static void mt_remove(struct hid_device *hdev) 8235519cab4SBenjamin Tissoires { 8245519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 825eec29e3dSBenjamin Tissoires sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); 8265519cab4SBenjamin Tissoires hid_hw_stop(hdev); 8275519cab4SBenjamin Tissoires kfree(td); 8285519cab4SBenjamin Tissoires hid_set_drvdata(hdev, NULL); 8295519cab4SBenjamin Tissoires } 8305519cab4SBenjamin Tissoires 8315519cab4SBenjamin Tissoires static const struct hid_device_id mt_devices[] = { 8325519cab4SBenjamin Tissoires 833f786bba4SBenjamin Tissoires /* 3M panels */ 834f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 8352c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 836f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M1968) }, 837f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 8382c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 839f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M2256) }, 840c4fad877SBenjamin Tissoires { .driver_data = MT_CLS_3M, 8412c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 842c4fad877SBenjamin Tissoires USB_DEVICE_ID_3M3266) }, 843f786bba4SBenjamin Tissoires 844e6aac342SBenjamin Tissoires /* ActionStar panels */ 845e6aac342SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 8462c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, 847e6aac342SBenjamin Tissoires USB_DEVICE_ID_ACTIONSTAR_1011) }, 848e6aac342SBenjamin Tissoires 849b1057124SBenjamin Tissoires /* Atmel panels */ 850b1057124SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 8512c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 852b1057124SBenjamin Tissoires USB_DEVICE_ID_ATMEL_MULTITOUCH) }, 853841cb157SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 8542c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 855841cb157SBenjamin Tissoires USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, 856b1057124SBenjamin Tissoires 8579ed32695SJiri Kosina /* Baanto multitouch devices */ 8589ed32695SJiri Kosina { .driver_data = MT_CLS_DEFAULT, 85916b79bb8SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, 8609ed32695SJiri Kosina USB_DEVICE_ID_BAANTO_MT_190W2) }, 861a841b62cSBenjamin Tissoires /* Cando panels */ 862a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8632c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 864a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, 865a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8662c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 867a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, 868a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8692c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 870a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, 871a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8722c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 873a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, 874a841b62cSBenjamin Tissoires 875942fd422SAustin Zhang /* Chunghwa Telecom touch panels */ 876942fd422SAustin Zhang { .driver_data = MT_CLS_DEFAULT, 8772c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, 878942fd422SAustin Zhang USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, 879942fd422SAustin Zhang 88079603dc9SBenjamin Tissoires /* CVTouch panels */ 88179603dc9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 8822c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, 88379603dc9SBenjamin Tissoires USB_DEVICE_ID_CVTOUCH_SCREEN) }, 88479603dc9SBenjamin Tissoires 885a3b5e577SBenjamin Tissoires /* Cypress panel */ 886a3b5e577SBenjamin Tissoires { .driver_data = MT_CLS_CYPRESS, 887a3b5e577SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, 888a3b5e577SBenjamin Tissoires USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, 889a3b5e577SBenjamin Tissoires 89022408283SBenjamin Tissoires /* eGalax devices (resistive) */ 89122408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8922c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 893e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, 89422408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8952c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 896e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, 89722408283SBenjamin Tissoires 89822408283SBenjamin Tissoires /* eGalax devices (capacitive) */ 89922408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 9002c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 901e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, 902fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9032c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 904fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) }, 905fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9062c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 907fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) }, 908fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9092c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 910fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, 9112ce09df4SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9122c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 9132ce09df4SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) }, 91422408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 9152c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 916e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, 917fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9182c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 919fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) }, 92022408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 9212c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 922e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, 923fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9242c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 925fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) }, 9261fd8f047SChris Bagwell { .driver_data = MT_CLS_EGALAX, 9272c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 92866f06127SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, 92966f06127SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 9302c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 931bb9ff210SMarek Vasut USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, 9321b723e8dSBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9332c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 934fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, 935fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 9362c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 937ae01c9e5SThierry Reding USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) }, 938ae01c9e5SThierry Reding { .driver_data = MT_CLS_EGALAX_SERIAL, 939ae01c9e5SThierry Reding MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 940e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, 9413d77104aSJiri Kosina { .driver_data = MT_CLS_EGALAX, 9423d77104aSJiri Kosina HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 9433d77104aSJiri Kosina USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, 9443d77104aSJiri Kosina { .driver_data = MT_CLS_EGALAX, 9453d77104aSJiri Kosina HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 9463d77104aSJiri Kosina USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) }, 9473d77104aSJiri Kosina { .driver_data = MT_CLS_EGALAX, 9483d77104aSJiri Kosina HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 9493d77104aSJiri Kosina USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) }, 95022408283SBenjamin Tissoires 951c04abeefSBenjamin Tissoires /* Elo TouchSystems IntelliTouch Plus panel */ 952c04abeefSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, 9532c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ELO, 954c04abeefSBenjamin Tissoires USB_DEVICE_ID_ELO_TS2515) }, 955c04abeefSBenjamin Tissoires 95677723e3bSHenrik Rydberg /* Flatfrog Panels */ 95777723e3bSHenrik Rydberg { .driver_data = MT_CLS_FLATFROG, 95877723e3bSHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, 95977723e3bSHenrik Rydberg USB_DEVICE_ID_MULTITOUCH_3200) }, 96077723e3bSHenrik Rydberg 9615572da08SBenjamin Tissoires /* GeneralTouch panel */ 962f5ff4e1eSXianhan Yu { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, 9632c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 9645572da08SBenjamin Tissoires USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, 965f5ff4e1eSXianhan Yu { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, 966f5ff4e1eSXianhan Yu MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 967f5ff4e1eSXianhan Yu USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, 9685572da08SBenjamin Tissoires 9694d5df5d1SAndreas Nielsen /* Gametel game controller */ 9704d5df5d1SAndreas Nielsen { .driver_data = MT_CLS_DEFAULT, 9712c2110e9SHenrik Rydberg MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL, 9724d5df5d1SAndreas Nielsen USB_DEVICE_ID_GAMETEL_MT_MODE) }, 9734d5df5d1SAndreas Nielsen 974ee0fbd14SBenjamin Tissoires /* GoodTouch panels */ 975ee0fbd14SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 9762c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, 977ee0fbd14SBenjamin Tissoires USB_DEVICE_ID_GOODTOUCH_000f) }, 978ee0fbd14SBenjamin Tissoires 97954580365SBenjamin Tissoires /* Hanvon panels */ 98054580365SBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 9812c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, 98254580365SBenjamin Tissoires USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, 98354580365SBenjamin Tissoires 984a062cc5aSStephane Chatty /* Ideacom panel */ 985a062cc5aSStephane Chatty { .driver_data = MT_CLS_SERIAL, 9862c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, 987a062cc5aSStephane Chatty USB_DEVICE_ID_IDEACOM_IDC6650) }, 98871078b0dSBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 9892c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, 99071078b0dSBenjamin Tissoires USB_DEVICE_ID_IDEACOM_IDC6651) }, 991a062cc5aSStephane Chatty 9924e61f0d7SAustin Zhang /* Ilitek dual touch panel */ 9934e61f0d7SAustin Zhang { .driver_data = MT_CLS_DEFAULT, 9942c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, 9954e61f0d7SAustin Zhang USB_DEVICE_ID_ILITEK_MULTITOUCH) }, 9964e61f0d7SAustin Zhang 9974dfcced8SBenjamin Tissoires /* IRTOUCH panels */ 9984dfcced8SBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 9992c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, 10004dfcced8SBenjamin Tissoires USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, 10014dfcced8SBenjamin Tissoires 1002c50bb1a4SJeff Brown /* LG Display panels */ 1003c50bb1a4SJeff Brown { .driver_data = MT_CLS_DEFAULT, 10042c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_LG, 1005c50bb1a4SJeff Brown USB_DEVICE_ID_LG_MULTITOUCH) }, 1006c50bb1a4SJeff Brown 1007df167c4aSBenjamin Tissoires /* Lumio panels */ 1008df167c4aSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 10092c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, 1010df167c4aSBenjamin Tissoires USB_DEVICE_ID_CRYSTALTOUCH) }, 1011c3ead6deSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 10122c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, 1013c3ead6deSBenjamin Tissoires USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, 1014df167c4aSBenjamin Tissoires 10154a6ee685SBenjamin Tissoires /* MosArt panels */ 10164a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 10172c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 10184a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUS_T91MT)}, 10194a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 10202c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 10214a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 10224a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 10232c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, 10244a6ee685SBenjamin Tissoires USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 10254a6ee685SBenjamin Tissoires 10262258e863SDenis Kovalev /* Panasonic panels */ 10272258e863SDenis Kovalev { .driver_data = MT_CLS_PANASONIC, 10282c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 10292258e863SDenis Kovalev USB_DEVICE_ID_PANABOARD_UBT780) }, 10302258e863SDenis Kovalev { .driver_data = MT_CLS_PANASONIC, 10312c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 10322258e863SDenis Kovalev USB_DEVICE_ID_PANABOARD_UBT880) }, 10332258e863SDenis Kovalev 10344db703eaSAustin Hendrix /* Novatek Panel */ 10354db703eaSAustin Hendrix { .driver_data = MT_CLS_DEFAULT, 10364380d819SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, 10374db703eaSAustin Hendrix USB_DEVICE_ID_NOVATEK_PCT) }, 10384db703eaSAustin Hendrix 10396ab3a9a6SJohn Sung /* PenMount panels */ 10406ab3a9a6SJohn Sung { .driver_data = MT_CLS_CONFIDENCE, 10412c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, 10426ab3a9a6SJohn Sung USB_DEVICE_ID_PENMOUNT_PCI) }, 10436ab3a9a6SJohn Sung 1044b7ea95ffSAaron Tian /* PixArt optical touch screen */ 1045b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 10462c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 1047b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) }, 1048b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 10492c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 1050b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) }, 1051b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 10522c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 1053b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) }, 1054b7ea95ffSAaron Tian 10555519cab4SBenjamin Tissoires /* PixCir-based panels */ 10561e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 10572c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_HANVON, 10585519cab4SBenjamin Tissoires USB_DEVICE_ID_HANVON_MULTITOUCH) }, 10591e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 10602c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 10615519cab4SBenjamin Tissoires USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, 10625519cab4SBenjamin Tissoires 10635e7ea11fSBenjamin Tissoires /* Quanta-based panels */ 10645e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 10652c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 10665e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, 10675e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 10682c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 10695e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, 10705e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 10712c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 10725e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) }, 10735e7ea11fSBenjamin Tissoires 1074043b403aSBenjamin Tissoires /* Stantum panels */ 1075bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 10762c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM, 1077043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP)}, 1078bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 10792c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, 1080043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_STM)}, 1081bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 10822c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, 1083043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_SITRONIX)}, 1084043b403aSBenjamin Tissoires 1085847672cdSBenjamin Tissoires /* TopSeed panels */ 1086847672cdSBenjamin Tissoires { .driver_data = MT_CLS_TOPSEED, 10872c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, 1088847672cdSBenjamin Tissoires USB_DEVICE_ID_TOPSEED2_PERIPAD_701) }, 1089847672cdSBenjamin Tissoires 10905e74e56dSBenjamin Tissoires /* Touch International panels */ 10915e74e56dSBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 10922c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, 10935e74e56dSBenjamin Tissoires USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, 10945e74e56dSBenjamin Tissoires 1095617b64f9SBenjamin Tissoires /* Unitec panels */ 1096617b64f9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 10972c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 1098617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, 1099617b64f9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 11002c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 1101617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, 1102bc8a2a9bSice chien /* XAT */ 1103bc8a2a9bSice chien { .driver_data = MT_CLS_DEFAULT, 11042c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XAT, 1105bc8a2a9bSice chien USB_DEVICE_ID_XAT_CSR) }, 1106617b64f9SBenjamin Tissoires 110711576c61SMasatoshi Hoshikawa /* Xiroku */ 110811576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11092c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 111011576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX) }, 111111576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11122c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 111311576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX) }, 111411576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11152c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 111611576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR) }, 111711576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11182c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 111911576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX1) }, 112011576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11212c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 112211576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX1) }, 112311576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11242c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 112511576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR1) }, 112611576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11272c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 112811576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX2) }, 112911576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11302c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 113111576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX2) }, 113211576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 11332c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 113411576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR2) }, 113511576c61SMasatoshi Hoshikawa 113682d06982SBenjamin Tissoires /* Zytronic panels */ 113782d06982SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 113882d06982SBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC, 113982d06982SBenjamin Tissoires USB_DEVICE_ID_ZYTRONIC_ZXY100) }, 114082d06982SBenjamin Tissoires 11414fa3a583SHenrik Rydberg /* Generic MT device */ 11424fa3a583SHenrik Rydberg { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, 11435519cab4SBenjamin Tissoires { } 11445519cab4SBenjamin Tissoires }; 11455519cab4SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, mt_devices); 11465519cab4SBenjamin Tissoires 11475519cab4SBenjamin Tissoires static const struct hid_usage_id mt_grabbed_usages[] = { 11485519cab4SBenjamin Tissoires { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 11495519cab4SBenjamin Tissoires { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 11505519cab4SBenjamin Tissoires }; 11515519cab4SBenjamin Tissoires 11525519cab4SBenjamin Tissoires static struct hid_driver mt_driver = { 11535519cab4SBenjamin Tissoires .name = "hid-multitouch", 11545519cab4SBenjamin Tissoires .id_table = mt_devices, 11555519cab4SBenjamin Tissoires .probe = mt_probe, 11565519cab4SBenjamin Tissoires .remove = mt_remove, 11575519cab4SBenjamin Tissoires .input_mapping = mt_input_mapping, 11585519cab4SBenjamin Tissoires .input_mapped = mt_input_mapped, 115976f5902aSHenrik Rydberg .input_configured = mt_input_configured, 11605519cab4SBenjamin Tissoires .feature_mapping = mt_feature_mapping, 11615519cab4SBenjamin Tissoires .usage_table = mt_grabbed_usages, 11625519cab4SBenjamin Tissoires .event = mt_event, 11635519cab4SBenjamin Tissoires #ifdef CONFIG_PM 11645519cab4SBenjamin Tissoires .reset_resume = mt_reset_resume, 1165dfeefd10SScott Liu .resume = mt_resume, 11665519cab4SBenjamin Tissoires #endif 11675519cab4SBenjamin Tissoires }; 11685519cab4SBenjamin Tissoires 11695519cab4SBenjamin Tissoires static int __init mt_init(void) 11705519cab4SBenjamin Tissoires { 11715519cab4SBenjamin Tissoires return hid_register_driver(&mt_driver); 11725519cab4SBenjamin Tissoires } 11735519cab4SBenjamin Tissoires 11745519cab4SBenjamin Tissoires static void __exit mt_exit(void) 11755519cab4SBenjamin Tissoires { 11765519cab4SBenjamin Tissoires hid_unregister_driver(&mt_driver); 11775519cab4SBenjamin Tissoires } 11785519cab4SBenjamin Tissoires 11795519cab4SBenjamin Tissoires module_init(mt_init); 11805519cab4SBenjamin Tissoires module_exit(mt_exit); 1181