hid-ntrig.c revision c0858552c088616c18879c347d9e0daa98cf2b15
1/* 2 * HID driver for N-Trig touchscreens 3 * 4 * Copyright (c) 2008-2010 Rafi Rubin 5 * Copyright (c) 2009-2010 Stephane Chatty 6 * 7 */ 8 9/* 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the Free 12 * Software Foundation; either version 2 of the License, or (at your option) 13 * any later version. 14 */ 15 16#include <linux/device.h> 17#include <linux/hid.h> 18#include <linux/usb.h> 19#include "usbhid/usbhid.h" 20#include <linux/module.h> 21#include <linux/slab.h> 22 23#include "hid-ids.h" 24 25#define NTRIG_DUPLICATE_USAGES 0x001 26 27#define nt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ 28 EV_KEY, (c)) 29 30struct ntrig_data { 31 /* Incoming raw values for a single contact */ 32 __u16 x, y, w, h; 33 __u16 id; 34 __u8 confidence; 35 36 bool reading_mt; 37 __u8 first_contact_confidence; 38 39 __u8 mt_footer[4]; 40 __u8 mt_foot_count; 41}; 42 43/* 44 * this driver is aimed at two firmware versions in circulation: 45 * - dual pen/finger single touch 46 * - finger multitouch, pen not working 47 */ 48 49static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, 50 struct hid_field *field, struct hid_usage *usage, 51 unsigned long **bit, int *max) 52{ 53 /* No special mappings needed for the pen and single touch */ 54 if (field->physical) 55 return 0; 56 57 switch (usage->hid & HID_USAGE_PAGE) { 58 case HID_UP_GENDESK: 59 switch (usage->hid) { 60 case HID_GD_X: 61 hid_map_usage(hi, usage, bit, max, 62 EV_ABS, ABS_MT_POSITION_X); 63 input_set_abs_params(hi->input, ABS_X, 64 field->logical_minimum, 65 field->logical_maximum, 0, 0); 66 return 1; 67 case HID_GD_Y: 68 hid_map_usage(hi, usage, bit, max, 69 EV_ABS, ABS_MT_POSITION_Y); 70 input_set_abs_params(hi->input, ABS_Y, 71 field->logical_minimum, 72 field->logical_maximum, 0, 0); 73 return 1; 74 } 75 return 0; 76 77 case HID_UP_DIGITIZER: 78 switch (usage->hid) { 79 /* we do not want to map these for now */ 80 case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */ 81 case HID_DG_INPUTMODE: 82 case HID_DG_DEVICEINDEX: 83 case HID_DG_CONTACTMAX: 84 return -1; 85 86 /* width/height mapped on TouchMajor/TouchMinor/Orientation */ 87 case HID_DG_WIDTH: 88 hid_map_usage(hi, usage, bit, max, 89 EV_ABS, ABS_MT_TOUCH_MAJOR); 90 return 1; 91 case HID_DG_HEIGHT: 92 hid_map_usage(hi, usage, bit, max, 93 EV_ABS, ABS_MT_TOUCH_MINOR); 94 input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 95 0, 1, 0, 0); 96 return 1; 97 } 98 return 0; 99 100 case 0xff000000: 101 /* we do not want to map these: no input-oriented meaning */ 102 return -1; 103 } 104 105 return 0; 106} 107 108static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, 109 struct hid_field *field, struct hid_usage *usage, 110 unsigned long **bit, int *max) 111{ 112 /* No special mappings needed for the pen and single touch */ 113 if (field->physical) 114 return 0; 115 116 if (usage->type == EV_KEY || usage->type == EV_REL 117 || usage->type == EV_ABS) 118 clear_bit(usage->code, *bit); 119 120 return 0; 121} 122 123/* 124 * this function is called upon all reports 125 * so that we can filter contact point information, 126 * decide whether we are in multi or single touch mode 127 * and call input_mt_sync after each point if necessary 128 */ 129static int ntrig_event (struct hid_device *hid, struct hid_field *field, 130 struct hid_usage *usage, __s32 value) 131{ 132 struct input_dev *input = field->hidinput->input; 133 struct ntrig_data *nd = hid_get_drvdata(hid); 134 135 /* No special handling needed for the pen */ 136 if (field->application == HID_DG_PEN) 137 return 0; 138 139 if (hid->claimed & HID_CLAIMED_INPUT) { 140 switch (usage->hid) { 141 case 0xff000001: 142 /* Tag indicating the start of a multitouch group */ 143 nd->reading_mt = 1; 144 nd->first_contact_confidence = 0; 145 break; 146 case HID_DG_TIPSWITCH: 147 /* Prevent emission of touch until validated */ 148 return 1; 149 case HID_DG_CONFIDENCE: 150 nd->confidence = value; 151 break; 152 case HID_GD_X: 153 nd->x = value; 154 /* Clear the contact footer */ 155 nd->mt_foot_count = 0; 156 break; 157 case HID_GD_Y: 158 nd->y = value; 159 break; 160 case HID_DG_CONTACTID: 161 nd->id = value; 162 break; 163 case HID_DG_WIDTH: 164 nd->w = value; 165 break; 166 case HID_DG_HEIGHT: 167 nd->h = value; 168 /* 169 * when in single touch mode, this is the last 170 * report received in a finger event. We want 171 * to emit a normal (X, Y) position 172 */ 173 if (!nd->reading_mt) { 174 input_report_key(input, BTN_TOOL_DOUBLETAP, 175 (nd->confidence != 0)); 176 input_event(input, EV_ABS, ABS_X, nd->x); 177 input_event(input, EV_ABS, ABS_Y, nd->y); 178 } 179 break; 180 case 0xff000002: 181 /* 182 * we receive this when the device is in multitouch 183 * mode. The first of the three values tagged with 184 * this usage tells if the contact point is real 185 * or a placeholder 186 */ 187 188 /* Shouldn't get more than 4 footer packets, so skip */ 189 if (nd->mt_foot_count >= 4) 190 break; 191 192 nd->mt_footer[nd->mt_foot_count++] = value; 193 194 /* if the footer isn't complete break */ 195 if (nd->mt_foot_count != 4) 196 break; 197 198 /* Pen activity signal, trigger end of touch. */ 199 if (nd->mt_footer[2]) { 200 nd->confidence = 0; 201 break; 202 } 203 204 /* If the contact was invalid */ 205 if (!(nd->confidence && nd->mt_footer[0]) 206 || nd->w <= 250 207 || nd->h <= 190) { 208 nd->confidence = 0; 209 break; 210 } 211 212 /* emit a normal (X, Y) for the first point only */ 213 if (nd->id == 0) { 214 nd->first_contact_confidence = nd->confidence; 215 input_event(input, EV_ABS, ABS_X, nd->x); 216 input_event(input, EV_ABS, ABS_Y, nd->y); 217 } 218 input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); 219 input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); 220 if (nd->w > nd->h) { 221 input_event(input, EV_ABS, 222 ABS_MT_ORIENTATION, 1); 223 input_event(input, EV_ABS, 224 ABS_MT_TOUCH_MAJOR, nd->w); 225 input_event(input, EV_ABS, 226 ABS_MT_TOUCH_MINOR, nd->h); 227 } else { 228 input_event(input, EV_ABS, 229 ABS_MT_ORIENTATION, 0); 230 input_event(input, EV_ABS, 231 ABS_MT_TOUCH_MAJOR, nd->h); 232 input_event(input, EV_ABS, 233 ABS_MT_TOUCH_MINOR, nd->w); 234 } 235 input_mt_sync(field->hidinput->input); 236 break; 237 238 case HID_DG_CONTACTCOUNT: /* End of a multitouch group */ 239 if (!nd->reading_mt) 240 break; 241 242 nd->reading_mt = 0; 243 244 if (nd->first_contact_confidence) { 245 switch (value) { 246 case 0: /* for single touch devices */ 247 case 1: 248 input_report_key(input, 249 BTN_TOOL_DOUBLETAP, 1); 250 break; 251 case 2: 252 input_report_key(input, 253 BTN_TOOL_TRIPLETAP, 1); 254 break; 255 case 3: 256 default: 257 input_report_key(input, 258 BTN_TOOL_QUADTAP, 1); 259 } 260 input_report_key(input, BTN_TOUCH, 1); 261 } else { 262 input_report_key(input, 263 BTN_TOOL_DOUBLETAP, 0); 264 input_report_key(input, 265 BTN_TOOL_TRIPLETAP, 0); 266 input_report_key(input, 267 BTN_TOOL_QUADTAP, 0); 268 input_report_key(input, BTN_TOUCH, 0); 269 } 270 break; 271 272 default: 273 /* fallback to the generic hidinput handling */ 274 return 0; 275 } 276 } 277 278 /* we have handled the hidinput part, now remains hiddev */ 279 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event) 280 hid->hiddev_hid_event(hid, field, usage, value); 281 282 return 1; 283} 284 285static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) 286{ 287 int ret; 288 struct ntrig_data *nd; 289 struct hid_input *hidinput; 290 struct input_dev *input; 291 struct hid_report *report; 292 293 if (id->driver_data) 294 hdev->quirks |= HID_QUIRK_MULTI_INPUT; 295 296 nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL); 297 if (!nd) { 298 dev_err(&hdev->dev, "cannot allocate N-Trig data\n"); 299 return -ENOMEM; 300 } 301 302 nd->reading_mt = 0; 303 hid_set_drvdata(hdev, nd); 304 305 ret = hid_parse(hdev); 306 if (ret) { 307 dev_err(&hdev->dev, "parse failed\n"); 308 goto err_free; 309 } 310 311 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); 312 if (ret) { 313 dev_err(&hdev->dev, "hw start failed\n"); 314 goto err_free; 315 } 316 317 318 list_for_each_entry(hidinput, &hdev->inputs, list) { 319 if (hidinput->report->maxfield < 1) 320 continue; 321 322 input = hidinput->input; 323 switch (hidinput->report->field[0]->application) { 324 case HID_DG_PEN: 325 input->name = "N-Trig Pen"; 326 break; 327 case HID_DG_TOUCHSCREEN: 328 /* These keys are redundant for fingers, clear them 329 * to prevent incorrect identification */ 330 __clear_bit(BTN_TOOL_PEN, input->keybit); 331 __clear_bit(BTN_TOOL_FINGER, input->keybit); 332 __clear_bit(BTN_0, input->keybit); 333 /* 334 * A little something special to enable 335 * two and three finger taps. 336 */ 337 __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); 338 __set_bit(BTN_TOOL_TRIPLETAP, input->keybit); 339 __set_bit(BTN_TOOL_QUADTAP, input->keybit); 340 /* 341 * The physical touchscreen (single touch) 342 * input has a value for physical, whereas 343 * the multitouch only has logical input 344 * fields. 345 */ 346 input->name = 347 (hidinput->report->field[0] 348 ->physical) ? 349 "N-Trig Touchscreen" : 350 "N-Trig MultiTouch"; 351 break; 352 } 353 } 354 355 /* This is needed for devices with more recent firmware versions */ 356 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a]; 357 if (report) 358 usbhid_submit_report(hdev, report, USB_DIR_OUT); 359 360 361 return 0; 362err_free: 363 kfree(nd); 364 return ret; 365} 366 367static void ntrig_remove(struct hid_device *hdev) 368{ 369 hid_hw_stop(hdev); 370 kfree(hid_get_drvdata(hdev)); 371} 372 373static const struct hid_device_id ntrig_devices[] = { 374 { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN), 375 .driver_data = NTRIG_DUPLICATE_USAGES }, 376 { } 377}; 378MODULE_DEVICE_TABLE(hid, ntrig_devices); 379 380static const struct hid_usage_id ntrig_grabbed_usages[] = { 381 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 382 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 } 383}; 384 385static struct hid_driver ntrig_driver = { 386 .name = "ntrig", 387 .id_table = ntrig_devices, 388 .probe = ntrig_probe, 389 .remove = ntrig_remove, 390 .input_mapping = ntrig_input_mapping, 391 .input_mapped = ntrig_input_mapped, 392 .usage_table = ntrig_grabbed_usages, 393 .event = ntrig_event, 394}; 395 396static int __init ntrig_init(void) 397{ 398 return hid_register_driver(&ntrig_driver); 399} 400 401static void __exit ntrig_exit(void) 402{ 403 hid_unregister_driver(&ntrig_driver); 404} 405 406module_init(ntrig_init); 407module_exit(ntrig_exit); 408MODULE_LICENSE("GPL"); 409