1/* 2 * HID driver for eGalax dual-touch panels 3 * 4 * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> 5 * 6 */ 7 8/* 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 */ 14 15#include <linux/device.h> 16#include <linux/hid.h> 17#include <linux/module.h> 18#include <linux/usb.h> 19#include <linux/slab.h> 20#include "usbhid/usbhid.h" 21 22MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); 23MODULE_DESCRIPTION("eGalax dual-touch panel"); 24MODULE_LICENSE("GPL"); 25 26#include "hid-ids.h" 27 28struct egalax_data { 29 __u16 x, y, z; 30 __u8 id; 31 bool first; /* is this the first finger in the frame? */ 32 bool valid; /* valid finger data, or just placeholder? */ 33 bool activity; /* at least one active finger previously? */ 34 __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */ 35}; 36 37static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, 38 struct hid_field *field, struct hid_usage *usage, 39 unsigned long **bit, int *max) 40{ 41 switch (usage->hid & HID_USAGE_PAGE) { 42 43 case HID_UP_GENDESK: 44 switch (usage->hid) { 45 case HID_GD_X: 46 hid_map_usage(hi, usage, bit, max, 47 EV_ABS, ABS_MT_POSITION_X); 48 /* touchscreen emulation */ 49 input_set_abs_params(hi->input, ABS_X, 50 field->logical_minimum, 51 field->logical_maximum, 0, 0); 52 return 1; 53 case HID_GD_Y: 54 hid_map_usage(hi, usage, bit, max, 55 EV_ABS, ABS_MT_POSITION_Y); 56 /* touchscreen emulation */ 57 input_set_abs_params(hi->input, ABS_Y, 58 field->logical_minimum, 59 field->logical_maximum, 0, 0); 60 return 1; 61 } 62 return 0; 63 64 case HID_UP_DIGITIZER: 65 switch (usage->hid) { 66 case HID_DG_TIPSWITCH: 67 /* touchscreen emulation */ 68 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); 69 return 1; 70 case HID_DG_INRANGE: 71 case HID_DG_CONFIDENCE: 72 case HID_DG_CONTACTCOUNT: 73 case HID_DG_CONTACTMAX: 74 return -1; 75 case HID_DG_CONTACTID: 76 hid_map_usage(hi, usage, bit, max, 77 EV_ABS, ABS_MT_TRACKING_ID); 78 return 1; 79 case HID_DG_TIPPRESSURE: 80 hid_map_usage(hi, usage, bit, max, 81 EV_ABS, ABS_MT_PRESSURE); 82 /* touchscreen emulation */ 83 input_set_abs_params(hi->input, ABS_PRESSURE, 84 field->logical_minimum, 85 field->logical_maximum, 0, 0); 86 return 1; 87 } 88 return 0; 89 } 90 91 /* ignore others (from other reports we won't get anyway) */ 92 return -1; 93} 94 95static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, 96 struct hid_field *field, struct hid_usage *usage, 97 unsigned long **bit, int *max) 98{ 99 if (usage->type == EV_KEY || usage->type == EV_ABS) 100 clear_bit(usage->code, *bit); 101 102 return 0; 103} 104 105/* 106 * this function is called when a whole finger has been parsed, 107 * so that it can decide what to send to the input layer. 108 */ 109static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) 110{ 111 td->first = !td->first; /* touchscreen emulation */ 112 113 if (td->valid) { 114 /* emit multitouch events */ 115 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); 116 input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3); 117 input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3); 118 input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); 119 120 input_mt_sync(input); 121 122 /* 123 * touchscreen emulation: store (x, y) as 124 * the last valid values in this frame 125 */ 126 td->lastx = td->x; 127 td->lasty = td->y; 128 td->lastz = td->z; 129 } 130 131 /* 132 * touchscreen emulation: if this is the second finger and at least 133 * one in this frame is valid, the latest valid in the frame is 134 * the oldest on the panel, the one we want for single touch 135 */ 136 if (!td->first && td->activity) { 137 input_event(input, EV_ABS, ABS_X, td->lastx >> 3); 138 input_event(input, EV_ABS, ABS_Y, td->lasty >> 3); 139 input_event(input, EV_ABS, ABS_PRESSURE, td->lastz); 140 } 141 142 if (!td->valid) { 143 /* 144 * touchscreen emulation: if the first finger is invalid 145 * and there previously was finger activity, this is a release 146 */ 147 if (td->first && td->activity) { 148 input_event(input, EV_KEY, BTN_TOUCH, 0); 149 td->activity = false; 150 } 151 return; 152 } 153 154 155 /* touchscreen emulation: if no previous activity, emit touch event */ 156 if (!td->activity) { 157 input_event(input, EV_KEY, BTN_TOUCH, 1); 158 td->activity = true; 159 } 160} 161 162 163static int egalax_event(struct hid_device *hid, struct hid_field *field, 164 struct hid_usage *usage, __s32 value) 165{ 166 struct egalax_data *td = hid_get_drvdata(hid); 167 168 /* Note, eGalax has two product lines: the first is resistive and 169 * uses a standard parallel multitouch protocol (product ID == 170 * 48xx). The second is capacitive and uses an unusual "serial" 171 * protocol with a different message for each multitouch finger 172 * (product ID == 72xx). We do not yet generate a correct event 173 * sequence for the capacitive/serial protocol. 174 */ 175 if (hid->claimed & HID_CLAIMED_INPUT) { 176 struct input_dev *input = field->hidinput->input; 177 178 switch (usage->hid) { 179 case HID_DG_INRANGE: 180 case HID_DG_CONFIDENCE: 181 /* avoid interference from generic hidinput handling */ 182 break; 183 case HID_DG_TIPSWITCH: 184 td->valid = value; 185 break; 186 case HID_DG_TIPPRESSURE: 187 td->z = value; 188 break; 189 case HID_DG_CONTACTID: 190 td->id = value; 191 break; 192 case HID_GD_X: 193 td->x = value; 194 break; 195 case HID_GD_Y: 196 td->y = value; 197 /* this is the last field in a finger */ 198 egalax_filter_event(td, input); 199 break; 200 case HID_DG_CONTACTCOUNT: 201 /* touch emulation: this is the last field in a frame */ 202 td->first = false; 203 break; 204 205 default: 206 /* fallback to the generic hidinput handling */ 207 return 0; 208 } 209 } 210 211 /* we have handled the hidinput part, now remains hiddev */ 212 if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 213 hid->hiddev_hid_event(hid, field, usage, value); 214 215 return 1; 216} 217 218static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id) 219{ 220 int ret; 221 struct egalax_data *td; 222 struct hid_report *report; 223 224 td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL); 225 if (!td) { 226 dev_err(&hdev->dev, "cannot allocate eGalax data\n"); 227 return -ENOMEM; 228 } 229 hid_set_drvdata(hdev, td); 230 231 ret = hid_parse(hdev); 232 if (ret) 233 goto end; 234 235 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 236 if (ret) 237 goto end; 238 239 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[5]; 240 if (report) { 241 report->field[0]->value[0] = 2; 242 usbhid_submit_report(hdev, report, USB_DIR_OUT); 243 } 244 245end: 246 if (ret) 247 kfree(td); 248 249 return ret; 250} 251 252static void egalax_remove(struct hid_device *hdev) 253{ 254 hid_hw_stop(hdev); 255 kfree(hid_get_drvdata(hdev)); 256 hid_set_drvdata(hdev, NULL); 257} 258 259static const struct hid_device_id egalax_devices[] = { 260 { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 261 USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, 262 { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, 263 USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, 264 { } 265}; 266MODULE_DEVICE_TABLE(hid, egalax_devices); 267 268static const struct hid_usage_id egalax_grabbed_usages[] = { 269 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 270 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 271}; 272 273static struct hid_driver egalax_driver = { 274 .name = "egalax-touch", 275 .id_table = egalax_devices, 276 .probe = egalax_probe, 277 .remove = egalax_remove, 278 .input_mapping = egalax_input_mapping, 279 .input_mapped = egalax_input_mapped, 280 .usage_table = egalax_grabbed_usages, 281 .event = egalax_event, 282}; 283 284static int __init egalax_init(void) 285{ 286 return hid_register_driver(&egalax_driver); 287} 288 289static void __exit egalax_exit(void) 290{ 291 hid_unregister_driver(&egalax_driver); 292} 293 294module_init(egalax_init); 295module_exit(egalax_exit); 296