15519cab4SBenjamin Tissoires /* 25519cab4SBenjamin Tissoires * HID driver for multitouch panels 35519cab4SBenjamin Tissoires * 45519cab4SBenjamin Tissoires * Copyright (c) 2010-2011 Stephane Chatty <chatty@enac.fr> 55519cab4SBenjamin Tissoires * Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com> 65519cab4SBenjamin Tissoires * Copyright (c) 2010-2011 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 62eec29e3dSBenjamin Tissoires struct mt_class { 63eec29e3dSBenjamin Tissoires __s32 name; /* MT_CLS */ 64eec29e3dSBenjamin Tissoires __s32 quirks; 65eec29e3dSBenjamin Tissoires __s32 sn_move; /* Signal/noise ratio for move events */ 66eec29e3dSBenjamin Tissoires __s32 sn_width; /* Signal/noise ratio for width events */ 67eec29e3dSBenjamin Tissoires __s32 sn_height; /* Signal/noise ratio for height events */ 68eec29e3dSBenjamin Tissoires __s32 sn_pressure; /* Signal/noise ratio for pressure events */ 69eec29e3dSBenjamin Tissoires __u8 maxcontacts; 70eec29e3dSBenjamin Tissoires }; 71eec29e3dSBenjamin Tissoires 725519cab4SBenjamin Tissoires struct mt_device { 735519cab4SBenjamin Tissoires struct mt_slot curdata; /* placeholder of incoming data */ 74eec29e3dSBenjamin Tissoires struct mt_class mtclass; /* our mt device class */ 755519cab4SBenjamin Tissoires unsigned last_field_index; /* last field index of the report */ 765519cab4SBenjamin Tissoires unsigned last_slot_field; /* the last field of a slot */ 77b84bd27fSBenjamin Tissoires int last_mt_collection; /* last known mt-related collection */ 785519cab4SBenjamin Tissoires __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ 795519cab4SBenjamin Tissoires __u8 num_received; /* how many contacts we received */ 805519cab4SBenjamin Tissoires __u8 num_expected; /* expected last contact index */ 819498f954SBenjamin Tissoires __u8 maxcontacts; 825519cab4SBenjamin Tissoires bool curvalid; /* is the current contact valid? */ 839498f954SBenjamin Tissoires struct mt_slot *slots; 845519cab4SBenjamin Tissoires }; 855519cab4SBenjamin Tissoires 865519cab4SBenjamin Tissoires /* classes of device behavior */ 8722408283SBenjamin Tissoires #define MT_CLS_DEFAULT 0x0001 8822408283SBenjamin Tissoires 89a062cc5aSStephane Chatty #define MT_CLS_SERIAL 0x0002 90a062cc5aSStephane Chatty #define MT_CLS_CONFIDENCE 0x0003 91a062cc5aSStephane Chatty #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0004 92a062cc5aSStephane Chatty #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0005 93a062cc5aSStephane Chatty #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0006 94a062cc5aSStephane Chatty #define MT_CLS_DUAL_NSMU_CONTACTID 0x0007 9522408283SBenjamin Tissoires 9622408283SBenjamin Tissoires /* vendor specific classes */ 9722408283SBenjamin Tissoires #define MT_CLS_3M 0x0101 9822408283SBenjamin Tissoires #define MT_CLS_CYPRESS 0x0102 9922408283SBenjamin Tissoires #define MT_CLS_EGALAX 0x0103 1005519cab4SBenjamin Tissoires 1019498f954SBenjamin Tissoires #define MT_DEFAULT_MAXCONTACT 10 1029498f954SBenjamin Tissoires 1035519cab4SBenjamin Tissoires /* 1045519cab4SBenjamin Tissoires * these device-dependent functions determine what slot corresponds 1055519cab4SBenjamin Tissoires * to a valid contact that was just read. 1065519cab4SBenjamin Tissoires */ 1075519cab4SBenjamin Tissoires 108a3b5e577SBenjamin Tissoires static int cypress_compute_slot(struct mt_device *td) 109a3b5e577SBenjamin Tissoires { 110a3b5e577SBenjamin Tissoires if (td->curdata.contactid != 0 || td->num_received == 0) 111a3b5e577SBenjamin Tissoires return td->curdata.contactid; 112a3b5e577SBenjamin Tissoires else 113a3b5e577SBenjamin Tissoires return -1; 114a3b5e577SBenjamin Tissoires } 115a3b5e577SBenjamin Tissoires 1165519cab4SBenjamin Tissoires static int find_slot_from_contactid(struct mt_device *td) 1175519cab4SBenjamin Tissoires { 1185519cab4SBenjamin Tissoires int i; 1199498f954SBenjamin Tissoires for (i = 0; i < td->maxcontacts; ++i) { 1205519cab4SBenjamin Tissoires if (td->slots[i].contactid == td->curdata.contactid && 1215519cab4SBenjamin Tissoires td->slots[i].touch_state) 1225519cab4SBenjamin Tissoires return i; 1235519cab4SBenjamin Tissoires } 1249498f954SBenjamin Tissoires for (i = 0; i < td->maxcontacts; ++i) { 1255519cab4SBenjamin Tissoires if (!td->slots[i].seen_in_this_frame && 1265519cab4SBenjamin Tissoires !td->slots[i].touch_state) 1275519cab4SBenjamin Tissoires return i; 1285519cab4SBenjamin Tissoires } 1295519cab4SBenjamin Tissoires /* should not occurs. If this happens that means 1305519cab4SBenjamin Tissoires * that the device sent more touches that it says 1315519cab4SBenjamin Tissoires * in the report descriptor. It is ignored then. */ 1322d93666eSBenjamin Tissoires return -1; 1335519cab4SBenjamin Tissoires } 1345519cab4SBenjamin Tissoires 1355519cab4SBenjamin Tissoires struct mt_class mt_classes[] = { 1362d93666eSBenjamin Tissoires { .name = MT_CLS_DEFAULT, 1379498f954SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, 138a062cc5aSStephane Chatty { .name = MT_CLS_SERIAL, 139a062cc5aSStephane Chatty .quirks = MT_QUIRK_ALWAYS_VALID}, 14022408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE, 14122408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, 14222408283SBenjamin Tissoires { .name = MT_CLS_CONFIDENCE_MINUS_ONE, 14322408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 14422408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, 1451e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTID, 1462d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 1472d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 1482d93666eSBenjamin Tissoires .maxcontacts = 2 }, 1491e9cf35bSBenjamin Tissoires { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 1502d93666eSBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_INRANGE | 1512d93666eSBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTNUMBER, 1522d93666eSBenjamin Tissoires .maxcontacts = 2 }, 15322408283SBenjamin Tissoires { .name = MT_CLS_DUAL_NSMU_CONTACTID, 15422408283SBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 15522408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 15622408283SBenjamin Tissoires .maxcontacts = 2 }, 15722408283SBenjamin Tissoires 15822408283SBenjamin Tissoires /* 15922408283SBenjamin Tissoires * vendor specific classes 16022408283SBenjamin Tissoires */ 16122408283SBenjamin Tissoires { .name = MT_CLS_3M, 16222408283SBenjamin Tissoires .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | 16322408283SBenjamin Tissoires MT_QUIRK_SLOT_IS_CONTACTID, 16422408283SBenjamin Tissoires .sn_move = 2048, 16522408283SBenjamin Tissoires .sn_width = 128, 16622408283SBenjamin Tissoires .sn_height = 128 }, 1672d93666eSBenjamin Tissoires { .name = MT_CLS_CYPRESS, 1682d93666eSBenjamin Tissoires .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | 1692d93666eSBenjamin Tissoires MT_QUIRK_CYPRESS, 1702d93666eSBenjamin Tissoires .maxcontacts = 10 }, 1714875ac11SRichard Nauber { .name = MT_CLS_EGALAX, 1724875ac11SRichard Nauber .quirks = MT_QUIRK_SLOT_IS_CONTACTID | 1732261bb9fSBenjamin Tissoires MT_QUIRK_VALID_IS_INRANGE, 1744875ac11SRichard Nauber .sn_move = 4096, 1754875ac11SRichard Nauber .sn_pressure = 32, 1764875ac11SRichard Nauber }, 177043b403aSBenjamin Tissoires 1782d93666eSBenjamin Tissoires { } 1795519cab4SBenjamin Tissoires }; 1805519cab4SBenjamin Tissoires 181eec29e3dSBenjamin Tissoires static ssize_t mt_show_quirks(struct device *dev, 182eec29e3dSBenjamin Tissoires struct device_attribute *attr, 183eec29e3dSBenjamin Tissoires char *buf) 184eec29e3dSBenjamin Tissoires { 185eec29e3dSBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 186eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 187eec29e3dSBenjamin Tissoires 188eec29e3dSBenjamin Tissoires return sprintf(buf, "%u\n", td->mtclass.quirks); 189eec29e3dSBenjamin Tissoires } 190eec29e3dSBenjamin Tissoires 191eec29e3dSBenjamin Tissoires static ssize_t mt_set_quirks(struct device *dev, 192eec29e3dSBenjamin Tissoires struct device_attribute *attr, 193eec29e3dSBenjamin Tissoires const char *buf, size_t count) 194eec29e3dSBenjamin Tissoires { 195eec29e3dSBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 196eec29e3dSBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 197eec29e3dSBenjamin Tissoires 198eec29e3dSBenjamin Tissoires unsigned long val; 199eec29e3dSBenjamin Tissoires 200eec29e3dSBenjamin Tissoires if (kstrtoul(buf, 0, &val)) 201eec29e3dSBenjamin Tissoires return -EINVAL; 202eec29e3dSBenjamin Tissoires 203eec29e3dSBenjamin Tissoires td->mtclass.quirks = val; 204eec29e3dSBenjamin Tissoires 205eec29e3dSBenjamin Tissoires return count; 206eec29e3dSBenjamin Tissoires } 207eec29e3dSBenjamin Tissoires 208eec29e3dSBenjamin Tissoires static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); 209eec29e3dSBenjamin Tissoires 210eec29e3dSBenjamin Tissoires static struct attribute *sysfs_attrs[] = { 211eec29e3dSBenjamin Tissoires &dev_attr_quirks.attr, 212eec29e3dSBenjamin Tissoires NULL 213eec29e3dSBenjamin Tissoires }; 214eec29e3dSBenjamin Tissoires 215eec29e3dSBenjamin Tissoires static struct attribute_group mt_attribute_group = { 216eec29e3dSBenjamin Tissoires .attrs = sysfs_attrs 217eec29e3dSBenjamin Tissoires }; 218eec29e3dSBenjamin Tissoires 219f635bd11SHenrik Rydberg static void mt_feature_mapping(struct hid_device *hdev, 2205519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage) 2215519cab4SBenjamin Tissoires { 2225519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 2239498f954SBenjamin Tissoires 2249498f954SBenjamin Tissoires switch (usage->hid) { 2259498f954SBenjamin Tissoires case HID_DG_INPUTMODE: 2265519cab4SBenjamin Tissoires td->inputmode = field->report->id; 2279498f954SBenjamin Tissoires break; 2289498f954SBenjamin Tissoires case HID_DG_CONTACTMAX: 2299498f954SBenjamin Tissoires td->maxcontacts = field->value[0]; 230eec29e3dSBenjamin Tissoires if (td->mtclass.maxcontacts) 2319498f954SBenjamin Tissoires /* check if the maxcontacts is given by the class */ 232eec29e3dSBenjamin Tissoires td->maxcontacts = td->mtclass.maxcontacts; 2339498f954SBenjamin Tissoires 2349498f954SBenjamin Tissoires break; 2355519cab4SBenjamin Tissoires } 2365519cab4SBenjamin Tissoires } 2375519cab4SBenjamin Tissoires 2385519cab4SBenjamin Tissoires static void set_abs(struct input_dev *input, unsigned int code, 2395519cab4SBenjamin Tissoires struct hid_field *field, int snratio) 2405519cab4SBenjamin Tissoires { 2415519cab4SBenjamin Tissoires int fmin = field->logical_minimum; 2425519cab4SBenjamin Tissoires int fmax = field->logical_maximum; 2435519cab4SBenjamin Tissoires int fuzz = snratio ? (fmax - fmin) / snratio : 0; 2445519cab4SBenjamin Tissoires input_set_abs_params(input, code, fmin, fmax, fuzz, 0); 2455519cab4SBenjamin Tissoires } 2465519cab4SBenjamin Tissoires 2475519cab4SBenjamin Tissoires static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 2485519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 2495519cab4SBenjamin Tissoires unsigned long **bit, int *max) 2505519cab4SBenjamin Tissoires { 2515519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 252eec29e3dSBenjamin Tissoires struct mt_class *cls = &td->mtclass; 2534875ac11SRichard Nauber 254658d4aedSJeff Brown /* Only map fields from TouchScreen or TouchPad collections. 255658d4aedSJeff Brown * We need to ignore fields that belong to other collections 256658d4aedSJeff Brown * such as Mouse that might have the same GenericDesktop usages. */ 257658d4aedSJeff Brown if (field->application == HID_DG_TOUCHSCREEN) 258658d4aedSJeff Brown set_bit(INPUT_PROP_DIRECT, hi->input->propbit); 259658d4aedSJeff Brown else if (field->application == HID_DG_TOUCHPAD) 260658d4aedSJeff Brown set_bit(INPUT_PROP_POINTER, hi->input->propbit); 261658d4aedSJeff Brown else 262658d4aedSJeff Brown return 0; 263658d4aedSJeff Brown 2642261bb9fSBenjamin Tissoires /* eGalax devices provide a Digitizer.Stylus input which overrides 2652261bb9fSBenjamin Tissoires * the correct Digitizers.Finger X/Y ranges. 2662261bb9fSBenjamin Tissoires * Let's just ignore this input. */ 2672261bb9fSBenjamin Tissoires if (field->physical == HID_DG_STYLUS) 2682261bb9fSBenjamin Tissoires return -1; 2692261bb9fSBenjamin Tissoires 2705519cab4SBenjamin Tissoires switch (usage->hid & HID_USAGE_PAGE) { 2715519cab4SBenjamin Tissoires 2725519cab4SBenjamin Tissoires case HID_UP_GENDESK: 2735519cab4SBenjamin Tissoires switch (usage->hid) { 2745519cab4SBenjamin Tissoires case HID_GD_X: 2755519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 2765519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_X); 2775519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_X, field, 2785519cab4SBenjamin Tissoires cls->sn_move); 2795519cab4SBenjamin Tissoires /* touchscreen emulation */ 2805519cab4SBenjamin Tissoires set_abs(hi->input, ABS_X, field, cls->sn_move); 281b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 2825519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 2832955caedSBenjamin Tissoires td->last_field_index = field->index; 284b84bd27fSBenjamin Tissoires } 2855519cab4SBenjamin Tissoires return 1; 2865519cab4SBenjamin Tissoires case HID_GD_Y: 2875519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 2885519cab4SBenjamin Tissoires EV_ABS, ABS_MT_POSITION_Y); 2895519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_POSITION_Y, field, 2905519cab4SBenjamin Tissoires cls->sn_move); 2915519cab4SBenjamin Tissoires /* touchscreen emulation */ 2925519cab4SBenjamin Tissoires set_abs(hi->input, ABS_Y, field, cls->sn_move); 293b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 2945519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 2952955caedSBenjamin Tissoires td->last_field_index = field->index; 296b84bd27fSBenjamin Tissoires } 2975519cab4SBenjamin Tissoires return 1; 2985519cab4SBenjamin Tissoires } 2995519cab4SBenjamin Tissoires return 0; 3005519cab4SBenjamin Tissoires 3015519cab4SBenjamin Tissoires case HID_UP_DIGITIZER: 3025519cab4SBenjamin Tissoires switch (usage->hid) { 3035519cab4SBenjamin Tissoires case HID_DG_INRANGE: 304b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 3055519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 3062955caedSBenjamin Tissoires td->last_field_index = field->index; 307b84bd27fSBenjamin Tissoires } 3085519cab4SBenjamin Tissoires return 1; 3095519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 310b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 3115519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 3122955caedSBenjamin Tissoires td->last_field_index = field->index; 313b84bd27fSBenjamin Tissoires } 3145519cab4SBenjamin Tissoires return 1; 3155519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 3165519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); 3175519cab4SBenjamin Tissoires input_set_capability(hi->input, EV_KEY, BTN_TOUCH); 318b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 3195519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 3202955caedSBenjamin Tissoires td->last_field_index = field->index; 321b84bd27fSBenjamin Tissoires } 3225519cab4SBenjamin Tissoires return 1; 3235519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 32450bc03abSBenjamin Tissoires if (!td->maxcontacts) 32550bc03abSBenjamin Tissoires td->maxcontacts = MT_DEFAULT_MAXCONTACT; 3269498f954SBenjamin Tissoires input_mt_init_slots(hi->input, td->maxcontacts); 3275519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 3282955caedSBenjamin Tissoires td->last_field_index = field->index; 329b84bd27fSBenjamin Tissoires td->last_mt_collection = usage->collection_index; 3305519cab4SBenjamin Tissoires return 1; 3315519cab4SBenjamin Tissoires case HID_DG_WIDTH: 3325519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3335519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MAJOR); 334f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, 335f786bba4SBenjamin Tissoires cls->sn_width); 336b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 3375519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 3382955caedSBenjamin Tissoires td->last_field_index = field->index; 339b84bd27fSBenjamin Tissoires } 3405519cab4SBenjamin Tissoires return 1; 3415519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 3425519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3435519cab4SBenjamin Tissoires EV_ABS, ABS_MT_TOUCH_MINOR); 344f786bba4SBenjamin Tissoires set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, 345f786bba4SBenjamin Tissoires cls->sn_height); 3461e648a13SBenjamin Tissoires input_set_abs_params(hi->input, 3471e648a13SBenjamin Tissoires ABS_MT_ORIENTATION, 0, 1, 0, 0); 348b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 3495519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 3502955caedSBenjamin Tissoires td->last_field_index = field->index; 351b84bd27fSBenjamin Tissoires } 3525519cab4SBenjamin Tissoires return 1; 3535519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 3545519cab4SBenjamin Tissoires hid_map_usage(hi, usage, bit, max, 3555519cab4SBenjamin Tissoires EV_ABS, ABS_MT_PRESSURE); 3565519cab4SBenjamin Tissoires set_abs(hi->input, ABS_MT_PRESSURE, field, 3575519cab4SBenjamin Tissoires cls->sn_pressure); 3585519cab4SBenjamin Tissoires /* touchscreen emulation */ 3595519cab4SBenjamin Tissoires set_abs(hi->input, ABS_PRESSURE, field, 3605519cab4SBenjamin Tissoires cls->sn_pressure); 361b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) { 3625519cab4SBenjamin Tissoires td->last_slot_field = usage->hid; 3632955caedSBenjamin Tissoires td->last_field_index = field->index; 364b84bd27fSBenjamin Tissoires } 3655519cab4SBenjamin Tissoires return 1; 3665519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 367b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) 3682955caedSBenjamin Tissoires td->last_field_index = field->index; 3695519cab4SBenjamin Tissoires return 1; 3705519cab4SBenjamin Tissoires case HID_DG_CONTACTMAX: 3715519cab4SBenjamin Tissoires /* we don't set td->last_slot_field as contactcount and 3725519cab4SBenjamin Tissoires * contact max are global to the report */ 373b84bd27fSBenjamin Tissoires if (td->last_mt_collection == usage->collection_index) 3742955caedSBenjamin Tissoires td->last_field_index = field->index; 3755519cab4SBenjamin Tissoires return -1; 3765519cab4SBenjamin Tissoires } 3775519cab4SBenjamin Tissoires /* let hid-input decide for the others */ 3785519cab4SBenjamin Tissoires return 0; 3795519cab4SBenjamin Tissoires 3805519cab4SBenjamin Tissoires case 0xff000000: 3815519cab4SBenjamin Tissoires /* we do not want to map these: no input-oriented meaning */ 3825519cab4SBenjamin Tissoires return -1; 3835519cab4SBenjamin Tissoires } 3845519cab4SBenjamin Tissoires 3855519cab4SBenjamin Tissoires return 0; 3865519cab4SBenjamin Tissoires } 3875519cab4SBenjamin Tissoires 3885519cab4SBenjamin Tissoires static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, 3895519cab4SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage, 3905519cab4SBenjamin Tissoires unsigned long **bit, int *max) 3915519cab4SBenjamin Tissoires { 3925519cab4SBenjamin Tissoires if (usage->type == EV_KEY || usage->type == EV_ABS) 3935519cab4SBenjamin Tissoires set_bit(usage->type, hi->input->evbit); 3945519cab4SBenjamin Tissoires 3955519cab4SBenjamin Tissoires return -1; 3965519cab4SBenjamin Tissoires } 3975519cab4SBenjamin Tissoires 3985519cab4SBenjamin Tissoires static int mt_compute_slot(struct mt_device *td) 3995519cab4SBenjamin Tissoires { 400eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 4015519cab4SBenjamin Tissoires 4022d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) 4032d93666eSBenjamin Tissoires return td->curdata.contactid; 4045519cab4SBenjamin Tissoires 4052d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_CYPRESS) 406a3b5e577SBenjamin Tissoires return cypress_compute_slot(td); 407a3b5e577SBenjamin Tissoires 4082d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) 4092d93666eSBenjamin Tissoires return td->num_received; 4105572da08SBenjamin Tissoires 4114a6ee685SBenjamin Tissoires if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) 4124a6ee685SBenjamin Tissoires return td->curdata.contactid - 1; 4134a6ee685SBenjamin Tissoires 4145519cab4SBenjamin Tissoires return find_slot_from_contactid(td); 4155519cab4SBenjamin Tissoires } 4165519cab4SBenjamin Tissoires 4175519cab4SBenjamin Tissoires /* 4185519cab4SBenjamin Tissoires * this function is called when a whole contact has been processed, 4195519cab4SBenjamin Tissoires * so that it can assign it to a slot and store the data there 4205519cab4SBenjamin Tissoires */ 4215519cab4SBenjamin Tissoires static void mt_complete_slot(struct mt_device *td) 4225519cab4SBenjamin Tissoires { 4232d93666eSBenjamin Tissoires td->curdata.seen_in_this_frame = true; 4245519cab4SBenjamin Tissoires if (td->curvalid) { 4255519cab4SBenjamin Tissoires int slotnum = mt_compute_slot(td); 4265519cab4SBenjamin Tissoires 4279498f954SBenjamin Tissoires if (slotnum >= 0 && slotnum < td->maxcontacts) 4282d93666eSBenjamin Tissoires td->slots[slotnum] = td->curdata; 4295519cab4SBenjamin Tissoires } 4305519cab4SBenjamin Tissoires td->num_received++; 4315519cab4SBenjamin Tissoires } 4325519cab4SBenjamin Tissoires 4335519cab4SBenjamin Tissoires 4345519cab4SBenjamin Tissoires /* 4355519cab4SBenjamin Tissoires * this function is called when a whole packet has been received and processed, 4365519cab4SBenjamin Tissoires * so that it can decide what to send to the input layer. 4375519cab4SBenjamin Tissoires */ 4385519cab4SBenjamin Tissoires static void mt_emit_event(struct mt_device *td, struct input_dev *input) 4395519cab4SBenjamin Tissoires { 4405519cab4SBenjamin Tissoires int i; 4415519cab4SBenjamin Tissoires 4429498f954SBenjamin Tissoires for (i = 0; i < td->maxcontacts; ++i) { 4435519cab4SBenjamin Tissoires struct mt_slot *s = &(td->slots[i]); 444eec29e3dSBenjamin Tissoires if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && 4455519cab4SBenjamin Tissoires !s->seen_in_this_frame) { 4465519cab4SBenjamin Tissoires s->touch_state = false; 4475519cab4SBenjamin Tissoires } 4485519cab4SBenjamin Tissoires 4495519cab4SBenjamin Tissoires input_mt_slot(input, i); 4505519cab4SBenjamin Tissoires input_mt_report_slot_state(input, MT_TOOL_FINGER, 4515519cab4SBenjamin Tissoires s->touch_state); 4522d93666eSBenjamin Tissoires if (s->touch_state) { 453f786bba4SBenjamin Tissoires /* this finger is on the screen */ 454f786bba4SBenjamin Tissoires int wide = (s->w > s->h); 455f786bba4SBenjamin Tissoires /* divided by two to match visual scale of touch */ 456f786bba4SBenjamin Tissoires int major = max(s->w, s->h) >> 1; 457f786bba4SBenjamin Tissoires int minor = min(s->w, s->h) >> 1; 458f786bba4SBenjamin Tissoires 4595519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); 4605519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); 461f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); 4625519cab4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); 463f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 464f786bba4SBenjamin Tissoires input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 4652d93666eSBenjamin Tissoires } 4665519cab4SBenjamin Tissoires s->seen_in_this_frame = false; 4675519cab4SBenjamin Tissoires 4685519cab4SBenjamin Tissoires } 4695519cab4SBenjamin Tissoires 4705519cab4SBenjamin Tissoires input_mt_report_pointer_emulation(input, true); 4715519cab4SBenjamin Tissoires input_sync(input); 4725519cab4SBenjamin Tissoires td->num_received = 0; 4735519cab4SBenjamin Tissoires } 4745519cab4SBenjamin Tissoires 4755519cab4SBenjamin Tissoires 4765519cab4SBenjamin Tissoires 4775519cab4SBenjamin Tissoires static int mt_event(struct hid_device *hid, struct hid_field *field, 4785519cab4SBenjamin Tissoires struct hid_usage *usage, __s32 value) 4795519cab4SBenjamin Tissoires { 4805519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hid); 481eec29e3dSBenjamin Tissoires __s32 quirks = td->mtclass.quirks; 4825519cab4SBenjamin Tissoires 4839498f954SBenjamin Tissoires if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { 4845519cab4SBenjamin Tissoires switch (usage->hid) { 4855519cab4SBenjamin Tissoires case HID_DG_INRANGE: 486a062cc5aSStephane Chatty if (quirks & MT_QUIRK_ALWAYS_VALID) 487a062cc5aSStephane Chatty td->curvalid = true; 488a062cc5aSStephane Chatty else if (quirks & MT_QUIRK_VALID_IS_INRANGE) 4892d93666eSBenjamin Tissoires td->curvalid = value; 4905519cab4SBenjamin Tissoires break; 4915519cab4SBenjamin Tissoires case HID_DG_TIPSWITCH: 4922d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) 4935519cab4SBenjamin Tissoires td->curvalid = value; 4945519cab4SBenjamin Tissoires td->curdata.touch_state = value; 4955519cab4SBenjamin Tissoires break; 4965519cab4SBenjamin Tissoires case HID_DG_CONFIDENCE: 4972d93666eSBenjamin Tissoires if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) 4982d93666eSBenjamin Tissoires td->curvalid = value; 4995519cab4SBenjamin Tissoires break; 5005519cab4SBenjamin Tissoires case HID_DG_CONTACTID: 5015519cab4SBenjamin Tissoires td->curdata.contactid = value; 5025519cab4SBenjamin Tissoires break; 5035519cab4SBenjamin Tissoires case HID_DG_TIPPRESSURE: 5045519cab4SBenjamin Tissoires td->curdata.p = value; 5055519cab4SBenjamin Tissoires break; 5065519cab4SBenjamin Tissoires case HID_GD_X: 5075519cab4SBenjamin Tissoires td->curdata.x = value; 5085519cab4SBenjamin Tissoires break; 5095519cab4SBenjamin Tissoires case HID_GD_Y: 5105519cab4SBenjamin Tissoires td->curdata.y = value; 5115519cab4SBenjamin Tissoires break; 5125519cab4SBenjamin Tissoires case HID_DG_WIDTH: 5135519cab4SBenjamin Tissoires td->curdata.w = value; 5145519cab4SBenjamin Tissoires break; 5155519cab4SBenjamin Tissoires case HID_DG_HEIGHT: 5165519cab4SBenjamin Tissoires td->curdata.h = value; 5175519cab4SBenjamin Tissoires break; 5185519cab4SBenjamin Tissoires case HID_DG_CONTACTCOUNT: 5195519cab4SBenjamin Tissoires /* 5202d93666eSBenjamin Tissoires * Includes multi-packet support where subsequent 5212d93666eSBenjamin Tissoires * packets are sent with zero contactcount. 5225519cab4SBenjamin Tissoires */ 5235519cab4SBenjamin Tissoires if (value) 5242d93666eSBenjamin Tissoires td->num_expected = value; 5255519cab4SBenjamin Tissoires break; 5265519cab4SBenjamin Tissoires 5275519cab4SBenjamin Tissoires default: 5285519cab4SBenjamin Tissoires /* fallback to the generic hidinput handling */ 5295519cab4SBenjamin Tissoires return 0; 5305519cab4SBenjamin Tissoires } 5315519cab4SBenjamin Tissoires 532f153fc39SHenrik Rydberg if (usage->hid == td->last_slot_field) { 5335519cab4SBenjamin Tissoires mt_complete_slot(td); 534f153fc39SHenrik Rydberg } 5355519cab4SBenjamin Tissoires 5365519cab4SBenjamin Tissoires if (field->index == td->last_field_index 5372d93666eSBenjamin Tissoires && td->num_received >= td->num_expected) 5385519cab4SBenjamin Tissoires mt_emit_event(td, field->hidinput->input); 5395519cab4SBenjamin Tissoires 5402d93666eSBenjamin Tissoires } 5412d93666eSBenjamin Tissoires 5425519cab4SBenjamin Tissoires /* we have handled the hidinput part, now remains hiddev */ 5435519cab4SBenjamin Tissoires if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 5445519cab4SBenjamin Tissoires hid->hiddev_hid_event(hid, field, usage, value); 5455519cab4SBenjamin Tissoires 5465519cab4SBenjamin Tissoires return 1; 5475519cab4SBenjamin Tissoires } 5485519cab4SBenjamin Tissoires 5495519cab4SBenjamin Tissoires static void mt_set_input_mode(struct hid_device *hdev) 5505519cab4SBenjamin Tissoires { 5515519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 5525519cab4SBenjamin Tissoires struct hid_report *r; 5535519cab4SBenjamin Tissoires struct hid_report_enum *re; 5545519cab4SBenjamin Tissoires 5555519cab4SBenjamin Tissoires if (td->inputmode < 0) 5565519cab4SBenjamin Tissoires return; 5575519cab4SBenjamin Tissoires 5585519cab4SBenjamin Tissoires re = &(hdev->report_enum[HID_FEATURE_REPORT]); 5595519cab4SBenjamin Tissoires r = re->report_id_hash[td->inputmode]; 5605519cab4SBenjamin Tissoires if (r) { 5615519cab4SBenjamin Tissoires r->field[0]->value[0] = 0x02; 5625519cab4SBenjamin Tissoires usbhid_submit_report(hdev, r, USB_DIR_OUT); 5635519cab4SBenjamin Tissoires } 5645519cab4SBenjamin Tissoires } 5655519cab4SBenjamin Tissoires 5665519cab4SBenjamin Tissoires static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 5675519cab4SBenjamin Tissoires { 5682d93666eSBenjamin Tissoires int ret, i; 5695519cab4SBenjamin Tissoires struct mt_device *td; 5702d93666eSBenjamin Tissoires struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ 5712d93666eSBenjamin Tissoires 5722d93666eSBenjamin Tissoires for (i = 0; mt_classes[i].name ; i++) { 5732d93666eSBenjamin Tissoires if (id->driver_data == mt_classes[i].name) { 5742d93666eSBenjamin Tissoires mtclass = &(mt_classes[i]); 5752d93666eSBenjamin Tissoires break; 5762d93666eSBenjamin Tissoires } 5772d93666eSBenjamin Tissoires } 5785519cab4SBenjamin Tissoires 579d682bd7fSHenrik Rydberg /* This allows the driver to correctly support devices 580d682bd7fSHenrik Rydberg * that emit events over several HID messages. 581d682bd7fSHenrik Rydberg */ 582d682bd7fSHenrik Rydberg hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 5835519cab4SBenjamin Tissoires 5849498f954SBenjamin Tissoires td = kzalloc(sizeof(struct mt_device), GFP_KERNEL); 5855519cab4SBenjamin Tissoires if (!td) { 5865519cab4SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch data\n"); 5875519cab4SBenjamin Tissoires return -ENOMEM; 5885519cab4SBenjamin Tissoires } 589eec29e3dSBenjamin Tissoires td->mtclass = *mtclass; 5905519cab4SBenjamin Tissoires td->inputmode = -1; 591b84bd27fSBenjamin Tissoires td->last_mt_collection = -1; 5925519cab4SBenjamin Tissoires hid_set_drvdata(hdev, td); 5935519cab4SBenjamin Tissoires 5945519cab4SBenjamin Tissoires ret = hid_parse(hdev); 5955519cab4SBenjamin Tissoires if (ret != 0) 5965519cab4SBenjamin Tissoires goto fail; 5975519cab4SBenjamin Tissoires 5985519cab4SBenjamin Tissoires ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 5992d93666eSBenjamin Tissoires if (ret) 6005519cab4SBenjamin Tissoires goto fail; 6015519cab4SBenjamin Tissoires 6029498f954SBenjamin Tissoires td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), 6039498f954SBenjamin Tissoires GFP_KERNEL); 6049498f954SBenjamin Tissoires if (!td->slots) { 6059498f954SBenjamin Tissoires dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); 6069498f954SBenjamin Tissoires hid_hw_stop(hdev); 6079498f954SBenjamin Tissoires ret = -ENOMEM; 6089498f954SBenjamin Tissoires goto fail; 6099498f954SBenjamin Tissoires } 6109498f954SBenjamin Tissoires 611eec29e3dSBenjamin Tissoires ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); 612eec29e3dSBenjamin Tissoires 6135519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 6145519cab4SBenjamin Tissoires 6155519cab4SBenjamin Tissoires return 0; 6165519cab4SBenjamin Tissoires 6175519cab4SBenjamin Tissoires fail: 6185519cab4SBenjamin Tissoires kfree(td); 6195519cab4SBenjamin Tissoires return ret; 6205519cab4SBenjamin Tissoires } 6215519cab4SBenjamin Tissoires 6225519cab4SBenjamin Tissoires #ifdef CONFIG_PM 6235519cab4SBenjamin Tissoires static int mt_reset_resume(struct hid_device *hdev) 6245519cab4SBenjamin Tissoires { 6255519cab4SBenjamin Tissoires mt_set_input_mode(hdev); 6265519cab4SBenjamin Tissoires return 0; 6275519cab4SBenjamin Tissoires } 6285519cab4SBenjamin Tissoires #endif 6295519cab4SBenjamin Tissoires 6305519cab4SBenjamin Tissoires static void mt_remove(struct hid_device *hdev) 6315519cab4SBenjamin Tissoires { 6325519cab4SBenjamin Tissoires struct mt_device *td = hid_get_drvdata(hdev); 633eec29e3dSBenjamin Tissoires sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); 6345519cab4SBenjamin Tissoires hid_hw_stop(hdev); 6359498f954SBenjamin Tissoires kfree(td->slots); 6365519cab4SBenjamin Tissoires kfree(td); 6375519cab4SBenjamin Tissoires hid_set_drvdata(hdev, NULL); 6385519cab4SBenjamin Tissoires } 6395519cab4SBenjamin Tissoires 6405519cab4SBenjamin Tissoires static const struct hid_device_id mt_devices[] = { 6415519cab4SBenjamin Tissoires 642f786bba4SBenjamin Tissoires /* 3M panels */ 643f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 644f786bba4SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_3M, 645f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M1968) }, 646f786bba4SBenjamin Tissoires { .driver_data = MT_CLS_3M, 647f786bba4SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_3M, 648f786bba4SBenjamin Tissoires USB_DEVICE_ID_3M2256) }, 649f786bba4SBenjamin Tissoires 650e6aac342SBenjamin Tissoires /* ActionStar panels */ 651e6aac342SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 652e6aac342SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, 653e6aac342SBenjamin Tissoires USB_DEVICE_ID_ACTIONSTAR_1011) }, 654e6aac342SBenjamin Tissoires 655a841b62cSBenjamin Tissoires /* Cando panels */ 656a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 657a841b62cSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CANDO, 658a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, 659a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 660a841b62cSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CANDO, 661a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, 662a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 663a841b62cSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CANDO, 664a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, 665a841b62cSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 666a841b62cSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CANDO, 667a841b62cSBenjamin Tissoires USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, 668a841b62cSBenjamin Tissoires 669942fd422SAustin Zhang /* Chunghwa Telecom touch panels */ 670942fd422SAustin Zhang { .driver_data = MT_CLS_DEFAULT, 671942fd422SAustin Zhang HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, 672942fd422SAustin Zhang USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, 673942fd422SAustin Zhang 67479603dc9SBenjamin Tissoires /* CVTouch panels */ 67579603dc9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 67679603dc9SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, 67779603dc9SBenjamin Tissoires USB_DEVICE_ID_CVTOUCH_SCREEN) }, 67879603dc9SBenjamin Tissoires 679a3b5e577SBenjamin Tissoires /* Cypress panel */ 680a3b5e577SBenjamin Tissoires { .driver_data = MT_CLS_CYPRESS, 681a3b5e577SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, 682a3b5e577SBenjamin Tissoires USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, 683a3b5e577SBenjamin Tissoires 68422408283SBenjamin Tissoires /* eGalax devices (resistive) */ 68522408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 68622408283SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 687e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, 68822408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 68922408283SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 690e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, 69122408283SBenjamin Tissoires 69222408283SBenjamin Tissoires /* eGalax devices (capacitive) */ 69322408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 69422408283SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 695e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, 69622408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 69722408283SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 698e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, 69922408283SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 70022408283SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 701e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, 7021fd8f047SChris Bagwell { .driver_data = MT_CLS_EGALAX, 7031fd8f047SChris Bagwell HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 704*66f06127SBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, 705*66f06127SBenjamin Tissoires { .driver_data = MT_CLS_EGALAX, 706*66f06127SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 707bb9ff210SMarek Vasut USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, 708bb9ff210SMarek Vasut { .driver_data = MT_CLS_EGALAX, 709bb9ff210SMarek Vasut HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 710e36f690bSBenjamin Tissoires USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, 71122408283SBenjamin Tissoires 712c04abeefSBenjamin Tissoires /* Elo TouchSystems IntelliTouch Plus panel */ 713c04abeefSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, 714c04abeefSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_ELO, 715c04abeefSBenjamin Tissoires USB_DEVICE_ID_ELO_TS2515) }, 716c04abeefSBenjamin Tissoires 7175572da08SBenjamin Tissoires /* GeneralTouch panel */ 7181e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, 7195572da08SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 7205572da08SBenjamin Tissoires USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, 7215572da08SBenjamin Tissoires 722ee0fbd14SBenjamin Tissoires /* GoodTouch panels */ 723ee0fbd14SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 724ee0fbd14SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, 725ee0fbd14SBenjamin Tissoires USB_DEVICE_ID_GOODTOUCH_000f) }, 726ee0fbd14SBenjamin Tissoires 727a062cc5aSStephane Chatty /* Ideacom panel */ 728a062cc5aSStephane Chatty { .driver_data = MT_CLS_SERIAL, 729a062cc5aSStephane Chatty HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, 730a062cc5aSStephane Chatty USB_DEVICE_ID_IDEACOM_IDC6650) }, 731a062cc5aSStephane Chatty 7324e61f0d7SAustin Zhang /* Ilitek dual touch panel */ 7334e61f0d7SAustin Zhang { .driver_data = MT_CLS_DEFAULT, 7344e61f0d7SAustin Zhang HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, 7354e61f0d7SAustin Zhang USB_DEVICE_ID_ILITEK_MULTITOUCH) }, 7364e61f0d7SAustin Zhang 7374dfcced8SBenjamin Tissoires /* IRTOUCH panels */ 7384dfcced8SBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 7394dfcced8SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, 7404dfcced8SBenjamin Tissoires USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, 7414dfcced8SBenjamin Tissoires 742c50bb1a4SJeff Brown /* LG Display panels */ 743c50bb1a4SJeff Brown { .driver_data = MT_CLS_DEFAULT, 744c50bb1a4SJeff Brown HID_USB_DEVICE(USB_VENDOR_ID_LG, 745c50bb1a4SJeff Brown USB_DEVICE_ID_LG_MULTITOUCH) }, 746c50bb1a4SJeff Brown 747df167c4aSBenjamin Tissoires /* Lumio panels */ 748df167c4aSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 749df167c4aSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, 750df167c4aSBenjamin Tissoires USB_DEVICE_ID_CRYSTALTOUCH) }, 751c3ead6deSBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 752c3ead6deSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, 753c3ead6deSBenjamin Tissoires USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, 754df167c4aSBenjamin Tissoires 7554a6ee685SBenjamin Tissoires /* MosArt panels */ 7564a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 7574a6ee685SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_ASUS, 7584a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUS_T91MT)}, 7594a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 7604a6ee685SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_ASUS, 7614a6ee685SBenjamin Tissoires USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 7624a6ee685SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, 7634a6ee685SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, 7644a6ee685SBenjamin Tissoires USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 7654a6ee685SBenjamin Tissoires 7666ab3a9a6SJohn Sung /* PenMount panels */ 7676ab3a9a6SJohn Sung { .driver_data = MT_CLS_CONFIDENCE, 7686ab3a9a6SJohn Sung HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, 7696ab3a9a6SJohn Sung USB_DEVICE_ID_PENMOUNT_PCI) }, 7706ab3a9a6SJohn Sung 7715519cab4SBenjamin Tissoires /* PixCir-based panels */ 7721e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 7735519cab4SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_HANVON, 7745519cab4SBenjamin Tissoires USB_DEVICE_ID_HANVON_MULTITOUCH) }, 7751e9cf35bSBenjamin Tissoires { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, 7765519cab4SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_CANDO, 7775519cab4SBenjamin Tissoires USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, 7785519cab4SBenjamin Tissoires 779043b403aSBenjamin Tissoires /* Stantum panels */ 780bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 781043b403aSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, 782043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP)}, 783bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 78485a60082SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, 785043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_STM)}, 786bf5af9b5SBenjamin Tissoires { .driver_data = MT_CLS_CONFIDENCE, 78785a60082SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, 788043b403aSBenjamin Tissoires USB_DEVICE_ID_MTP_SITRONIX)}, 789043b403aSBenjamin Tissoires 7905e74e56dSBenjamin Tissoires /* Touch International panels */ 7915e74e56dSBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 7925e74e56dSBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, 7935e74e56dSBenjamin Tissoires USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, 7945e74e56dSBenjamin Tissoires 795617b64f9SBenjamin Tissoires /* Unitec panels */ 796617b64f9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 797617b64f9SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, 798617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, 799617b64f9SBenjamin Tissoires { .driver_data = MT_CLS_DEFAULT, 800617b64f9SBenjamin Tissoires HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, 801617b64f9SBenjamin Tissoires USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, 802bc8a2a9bSice chien /* XAT */ 803bc8a2a9bSice chien { .driver_data = MT_CLS_DEFAULT, 804bc8a2a9bSice chien HID_USB_DEVICE(USB_VENDOR_ID_XAT, 805bc8a2a9bSice chien USB_DEVICE_ID_XAT_CSR) }, 806617b64f9SBenjamin Tissoires 8075519cab4SBenjamin Tissoires { } 8085519cab4SBenjamin Tissoires }; 8095519cab4SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, mt_devices); 8105519cab4SBenjamin Tissoires 8115519cab4SBenjamin Tissoires static const struct hid_usage_id mt_grabbed_usages[] = { 8125519cab4SBenjamin Tissoires { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 8135519cab4SBenjamin Tissoires { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 8145519cab4SBenjamin Tissoires }; 8155519cab4SBenjamin Tissoires 8165519cab4SBenjamin Tissoires static struct hid_driver mt_driver = { 8175519cab4SBenjamin Tissoires .name = "hid-multitouch", 8185519cab4SBenjamin Tissoires .id_table = mt_devices, 8195519cab4SBenjamin Tissoires .probe = mt_probe, 8205519cab4SBenjamin Tissoires .remove = mt_remove, 8215519cab4SBenjamin Tissoires .input_mapping = mt_input_mapping, 8225519cab4SBenjamin Tissoires .input_mapped = mt_input_mapped, 8235519cab4SBenjamin Tissoires .feature_mapping = mt_feature_mapping, 8245519cab4SBenjamin Tissoires .usage_table = mt_grabbed_usages, 8255519cab4SBenjamin Tissoires .event = mt_event, 8265519cab4SBenjamin Tissoires #ifdef CONFIG_PM 8275519cab4SBenjamin Tissoires .reset_resume = mt_reset_resume, 8285519cab4SBenjamin Tissoires #endif 8295519cab4SBenjamin Tissoires }; 8305519cab4SBenjamin Tissoires 8315519cab4SBenjamin Tissoires static int __init mt_init(void) 8325519cab4SBenjamin Tissoires { 8335519cab4SBenjamin Tissoires return hid_register_driver(&mt_driver); 8345519cab4SBenjamin Tissoires } 8355519cab4SBenjamin Tissoires 8365519cab4SBenjamin Tissoires static void __exit mt_exit(void) 8375519cab4SBenjamin Tissoires { 8385519cab4SBenjamin Tissoires hid_unregister_driver(&mt_driver); 8395519cab4SBenjamin Tissoires } 8405519cab4SBenjamin Tissoires 8415519cab4SBenjamin Tissoires module_init(mt_init); 8425519cab4SBenjamin Tissoires module_exit(mt_exit); 843