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) 545519cab4SBenjamin Tissoires 555519cab4SBenjamin Tissoires struct mt_slot { 565519cab4SBenjamin Tissoires __s32 x, y, p, w, h; 575519cab4SBenjamin Tissoires __s32 contactid; /* the device ContactID assigned to this slot */ 585519cab4SBenjamin Tissoires bool touch_state; /* is the touch valid? */ 595519cab4SBenjamin Tissoires bool seen_in_this_frame;/* has this slot been updated */ 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 */ 95*76f5902aSHenrik Rydberg bool serial_maybe; /* need to check for serial protocol */ 965519cab4SBenjamin Tissoires bool curvalid; /* is the current contact valid? */ 975519cab4SBenjamin Tissoires struct mt_slot *slots; 98*76f5902aSHenrik Rydberg unsigned mt_flags; /* flags to pass to input-mt */ 995519cab4SBenjamin Tissoires }; 1005519cab4SBenjamin Tissoires 1015519cab4SBenjamin Tissoires /* classes of device behavior */ 10222408283SBenjamin Tissoires #define MT_CLS_DEFAULT 0x0001 10322408283SBenjamin Tissoires 104a062cc5aSStephane Chatty #define MT_CLS_SERIAL 0x0002 105a062cc5aSStephane Chatty #define MT_CLS_CONFIDENCE 0x0003 1065e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_CONTACT_ID 0x0004 1075e7ea11fSBenjamin Tissoires #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 1085e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 1095e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 1105e7ea11fSBenjamin Tissoires #define MT_CLS_DUAL_NSMU_CONTACTID 0x0008 111b7ea95ffSAaron Tian #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 11222408283SBenjamin Tissoires 11322408283SBenjamin Tissoires /* vendor specific classes */ 11422408283SBenjamin Tissoires #define MT_CLS_3M 0x0101 11522408283SBenjamin Tissoires #define MT_CLS_CYPRESS 0x0102 11622408283SBenjamin Tissoires #define MT_CLS_EGALAX 0x0103 1171b723e8dSBenjamin Tissoires #define MT_CLS_EGALAX_SERIAL 0x0104 118847672cdSBenjamin Tissoires #define MT_CLS_TOPSEED 0x0105 1192258e863SDenis Kovalev #define MT_CLS_PANASONIC 0x0106 1205519cab4SBenjamin Tissoires 1219498f954SBenjamin Tissoires #define MT_DEFAULT_MAXCONTACT 10 1229498f954SBenjamin Tissoires 1232c2110e9SHenrik Rydberg #define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) 1242c2110e9SHenrik Rydberg #define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) 1252c2110e9SHenrik Rydberg 1265519cab4SBenjamin Tissoires /* 1275519cab4SBenjamin Tissoires * these device-dependent functions determine what slot corresponds 1285519cab4SBenjamin Tissoires * to a valid contact that was just read. 1295519cab4SBenjamin Tissoires */ 1305519cab4SBenjamin Tissoires 131a3b5e577SBenjamin Tissoires static int cypress_compute_slot(struct mt_device *td) 132a3b5e577SBenjamin Tissoires { 133a3b5e577SBenjamin Tissoires if (td->curdata.contactid != 0 || td->num_received == 0) 134a3b5e577SBenjamin Tissoires return td->curdata.contactid; 135a3b5e577SBenjamin Tissoires else 136a3b5e577SBenjamin Tissoires return -1; 137a3b5e577SBenjamin Tissoires } 138a3b5e577SBenjamin Tissoires 1395519cab4SBenjamin Tissoires static int find_slot_from_contactid(struct mt_device *td) 1405519cab4SBenjamin Tissoires { 1415519cab4SBenjamin Tissoires int i; 1429498f954SBenjamin Tissoires for (i = 0; i < td->maxcontacts; ++i) { 1435519cab4SBenjamin Tissoires if (td->slots[i].contactid == td->curdata.contactid && 1445519cab4SBenjamin Tissoires td->slots[i].touch_state) 1455519cab4SBenjamin Tissoires return i; 1465519cab4SBenjamin Tissoires } 1479498f954SBenjamin Tissoires for (i = 0; i < td->maxcontacts; ++i) { 1485519cab4SBenjamin Tissoires if (!td->slots[i].seen_in_this_frame && 1495519cab4SBenjamin Tissoires !td->slots[i].touch_state) 1505519cab4SBenjamin Tissoires return i; 1515519cab4SBenjamin Tissoires } 1525519cab4SBenjamin Tissoires /* should not occurs. If this happens that means 1535519cab4SBenjamin Tissoires * that the device sent more touches that it says 1545519cab4SBenjamin Tissoires * in the report descriptor. It is ignored then. */ 1552d93666eSBenjamin Tissoires return -1; 1565519cab4SBenjamin Tissoires } 1575519cab4SBenjamin Tissoires 158b3c21d2cSJiri Kosina static struct mt_class mt_classes[] = { 1592d93666eSBenjamin Tissoires { .name = MT_CLS_DEFAULT, 1609498f954SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, 161a062cc5aSStephane Chatty { .name = MT_CLS_SERIAL, 162a062cc5aSStephane Chatty .quirks = MT_QUIRK_ALWAYS_VALID}, 16322408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE, 16422408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, 1655e7ea11fSBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_CONTACT_ID, 1665e7ea11fSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 1675e7ea11fSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID }, 16822408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_MINUS_ONE, 16922408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 17022408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, 1711e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTID, 1722d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 1732d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 1742d93666eSBenjamin Tissoires .maxcontacts = 2 }, 1751e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 1762d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 1772d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTNUMBER, 1782d93666eSBenjamin Tissoires .maxcontacts = 2 }, 17922408283SBenjamin Tissoires { .name = MT_CLS_DUAL_NSMU_CONTACTID, 18022408283SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 18122408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 18222408283SBenjamin Tissoires .maxcontacts = 2 }, 183b7ea95ffSAaron Tian { .name = MT_CLS_INRANGE_CONTACTNUMBER, 184b7ea95ffSAaron Tian .quirks = MT_QUIRK_VALID_IS_INRANGE | 185b7ea95ffSAaron Tian MT_QUIRK_SLOT_IS_CONTACTNUMBER }, 18622408283SBenjamin Tissoires 18722408283SBenjamin Tissoires /* 18822408283SBenjamin Tissoires * vendor specific classes 18922408283SBenjamin Tissoires */ 19022408283SBenjamin Tissoires { .name = MT_CLS_3M, 19122408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 19222408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 19322408283SBenjamin Tissoires .sn_move = 2048, 19422408283SBenjamin Tissoires .sn_width = 128, 19522408283SBenjamin Tissoires .sn_height = 128 }, 1962d93666eSBenjamin Tissoires { .name = MT_CLS_CYPRESS, 1972d93666eSBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 1982d93666eSBenjamin Tissoires MT_QUIRK_CYPRESS, 1992d93666eSBenjamin Tissoires .maxcontacts = 10 }, 2004875ac11SRichard Nauber { .name = MT_CLS_EGALAX, 2014875ac11SRichard Nauber .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 2022261bb9fSBenjamin Tissoires MT_QUIRK_VALID_IS_INRANGE, 2034875ac11SRichard Nauber .sn_move = 4096, 2044875ac11SRichard Nauber .sn_pressure = 32, 2054875ac11SRichard Nauber }, 2061b723e8dSBenjamin Tissoires { .name = MT_CLS_EGALAX_SERIAL, 2071b723e8dSBenjamin Tissoires .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 2081b723e8dSBenjamin Tissoires MT_QUIRK_ALWAYS_VALID, 2092d93666eSBenjamin Tissoires .sn_move = 4096, 2102d93666eSBenjamin Tissoires .sn_pressure = 32, 2112d93666eSBenjamin Tissoires }, 212847672cdSBenjamin Tissoires { .name = MT_CLS_TOPSEED, 213847672cdSBenjamin Tissoires .quirks = MT_QUIRK_ALWAYS_VALID, 214847672cdSBenjamin Tissoires .is_indirect = true, 215847672cdSBenjamin Tissoires .maxcontacts = 2, 216847672cdSBenjamin Tissoires }, 2172258e863SDenis Kovalev { .name = MT_CLS_PANASONIC, 2182258e863SDenis Kovalev .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, 2192258e863SDenis Kovalev .maxcontacts = 4 }, 220043b403aSBenjamin Tissoires 2212d93666eSBenjamin Tissoires { } 2225519cab4SBenjamin Tissoires }; 2235519cab4SBenjamin Tissoires 224eec29e3dSBenjamin Tissoires static ssize_t mt_show_quirks(struct device *dev, 225eec29e3dSBenjamin Tissoires struct device_attribute *attr, 226eec29e3dSBenjamin Tissoires char *buf) 227eec29e3dSBenjamin Tissoires { 228eec29e3dSBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 229eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 230eec29e3dSBenjamin Tissoires 231eec29e3dSBenjamin Tissoires return sprintf(buf, "%u\n", td->mtclass.quirks); 232eec29e3dSBenjamin Tissoires } 233eec29e3dSBenjamin Tissoires 234eec29e3dSBenjamin Tissoires static ssize_t mt_set_quirks(struct device *dev, 235eec29e3dSBenjamin Tissoires struct device_attribute *attr, 236eec29e3dSBenjamin Tissoires const char *buf, size_t count) 237eec29e3dSBenjamin Tissoires { 238eec29e3dSBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 239eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 240eec29e3dSBenjamin Tissoires 241eec29e3dSBenjamin Tissoires unsigned long val; 242eec29e3dSBenjamin Tissoires 243eec29e3dSBenjamin Tissoires if (kstrtoul(buf, 0, &val)) 244eec29e3dSBenjamin Tissoires return -EINVAL; 245eec29e3dSBenjamin Tissoires 246eec29e3dSBenjamin Tissoires td->mtclass.quirks = val; 247eec29e3dSBenjamin Tissoires 248eec29e3dSBenjamin Tissoires return count; 249eec29e3dSBenjamin Tissoires } 250eec29e3dSBenjamin Tissoires 251eec29e3dSBenjamin Tissoires static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); 252eec29e3dSBenjamin Tissoires 253eec29e3dSBenjamin Tissoires static struct attribute *sysfs_attrs[] = { 254eec29e3dSBenjamin Tissoires &dev_attr_quirks.attr, 255eec29e3dSBenjamin Tissoires NULL 256eec29e3dSBenjamin Tissoires }; 257eec29e3dSBenjamin Tissoires 258eec29e3dSBenjamin Tissoires static struct attribute_group mt_attribute_group = { 259eec29e3dSBenjamin Tissoires .attrs = sysfs_attrs 260eec29e3dSBenjamin Tissoires }; 261eec29e3dSBenjamin Tissoires 262f635bd11SHenrik Rydberg static void mt_feature_mapping(struct hid_device *hdev, 2635519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage) 2645519cab4SBenjamin Tissoires { 2655519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 2664aceed37SBenjamin Tissoires int i; 2679498f954SBenjamin Tissoires 2689498f954SBenjamin Tissoires switch (usage->hid) { 2699498f954SBenjamin Tissoires case HID_DG_INPUTMODE: 2705519cab4SBenjamin Tissoires td->inputmode = field->report->id; 2714aceed37SBenjamin Tissoires td->inputmode_index = 0; /* has to be updated below */ 2724aceed37SBenjamin Tissoires 2734aceed37SBenjamin Tissoires for (i=0; i < field->maxusage; i++) { 2744aceed37SBenjamin Tissoires if (field->usage[i].hid == usage->hid) { 2754aceed37SBenjamin Tissoires td->inputmode_index = i; 2764aceed37SBenjamin Tissoires break; 2774aceed37SBenjamin Tissoires } 2784aceed37SBenjamin Tissoires } 2794aceed37SBenjamin Tissoires 2809498f954SBenjamin Tissoires break; 2819498f954SBenjamin Tissoires case HID_DG_CONTACTMAX: 28231ae9bddSBenjamin Tissoires td->maxcontact_report_id = field->report->id; 2839498f954SBenjamin Tissoires td->maxcontacts = field->value[0]; 284eec29e3dSBenjamin Tissoires if (td->mtclass.maxcontacts) 2859498f954SBenjamin Tissoires /* check if the maxcontacts is given by the class */ 286eec29e3dSBenjamin Tissoires td->maxcontacts = td->mtclass.maxcontacts; 2879498f954SBenjamin Tissoires 2889498f954SBenjamin Tissoires break; 2895519cab4SBenjamin Tissoires } 2905519cab4SBenjamin Tissoires } 2915519cab4SBenjamin Tissoires 2925519cab4SBenjamin Tissoires static void set_abs(struct input_dev *input, unsigned int code, 2935519cab4SBenjamin Tissoires struct hid_field *field, int snratio) 2945519cab4SBenjamin Tissoires { 2955519cab4SBenjamin Tissoires int fmin = field->logical_minimum; 2965519cab4SBenjamin Tissoires int fmax = field->logical_maximum; 2975519cab4SBenjamin Tissoires int fuzz = snratio ? (fmax - fmin) / snratio : 0; 2985519cab4SBenjamin Tissoires input_set_abs_params(input, code, fmin, fmax, fuzz, 0); 2995519cab4SBenjamin Tissoires } 3005519cab4SBenjamin Tissoires 3013ac36d15SBenjamin Tissoires static void mt_store_field(struct hid_usage *usage, struct mt_device *td, 302ed9d5c96SBenjamin Tissoires struct hid_input *hi) 303ed9d5c96SBenjamin Tissoires { 3043ac36d15SBenjamin Tissoires struct mt_fields *f = td->fields; 3053ac36d15SBenjamin Tissoires 3063ac36d15SBenjamin Tissoires if (f->length >= HID_MAX_FIELDS) 3073ac36d15SBenjamin Tissoires return; 3083ac36d15SBenjamin Tissoires 3093ac36d15SBenjamin Tissoires f->usages[f->length++] = usage->hid; 310ed9d5c96SBenjamin Tissoires } 311ed9d5c96SBenjamin Tissoires 3125519cab4SBenjamin Tissoires static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 3135519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 3145519cab4SBenjamin Tissoires unsigned long **bit, int *max) 3155519cab4SBenjamin Tissoires { 3165519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 317eec29e3dSBenjamin Tissoires struct mt_class *cls = &td->mtclass; 318c2ef8f21SBenjamin Tissoires int code; 3194875ac11SRichard Nauber 320658d4aedSJeff Brown /* Only map fields from TouchScreen or TouchPad collections. 321658d4aedSJeff Brown * We need to ignore fields that belong to other collections 322658d4aedSJeff Brown * such as Mouse that might have the same GenericDesktop usages. */ 323658d4aedSJeff Brown if (field->application == HID_DG_TOUCHSCREEN) 324*76f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_DIRECT; 325c2ef8f21SBenjamin Tissoires else if (field->application != HID_DG_TOUCHPAD) 326658d4aedSJeff Brown return 0; 327658d4aedSJeff Brown 328*76f5902aSHenrik Rydberg /* 329*76f5902aSHenrik Rydberg * Model touchscreens providing buttons as touchpads. 330c2ef8f21SBenjamin Tissoires */ 331c2ef8f21SBenjamin Tissoires if (field->application == HID_DG_TOUCHPAD || 332*76f5902aSHenrik Rydberg (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) 333*76f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_POINTER; 334c2ef8f21SBenjamin Tissoires 3352261bb9fSBenjamin Tissoires /* eGalax devices provide a Digitizer.Stylus input which overrides 3362261bb9fSBenjamin Tissoires * the correct Digitizers.Finger X/Y ranges. 3372261bb9fSBenjamin Tissoires * Let's just ignore this input. */ 3382261bb9fSBenjamin Tissoires if (field->physical == HID_DG_STYLUS) 3392261bb9fSBenjamin Tissoires return -1; 3402261bb9fSBenjamin Tissoires 3415519cab4SBenjamin Tissoires switch (usage->hid & HID_USAGE_PAGE) { 3425519cab4SBenjamin Tissoires 3435519cab4SBenjamin Tissoires case HID_UP_GENDESK: 3445519cab4SBenjamin Tissoires switch (usage->hid) { 3455519cab4SBenjamin Tissoires case HID_GD_X: 3465519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3475519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_X); 3485519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_X, field, 3495519cab4SBenjamin Tissoires cls->sn_move); 3503ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3512955caedSBenjamin Tissoires td->last_field_index = field->index; 3525519cab4SBenjamin Tissoires return 1; 3535519cab4SBenjamin Tissoires case HID_GD_Y: 3545519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3555519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_Y); 3565519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_Y, field, 3575519cab4SBenjamin Tissoires cls->sn_move); 3583ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3592955caedSBenjamin Tissoires td->last_field_index = field->index; 3605519cab4SBenjamin Tissoires return 1; 3615519cab4SBenjamin Tissoires } 3625519cab4SBenjamin Tissoires return 0; 3635519cab4SBenjamin Tissoires 3645519cab4SBenjamin Tissoires case HID_UP_DIGITIZER: 3655519cab4SBenjamin Tissoires switch (usage->hid) { 3665519cab4SBenjamin Tissoires case HID_DG_INRANGE: 3673ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3682955caedSBenjamin Tissoires td->last_field_index = field->index; 3695519cab4SBenjamin Tissoires return 1; 3705519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 3713ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3722955caedSBenjamin Tissoires td->last_field_index = field->index; 3735519cab4SBenjamin Tissoires return 1; 3745519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 3755519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); 3765519cab4SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, BTN_TOUCH); 3773ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3782955caedSBenjamin Tissoires td->last_field_index = field->index; 3795519cab4SBenjamin Tissoires return 1; 3805519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 3813ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3822955caedSBenjamin Tissoires td->last_field_index = field->index; 3839e87f22aSBenjamin Tissoires td->touches_by_report++; 3845519cab4SBenjamin Tissoires return 1; 3855519cab4SBenjamin Tissoires case HID_DG_WIDTH: 3865519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3875519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MAJOR); 388f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, 389f786bba4SBenjamin Tissoires cls->sn_width); 3903ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 3912955caedSBenjamin Tissoires td->last_field_index = field->index; 3925519cab4SBenjamin Tissoires return 1; 3935519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 3945519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3955519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MINOR); 396f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, 397f786bba4SBenjamin Tissoires cls->sn_height); 3981e648a13SBenjamin Tissoires input_set_abs_params(hi->input, 3991e648a13SBenjamin Tissoires ABS_MT_ORIENTATION, 0, 1, 0, 0); 4003ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 4012955caedSBenjamin Tissoires td->last_field_index = field->index; 4025519cab4SBenjamin Tissoires return 1; 4035519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 4045519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 4055519cab4SBenjamin Tissoires EV_ABS, ABS_MT_PRESSURE); 4065519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_PRESSURE, field, 4075519cab4SBenjamin Tissoires cls->sn_pressure); 4083ac36d15SBenjamin Tissoires mt_store_field(usage, td, hi); 4092955caedSBenjamin Tissoires td->last_field_index = field->index; 4105519cab4SBenjamin Tissoires return 1; 4115519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 4122955caedSBenjamin Tissoires td->last_field_index = field->index; 4135519cab4SBenjamin Tissoires return 1; 4145519cab4SBenjamin Tissoires case HID_DG_CONTACTMAX: 4155519cab4SBenjamin Tissoires /* we don't set td->last_slot_field as contactcount and 4165519cab4SBenjamin Tissoires * contact max are global to the report */ 4172955caedSBenjamin Tissoires td->last_field_index = field->index; 4185519cab4SBenjamin Tissoires return -1; 4195519cab4SBenjamin Tissoires } 420c2ef8f21SBenjamin Tissoires case HID_DG_TOUCH: 421c2ef8f21SBenjamin Tissoires /* Legacy devices use TIPSWITCH and not TOUCH. 422c2ef8f21SBenjamin Tissoires * Let's just ignore this field. */ 423c2ef8f21SBenjamin Tissoires return -1; 4245519cab4SBenjamin Tissoires /* let hid-input decide for the others */ 4255519cab4SBenjamin Tissoires return 0; 4265519cab4SBenjamin Tissoires 427c2ef8f21SBenjamin Tissoires case HID_UP_BUTTON: 428c2ef8f21SBenjamin Tissoires code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); 429c2ef8f21SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, code); 430c2ef8f21SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, code); 431c2ef8f21SBenjamin Tissoires return 1; 432c2ef8f21SBenjamin Tissoires 4335519cab4SBenjamin Tissoires case 0xff000000: 4345519cab4SBenjamin Tissoires /* we do not want to map these: no input-oriented meaning */ 4355519cab4SBenjamin Tissoires return -1; 4365519cab4SBenjamin Tissoires } 4375519cab4SBenjamin Tissoires 4385519cab4SBenjamin Tissoires return 0; 4395519cab4SBenjamin Tissoires } 4405519cab4SBenjamin Tissoires 4415519cab4SBenjamin Tissoires static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, 4425519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 4435519cab4SBenjamin Tissoires unsigned long **bit, int *max) 4445519cab4SBenjamin Tissoires { 4455519cab4SBenjamin Tissoires if (usage->type == EV_KEY || usage->type == EV_ABS) 4465519cab4SBenjamin Tissoires set_bit(usage->type, hi->input->evbit); 4475519cab4SBenjamin Tissoires 4485519cab4SBenjamin Tissoires return -1; 4495519cab4SBenjamin Tissoires } 4505519cab4SBenjamin Tissoires 4515519cab4SBenjamin Tissoires static int mt_compute_slot(struct mt_device *td) 4525519cab4SBenjamin Tissoires { 453eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 4545519cab4SBenjamin Tissoires 4552d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) 4562d93666eSBenjamin Tissoires return td->curdata.contactid; 4575519cab4SBenjamin Tissoires 4582d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_CYPRESS) 459a3b5e577SBenjamin Tissoires return cypress_compute_slot(td); 460a3b5e577SBenjamin Tissoires 4612d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) 4622d93666eSBenjamin Tissoires return td->num_received; 4635572da08SBenjamin Tissoires 4644a6ee685SBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) 4654a6ee685SBenjamin Tissoires return td->curdata.contactid - 1; 4664a6ee685SBenjamin Tissoires 4675519cab4SBenjamin Tissoires return find_slot_from_contactid(td); 4685519cab4SBenjamin Tissoires } 4695519cab4SBenjamin Tissoires 4705519cab4SBenjamin Tissoires /* 4715519cab4SBenjamin Tissoires * this function is called when a whole contact has been processed, 4725519cab4SBenjamin Tissoires * so that it can assign it to a slot and store the data there 4735519cab4SBenjamin Tissoires */ 4745519cab4SBenjamin Tissoires static void mt_complete_slot(struct mt_device *td) 4755519cab4SBenjamin Tissoires { 4762d93666eSBenjamin Tissoires td->curdata.seen_in_this_frame = true; 4775519cab4SBenjamin Tissoires if (td->curvalid) { 4785519cab4SBenjamin Tissoires int slotnum = mt_compute_slot(td); 4795519cab4SBenjamin Tissoires 4809498f954SBenjamin Tissoires if (slotnum >= 0 && slotnum < td->maxcontacts) 4812d93666eSBenjamin Tissoires td->slots[slotnum] = td->curdata; 4825519cab4SBenjamin Tissoires } 4835519cab4SBenjamin Tissoires td->num_received++; 4845519cab4SBenjamin Tissoires } 4855519cab4SBenjamin Tissoires 4865519cab4SBenjamin Tissoires 4875519cab4SBenjamin Tissoires /* 4885519cab4SBenjamin Tissoires * this function is called when a whole packet has been received and processed, 4895519cab4SBenjamin Tissoires * so that it can decide what to send to the input layer. 4905519cab4SBenjamin Tissoires */ 4915519cab4SBenjamin Tissoires static void mt_emit_event(struct mt_device *td, struct input_dev *input) 4925519cab4SBenjamin Tissoires { 4935519cab4SBenjamin Tissoires int i; 4945519cab4SBenjamin Tissoires 4959498f954SBenjamin Tissoires for (i = 0; i < td->maxcontacts; ++i) { 4965519cab4SBenjamin Tissoires struct mt_slot *s = &(td->slots[i]); 497eec29e3dSBenjamin Tissoires if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && 4985519cab4SBenjamin Tissoires !s->seen_in_this_frame) { 4995519cab4SBenjamin Tissoires s->touch_state = false; 5005519cab4SBenjamin Tissoires } 5015519cab4SBenjamin Tissoires 5025519cab4SBenjamin Tissoires input_mt_slot(input, i); 5035519cab4SBenjamin Tissoires input_mt_report_slot_state(input, MT_TOOL_FINGER, 5045519cab4SBenjamin Tissoires s->touch_state); 5052d93666eSBenjamin Tissoires if (s->touch_state) { 506f786bba4SBenjamin Tissoires /* this finger is on the screen */ 507f786bba4SBenjamin Tissoires int wide = (s->w > s->h); 508f786bba4SBenjamin Tissoires /* divided by two to match visual scale of touch */ 509f786bba4SBenjamin Tissoires int major = max(s->w, s->h) >> 1; 510f786bba4SBenjamin Tissoires int minor = min(s->w, s->h) >> 1; 511f786bba4SBenjamin Tissoires 5125519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); 5135519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); 514f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); 5155519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); 516f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 517f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 5182d93666eSBenjamin Tissoires } 5195519cab4SBenjamin Tissoires s->seen_in_this_frame = false; 5205519cab4SBenjamin Tissoires 5215519cab4SBenjamin Tissoires } 5225519cab4SBenjamin Tissoires 523*76f5902aSHenrik Rydberg input_mt_sync_frame(input); 5245519cab4SBenjamin Tissoires input_sync(input); 5255519cab4SBenjamin Tissoires td->num_received = 0; 5265519cab4SBenjamin Tissoires } 5275519cab4SBenjamin Tissoires 5285519cab4SBenjamin Tissoires 5295519cab4SBenjamin Tissoires 5305519cab4SBenjamin Tissoires static int mt_event(struct hid_device *hid, struct hid_field *field, 5315519cab4SBenjamin Tissoires struct hid_usage *usage, __s32 value) 5325519cab4SBenjamin Tissoires { 5335519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 534eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 5355519cab4SBenjamin Tissoires 5369498f954SBenjamin Tissoires if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { 5375519cab4SBenjamin Tissoires switch (usage->hid) { 5385519cab4SBenjamin Tissoires case HID_DG_INRANGE: 539a062cc5aSStephane Chatty if (quirks & MT_QUIRK_ALWAYS_VALID) 540a062cc5aSStephane Chatty td->curvalid = true; 541a062cc5aSStephane Chatty else if (quirks & MT_QUIRK_VALID_IS_INRANGE) 5422d93666eSBenjamin Tissoires td->curvalid = value; 5435519cab4SBenjamin Tissoires break; 5445519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 5452d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 5465519cab4SBenjamin Tissoires td->curvalid = value; 5475519cab4SBenjamin Tissoires td->curdata.touch_state = value; 5485519cab4SBenjamin Tissoires break; 5495519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 5502d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) 5512d93666eSBenjamin Tissoires td->curvalid = value; 5525519cab4SBenjamin Tissoires break; 5535519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 5545519cab4SBenjamin Tissoires td->curdata.contactid = value; 5555519cab4SBenjamin Tissoires break; 5565519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 5575519cab4SBenjamin Tissoires td->curdata.p = value; 5585519cab4SBenjamin Tissoires break; 5595519cab4SBenjamin Tissoires case HID_GD_X: 5605519cab4SBenjamin Tissoires td->curdata.x = value; 5615519cab4SBenjamin Tissoires break; 5625519cab4SBenjamin Tissoires case HID_GD_Y: 5635519cab4SBenjamin Tissoires td->curdata.y = value; 5645519cab4SBenjamin Tissoires break; 5655519cab4SBenjamin Tissoires case HID_DG_WIDTH: 5665519cab4SBenjamin Tissoires td->curdata.w = value; 5675519cab4SBenjamin Tissoires break; 5685519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 5695519cab4SBenjamin Tissoires td->curdata.h = value; 5705519cab4SBenjamin Tissoires break; 5715519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 5725519cab4SBenjamin Tissoires /* 5732d93666eSBenjamin Tissoires * Includes multi-packet support where subsequent 5742d93666eSBenjamin Tissoires * packets are sent with zero contactcount. 5755519cab4SBenjamin Tissoires */ 5765519cab4SBenjamin Tissoires if (value) 5772d93666eSBenjamin Tissoires td->num_expected = value; 5785519cab4SBenjamin Tissoires break; 579c2ef8f21SBenjamin Tissoires case HID_DG_TOUCH: 580c2ef8f21SBenjamin Tissoires /* do nothing */ 581c2ef8f21SBenjamin Tissoires break; 5825519cab4SBenjamin Tissoires 5835519cab4SBenjamin Tissoires default: 5845519cab4SBenjamin Tissoires /* fallback to the generic hidinput handling */ 5855519cab4SBenjamin Tissoires return 0; 5865519cab4SBenjamin Tissoires } 5875519cab4SBenjamin Tissoires 5882258e863SDenis Kovalev if (usage->hid == td->last_slot_field) 5895519cab4SBenjamin Tissoires mt_complete_slot(td); 5905519cab4SBenjamin Tissoires 5915519cab4SBenjamin Tissoires if (field->index == td->last_field_index 5922d93666eSBenjamin Tissoires && td->num_received >= td->num_expected) 5935519cab4SBenjamin Tissoires mt_emit_event(td, field->hidinput->input); 5945519cab4SBenjamin Tissoires 5952d93666eSBenjamin Tissoires } 5962d93666eSBenjamin Tissoires 5975519cab4SBenjamin Tissoires /* we have handled the hidinput part, now remains hiddev */ 5985519cab4SBenjamin Tissoires if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 5995519cab4SBenjamin Tissoires hid->hiddev_hid_event(hid, field, usage, value); 6005519cab4SBenjamin Tissoires 6015519cab4SBenjamin Tissoires return 1; 6025519cab4SBenjamin Tissoires } 6035519cab4SBenjamin Tissoires 6045519cab4SBenjamin Tissoires static void mt_set_input_mode(struct hid_device *hdev) 6055519cab4SBenjamin Tissoires { 6065519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 6075519cab4SBenjamin Tissoires struct hid_report *r; 6085519cab4SBenjamin Tissoires struct hid_report_enum *re; 6095519cab4SBenjamin Tissoires 6105519cab4SBenjamin Tissoires if (td->inputmode < 0) 6115519cab4SBenjamin Tissoires return; 6125519cab4SBenjamin Tissoires 6135519cab4SBenjamin Tissoires re = &(hdev->report_enum[HID_FEATURE_REPORT]); 6145519cab4SBenjamin Tissoires r = re->report_id_hash[td->inputmode]; 6155519cab4SBenjamin Tissoires if (r) { 6164aceed37SBenjamin Tissoires r->field[0]->value[td->inputmode_index] = 0x02; 6175519cab4SBenjamin Tissoires usbhid_submit_report(hdev, r, USB_DIR_OUT); 6185519cab4SBenjamin Tissoires } 6195519cab4SBenjamin Tissoires } 6205519cab4SBenjamin Tissoires 62131ae9bddSBenjamin Tissoires static void mt_set_maxcontacts(struct hid_device *hdev) 62231ae9bddSBenjamin Tissoires { 62331ae9bddSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 62431ae9bddSBenjamin Tissoires struct hid_report *r; 62531ae9bddSBenjamin Tissoires struct hid_report_enum *re; 62631ae9bddSBenjamin Tissoires int fieldmax, max; 62731ae9bddSBenjamin Tissoires 62831ae9bddSBenjamin Tissoires if (td->maxcontact_report_id < 0) 62931ae9bddSBenjamin Tissoires return; 63031ae9bddSBenjamin Tissoires 63131ae9bddSBenjamin Tissoires if (!td->mtclass.maxcontacts) 63231ae9bddSBenjamin Tissoires return; 63331ae9bddSBenjamin Tissoires 63431ae9bddSBenjamin Tissoires re = &hdev->report_enum[HID_FEATURE_REPORT]; 63531ae9bddSBenjamin Tissoires r = re->report_id_hash[td->maxcontact_report_id]; 63631ae9bddSBenjamin Tissoires if (r) { 63731ae9bddSBenjamin Tissoires max = td->mtclass.maxcontacts; 63831ae9bddSBenjamin Tissoires fieldmax = r->field[0]->logical_maximum; 63931ae9bddSBenjamin Tissoires max = min(fieldmax, max); 64031ae9bddSBenjamin Tissoires if (r->field[0]->value[0] != max) { 64131ae9bddSBenjamin Tissoires r->field[0]->value[0] = max; 64231ae9bddSBenjamin Tissoires usbhid_submit_report(hdev, r, USB_DIR_OUT); 64331ae9bddSBenjamin Tissoires } 64431ae9bddSBenjamin Tissoires } 64531ae9bddSBenjamin Tissoires } 64631ae9bddSBenjamin Tissoires 6474fa3a583SHenrik Rydberg static void mt_post_parse_default_settings(struct mt_device *td) 6484fa3a583SHenrik Rydberg { 6494fa3a583SHenrik Rydberg __s32 quirks = td->mtclass.quirks; 6504fa3a583SHenrik Rydberg 6514fa3a583SHenrik Rydberg /* unknown serial device needs special quirks */ 6524fa3a583SHenrik Rydberg if (td->touches_by_report == 1) { 6534fa3a583SHenrik Rydberg quirks |= MT_QUIRK_ALWAYS_VALID; 6544fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; 6554fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_INRANGE; 6564fa3a583SHenrik Rydberg quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; 6574fa3a583SHenrik Rydberg } 6584fa3a583SHenrik Rydberg 6594fa3a583SHenrik Rydberg td->mtclass.quirks = quirks; 6604fa3a583SHenrik Rydberg } 6614fa3a583SHenrik Rydberg 6623ac36d15SBenjamin Tissoires static void mt_post_parse(struct mt_device *td) 6633ac36d15SBenjamin Tissoires { 6643ac36d15SBenjamin Tissoires struct mt_fields *f = td->fields; 6653ac36d15SBenjamin Tissoires 6663ac36d15SBenjamin Tissoires if (td->touches_by_report > 0) { 6673ac36d15SBenjamin Tissoires int field_count_per_touch = f->length / td->touches_by_report; 6683ac36d15SBenjamin Tissoires td->last_slot_field = f->usages[field_count_per_touch - 1]; 6693ac36d15SBenjamin Tissoires } 6703ac36d15SBenjamin Tissoires } 6713ac36d15SBenjamin Tissoires 672*76f5902aSHenrik Rydberg static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) 673*76f5902aSHenrik Rydberg 674*76f5902aSHenrik Rydberg { 675*76f5902aSHenrik Rydberg struct mt_device *td = hid_get_drvdata(hdev); 676*76f5902aSHenrik Rydberg struct mt_class *cls = &td->mtclass; 677*76f5902aSHenrik Rydberg struct input_dev *input = hi->input; 678*76f5902aSHenrik Rydberg 679*76f5902aSHenrik Rydberg /* Only initialize slots for MT input devices */ 680*76f5902aSHenrik Rydberg if (!test_bit(ABS_MT_POSITION_X, input->absbit)) 681*76f5902aSHenrik Rydberg return; 682*76f5902aSHenrik Rydberg 683*76f5902aSHenrik Rydberg if (!td->maxcontacts) 684*76f5902aSHenrik Rydberg td->maxcontacts = MT_DEFAULT_MAXCONTACT; 685*76f5902aSHenrik Rydberg 686*76f5902aSHenrik Rydberg mt_post_parse(td); 687*76f5902aSHenrik Rydberg if (td->serial_maybe) 688*76f5902aSHenrik Rydberg mt_post_parse_default_settings(td); 689*76f5902aSHenrik Rydberg 690*76f5902aSHenrik Rydberg if (cls->is_indirect) 691*76f5902aSHenrik Rydberg td->mt_flags |= INPUT_MT_POINTER; 692*76f5902aSHenrik Rydberg 693*76f5902aSHenrik Rydberg input_mt_init_slots(input, td->maxcontacts, td->mt_flags); 694*76f5902aSHenrik Rydberg 695*76f5902aSHenrik Rydberg td->mt_flags = 0; 696*76f5902aSHenrik Rydberg } 697*76f5902aSHenrik Rydberg 6985519cab4SBenjamin Tissoires static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 6995519cab4SBenjamin Tissoires { 7002d93666eSBenjamin Tissoires int ret, i; 7015519cab4SBenjamin Tissoires struct mt_device *td; 7022d93666eSBenjamin Tissoires struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ 7032d93666eSBenjamin Tissoires 7048d179a9eSBenjamin Tissoires if (id) { 7052d93666eSBenjamin Tissoires for (i = 0; mt_classes[i].name ; i++) { 7062d93666eSBenjamin Tissoires if (id->driver_data == mt_classes[i].name) { 7072d93666eSBenjamin Tissoires mtclass = &(mt_classes[i]); 7082d93666eSBenjamin Tissoires break; 7092d93666eSBenjamin Tissoires } 7102d93666eSBenjamin Tissoires } 7118d179a9eSBenjamin Tissoires } 7125519cab4SBenjamin Tissoires 713d682bd7fSHenrik Rydberg /* This allows the driver to correctly support devices 714d682bd7fSHenrik Rydberg * that emit events over several HID messages. 715d682bd7fSHenrik Rydberg */ 716d682bd7fSHenrik Rydberg hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 7175519cab4SBenjamin Tissoires 7189498f954SBenjamin Tissoires td = kzalloc(sizeof(struct mt_device), GFP_KERNEL); 7195519cab4SBenjamin Tissoires if (!td) { 7205519cab4SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch data\n"); 7215519cab4SBenjamin Tissoires return -ENOMEM; 7225519cab4SBenjamin Tissoires } 723eec29e3dSBenjamin Tissoires td->mtclass = *mtclass; 7245519cab4SBenjamin Tissoires td->inputmode = -1; 72531ae9bddSBenjamin Tissoires td->maxcontact_report_id = -1; 7265519cab4SBenjamin Tissoires hid_set_drvdata(hdev, td); 7275519cab4SBenjamin Tissoires 7283ac36d15SBenjamin Tissoires td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL); 7293ac36d15SBenjamin Tissoires if (!td->fields) { 7303ac36d15SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch fields data\n"); 7313ac36d15SBenjamin Tissoires ret = -ENOMEM; 7323ac36d15SBenjamin Tissoires goto fail; 7333ac36d15SBenjamin Tissoires } 7343ac36d15SBenjamin Tissoires 735*76f5902aSHenrik Rydberg if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) 736*76f5902aSHenrik Rydberg td->serial_maybe = true; 737*76f5902aSHenrik Rydberg 7385519cab4SBenjamin Tissoires ret = hid_parse(hdev); 7395519cab4SBenjamin Tissoires if (ret != 0) 7405519cab4SBenjamin Tissoires goto fail; 7415519cab4SBenjamin Tissoires 7425519cab4SBenjamin Tissoires ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 7432d93666eSBenjamin Tissoires if (ret) 7445519cab4SBenjamin Tissoires goto fail; 7455519cab4SBenjamin Tissoires 7469498f954SBenjamin Tissoires td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), 7479498f954SBenjamin Tissoires GFP_KERNEL); 7489498f954SBenjamin Tissoires if (!td->slots) { 7499498f954SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); 7509498f954SBenjamin Tissoires hid_hw_stop(hdev); 7519498f954SBenjamin Tissoires ret = -ENOMEM; 7529498f954SBenjamin Tissoires goto fail; 7539498f954SBenjamin Tissoires } 7549498f954SBenjamin Tissoires 755eec29e3dSBenjamin Tissoires ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); 756eec29e3dSBenjamin Tissoires 75731ae9bddSBenjamin Tissoires mt_set_maxcontacts(hdev); 7585519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 7595519cab4SBenjamin Tissoires 7603ac36d15SBenjamin Tissoires kfree(td->fields); 7613ac36d15SBenjamin Tissoires td->fields = NULL; 7623ac36d15SBenjamin Tissoires 7635519cab4SBenjamin Tissoires return 0; 7645519cab4SBenjamin Tissoires 7655519cab4SBenjamin Tissoires fail: 7663ac36d15SBenjamin Tissoires kfree(td->fields); 7675519cab4SBenjamin Tissoires kfree(td); 7685519cab4SBenjamin Tissoires return ret; 7695519cab4SBenjamin Tissoires } 7705519cab4SBenjamin Tissoires 7715519cab4SBenjamin Tissoires #ifdef CONFIG_PM 7725519cab4SBenjamin Tissoires static int mt_reset_resume(struct hid_device *hdev) 7735519cab4SBenjamin Tissoires { 77431ae9bddSBenjamin Tissoires mt_set_maxcontacts(hdev); 7755519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 7765519cab4SBenjamin Tissoires return 0; 7775519cab4SBenjamin Tissoires } 7785519cab4SBenjamin Tissoires #endif 7795519cab4SBenjamin Tissoires 7805519cab4SBenjamin Tissoires static void mt_remove(struct hid_device *hdev) 7815519cab4SBenjamin Tissoires { 7825519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 783eec29e3dSBenjamin Tissoires sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); 7845519cab4SBenjamin Tissoires hid_hw_stop(hdev); 7859498f954SBenjamin Tissoires kfree(td->slots); 7865519cab4SBenjamin Tissoires kfree(td); 7875519cab4SBenjamin Tissoires hid_set_drvdata(hdev, NULL); 7885519cab4SBenjamin Tissoires } 7895519cab4SBenjamin Tissoires 7905519cab4SBenjamin Tissoires static const struct hid_device_id mt_devices[] = { 7915519cab4SBenjamin Tissoires 792f786bba4SBenjamin Tissoires /* 3M panels */ 793f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 7942c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 795f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M1968) }, 796f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 7972c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 798f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M2256) }, 799c4fad877SBenjamin Tissoires { .driver_data = MT_CLS_3M, 8002c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_3M, 801c4fad877SBenjamin Tissoires USB_DEVICE_ID_3M3266) }, 802f786bba4SBenjamin Tissoires 803e6aac342SBenjamin Tissoires /* ActionStar panels */ 804e6aac342SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 8052c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, 806e6aac342SBenjamin Tissoires USB_DEVICE_ID_ACTIONSTAR_1011) }, 807e6aac342SBenjamin Tissoires 808b1057124SBenjamin Tissoires /* Atmel panels */ 809b1057124SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 8102c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 811b1057124SBenjamin Tissoires USB_DEVICE_ID_ATMEL_MULTITOUCH) }, 812841cb157SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 8132c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, 814841cb157SBenjamin Tissoires USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, 815b1057124SBenjamin Tissoires 8169ed32695SJiri Kosina /* Baanto multitouch devices */ 8179ed32695SJiri Kosina { .driver_data = MT_CLS_DEFAULT, 81816b79bb8SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, 8199ed32695SJiri Kosina USB_DEVICE_ID_BAANTO_MT_190W2) }, 820a841b62cSBenjamin Tissoires /* Cando panels */ 821a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8222c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 823a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, 824a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8252c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 826a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, 827a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8282c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 829a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, 830a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 8312c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 832a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, 833a841b62cSBenjamin Tissoires 834942fd422SAustin Zhang /* Chunghwa Telecom touch panels */ 835942fd422SAustin Zhang { .driver_data = MT_CLS_DEFAULT, 8362c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, 837942fd422SAustin Zhang USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, 838942fd422SAustin Zhang 83979603dc9SBenjamin Tissoires /* CVTouch panels */ 84079603dc9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 8412c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, 84279603dc9SBenjamin Tissoires USB_DEVICE_ID_CVTOUCH_SCREEN) }, 84379603dc9SBenjamin Tissoires 844a3b5e577SBenjamin Tissoires /* Cypress panel */ 845a3b5e577SBenjamin Tissoires { .driver_data = MT_CLS_CYPRESS, 846a3b5e577SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, 847a3b5e577SBenjamin Tissoires USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, 848a3b5e577SBenjamin Tissoires 84922408283SBenjamin Tissoires /* eGalax devices (resistive) */ 85022408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8512c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 852e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, 85322408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8542c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 855e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, 85622408283SBenjamin Tissoires 85722408283SBenjamin Tissoires /* eGalax devices (capacitive) */ 85822408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8592c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 860e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, 861fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8622c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 863fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) }, 864fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8652c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 866fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) }, 867fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8682c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 869fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, 8702ce09df4SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8712c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 8722ce09df4SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) }, 87322408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8742c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 875e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, 876fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8772c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 878fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) }, 87922408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8802c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 881e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, 882fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8832c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 884fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) }, 8851fd8f047SChris Bagwell { .driver_data = MT_CLS_EGALAX, 8862c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 88766f06127SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, 88866f06127SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 8892c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 890bb9ff210SMarek Vasut USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, 8911b723e8dSBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8922c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 893fd1d1525SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, 894fd1d1525SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX_SERIAL, 8952c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_DWAV, 896e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, 89722408283SBenjamin Tissoires 898c04abeefSBenjamin Tissoires /* Elo TouchSystems IntelliTouch Plus panel */ 899c04abeefSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, 9002c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ELO, 901c04abeefSBenjamin Tissoires USB_DEVICE_ID_ELO_TS2515) }, 902c04abeefSBenjamin Tissoires 9035572da08SBenjamin Tissoires /* GeneralTouch panel */ 9041e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 9052c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 9065572da08SBenjamin Tissoires USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, 9075572da08SBenjamin Tissoires 9084d5df5d1SAndreas Nielsen /* Gametel game controller */ 9094d5df5d1SAndreas Nielsen { .driver_data = MT_CLS_DEFAULT, 9102c2110e9SHenrik Rydberg MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL, 9114d5df5d1SAndreas Nielsen USB_DEVICE_ID_GAMETEL_MT_MODE) }, 9124d5df5d1SAndreas Nielsen 913ee0fbd14SBenjamin Tissoires /* GoodTouch panels */ 914ee0fbd14SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 9152c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, 916ee0fbd14SBenjamin Tissoires USB_DEVICE_ID_GOODTOUCH_000f) }, 917ee0fbd14SBenjamin Tissoires 91854580365SBenjamin Tissoires /* Hanvon panels */ 91954580365SBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 9202c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, 92154580365SBenjamin Tissoires USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, 92254580365SBenjamin Tissoires 923a062cc5aSStephane Chatty /* Ideacom panel */ 924a062cc5aSStephane Chatty { .driver_data = MT_CLS_SERIAL, 9252c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, 926a062cc5aSStephane Chatty USB_DEVICE_ID_IDEACOM_IDC6650) }, 92771078b0dSBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 9282c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, 92971078b0dSBenjamin Tissoires USB_DEVICE_ID_IDEACOM_IDC6651) }, 930a062cc5aSStephane Chatty 9314e61f0d7SAustin Zhang /* Ilitek dual touch panel */ 9324e61f0d7SAustin Zhang { .driver_data = MT_CLS_DEFAULT, 9332c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, 9344e61f0d7SAustin Zhang USB_DEVICE_ID_ILITEK_MULTITOUCH) }, 9354e61f0d7SAustin Zhang 9364dfcced8SBenjamin Tissoires /* IRTOUCH panels */ 9374dfcced8SBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 9382c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, 9394dfcced8SBenjamin Tissoires USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, 9404dfcced8SBenjamin Tissoires 941c50bb1a4SJeff Brown /* LG Display panels */ 942c50bb1a4SJeff Brown { .driver_data = MT_CLS_DEFAULT, 9432c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_LG, 944c50bb1a4SJeff Brown USB_DEVICE_ID_LG_MULTITOUCH) }, 945c50bb1a4SJeff Brown 946df167c4aSBenjamin Tissoires /* Lumio panels */ 947df167c4aSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 9482c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, 949df167c4aSBenjamin Tissoires USB_DEVICE_ID_CRYSTALTOUCH) }, 950c3ead6deSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 9512c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, 952c3ead6deSBenjamin Tissoires USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, 953df167c4aSBenjamin Tissoires 9544a6ee685SBenjamin Tissoires /* MosArt panels */ 9554a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 9562c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 9574a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUS_T91MT)}, 9584a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 9592c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_ASUS, 9604a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 9614a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 9622c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, 9634a6ee685SBenjamin Tissoires USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 9644a6ee685SBenjamin Tissoires 9652258e863SDenis Kovalev /* Panasonic panels */ 9662258e863SDenis Kovalev { .driver_data = MT_CLS_PANASONIC, 9672c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 9682258e863SDenis Kovalev USB_DEVICE_ID_PANABOARD_UBT780) }, 9692258e863SDenis Kovalev { .driver_data = MT_CLS_PANASONIC, 9702c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, 9712258e863SDenis Kovalev USB_DEVICE_ID_PANABOARD_UBT880) }, 9722258e863SDenis Kovalev 9734db703eaSAustin Hendrix /* Novatek Panel */ 9744db703eaSAustin Hendrix { .driver_data = MT_CLS_DEFAULT, 9754380d819SJiri Kosina MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, 9764db703eaSAustin Hendrix USB_DEVICE_ID_NOVATEK_PCT) }, 9774db703eaSAustin Hendrix 9786ab3a9a6SJohn Sung /* PenMount panels */ 9796ab3a9a6SJohn Sung { .driver_data = MT_CLS_CONFIDENCE, 9802c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, 9816ab3a9a6SJohn Sung USB_DEVICE_ID_PENMOUNT_PCI) }, 9826ab3a9a6SJohn Sung 983b7ea95ffSAaron Tian /* PixArt optical touch screen */ 984b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 9852c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 986b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) }, 987b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 9882c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 989b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) }, 990b7ea95ffSAaron Tian { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, 9912c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_PIXART, 992b7ea95ffSAaron Tian USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) }, 993b7ea95ffSAaron Tian 9945519cab4SBenjamin Tissoires /* PixCir-based panels */ 9951e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 9962c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_HANVON, 9975519cab4SBenjamin Tissoires USB_DEVICE_ID_HANVON_MULTITOUCH) }, 9981e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 9992c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_CANDO, 10005519cab4SBenjamin Tissoires USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, 10015519cab4SBenjamin Tissoires 10025e7ea11fSBenjamin Tissoires /* Quanta-based panels */ 10035e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 10042c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 10055e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, 10065e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 10072c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 10085e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, 10095e7ea11fSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, 10102c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, 10115e7ea11fSBenjamin Tissoires USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) }, 10125e7ea11fSBenjamin Tissoires 1013043b403aSBenjamin Tissoires /* Stantum panels */ 1014bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 10152c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM, 1016043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP)}, 1017bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 10182c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, 1019043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_STM)}, 1020bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 10212c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, 1022043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_SITRONIX)}, 1023043b403aSBenjamin Tissoires 1024847672cdSBenjamin Tissoires /* TopSeed panels */ 1025847672cdSBenjamin Tissoires { .driver_data = MT_CLS_TOPSEED, 10262c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, 1027847672cdSBenjamin Tissoires USB_DEVICE_ID_TOPSEED2_PERIPAD_701) }, 1028847672cdSBenjamin Tissoires 10295e74e56dSBenjamin Tissoires /* Touch International panels */ 10305e74e56dSBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 10312c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, 10325e74e56dSBenjamin Tissoires USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, 10335e74e56dSBenjamin Tissoires 1034617b64f9SBenjamin Tissoires /* Unitec panels */ 1035617b64f9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 10362c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 1037617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, 1038617b64f9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 10392c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, 1040617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, 1041bc8a2a9bSice chien /* XAT */ 1042bc8a2a9bSice chien { .driver_data = MT_CLS_DEFAULT, 10432c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XAT, 1044bc8a2a9bSice chien USB_DEVICE_ID_XAT_CSR) }, 1045617b64f9SBenjamin Tissoires 104611576c61SMasatoshi Hoshikawa /* Xiroku */ 104711576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10482c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 104911576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX) }, 105011576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10512c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 105211576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX) }, 105311576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10542c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 105511576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR) }, 105611576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10572c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 105811576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX1) }, 105911576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10602c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 106111576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX1) }, 106211576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10632c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 106411576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR1) }, 106511576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10662c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 106711576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_SPX2) }, 106811576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10692c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 107011576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_MPX2) }, 107111576c61SMasatoshi Hoshikawa { .driver_data = MT_CLS_DEFAULT, 10722c2110e9SHenrik Rydberg MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, 107311576c61SMasatoshi Hoshikawa USB_DEVICE_ID_XIROKU_CSR2) }, 107411576c61SMasatoshi Hoshikawa 107582d06982SBenjamin Tissoires /* Zytronic panels */ 107682d06982SBenjamin Tissoires { .driver_data = MT_CLS_SERIAL, 107782d06982SBenjamin Tissoires MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC, 107882d06982SBenjamin Tissoires USB_DEVICE_ID_ZYTRONIC_ZXY100) }, 107982d06982SBenjamin Tissoires 10804fa3a583SHenrik Rydberg /* Generic MT device */ 10814fa3a583SHenrik Rydberg { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, 10825519cab4SBenjamin Tissoires { } 10835519cab4SBenjamin Tissoires }; 10845519cab4SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, mt_devices); 10855519cab4SBenjamin Tissoires 10865519cab4SBenjamin Tissoires static const struct hid_usage_id mt_grabbed_usages[] = { 10875519cab4SBenjamin Tissoires { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 10885519cab4SBenjamin Tissoires { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 10895519cab4SBenjamin Tissoires }; 10905519cab4SBenjamin Tissoires 10915519cab4SBenjamin Tissoires static struct hid_driver mt_driver = { 10925519cab4SBenjamin Tissoires .name = "hid-multitouch", 10935519cab4SBenjamin Tissoires .id_table = mt_devices, 10945519cab4SBenjamin Tissoires .probe = mt_probe, 10955519cab4SBenjamin Tissoires .remove = mt_remove, 10965519cab4SBenjamin Tissoires .input_mapping = mt_input_mapping, 10975519cab4SBenjamin Tissoires .input_mapped = mt_input_mapped, 1098*76f5902aSHenrik Rydberg .input_configured = mt_input_configured, 10995519cab4SBenjamin Tissoires .feature_mapping = mt_feature_mapping, 11005519cab4SBenjamin Tissoires .usage_table = mt_grabbed_usages, 11015519cab4SBenjamin Tissoires .event = mt_event, 11025519cab4SBenjamin Tissoires #ifdef CONFIG_PM 11035519cab4SBenjamin Tissoires .reset_resume = mt_reset_resume, 11045519cab4SBenjamin Tissoires #endif 11055519cab4SBenjamin Tissoires }; 11065519cab4SBenjamin Tissoires 11075519cab4SBenjamin Tissoires static int __init mt_init(void) 11085519cab4SBenjamin Tissoires { 11095519cab4SBenjamin Tissoires return hid_register_driver(&mt_driver); 11105519cab4SBenjamin Tissoires } 11115519cab4SBenjamin Tissoires 11125519cab4SBenjamin Tissoires static void __exit mt_exit(void) 11135519cab4SBenjamin Tissoires { 11145519cab4SBenjamin Tissoires hid_unregister_driver(&mt_driver); 11155519cab4SBenjamin Tissoires } 11165519cab4SBenjamin Tissoires 11175519cab4SBenjamin Tissoires module_init(mt_init); 11185519cab4SBenjamin Tissoires module_exit(mt_exit); 1119