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