hid-ntrig.c revision b0549cf1a35a92edf053d94066e60fb0ed02bb71
1/* 2 * HID driver for N-Trig touchscreens 3 * 4 * Copyright (c) 2008 Rafi Rubin 5 * Copyright (c) 2009 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/module.h> 19 20#include "hid-ids.h" 21 22#define NTRIG_DUPLICATE_USAGES 0x001 23 24#define nt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ 25 EV_KEY, (c)) 26 27struct ntrig_data { 28 __s32 x, y, id, w, h; 29 bool reading_a_point, found_contact_id; 30}; 31 32/* 33 * this driver is aimed at two firmware versions in circulation: 34 * - dual pen/finger single touch 35 * - finger multitouch, pen not working 36 */ 37 38static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, 39 struct hid_field *field, struct hid_usage *usage, 40 unsigned long **bit, int *max) 41{ 42 /* No special mappings needed for the pen */ 43 if (field->application == HID_DG_PEN) 44 return 0; 45 46 switch (usage->hid & HID_USAGE_PAGE) { 47 case HID_UP_GENDESK: 48 switch (usage->hid) { 49 case HID_GD_X: 50 hid_map_usage(hi, usage, bit, max, 51 EV_ABS, ABS_MT_POSITION_X); 52 input_set_abs_params(hi->input, ABS_X, 53 field->logical_minimum, 54 field->logical_maximum, 0, 0); 55 return 1; 56 case HID_GD_Y: 57 hid_map_usage(hi, usage, bit, max, 58 EV_ABS, ABS_MT_POSITION_Y); 59 input_set_abs_params(hi->input, ABS_Y, 60 field->logical_minimum, 61 field->logical_maximum, 0, 0); 62 return 1; 63 } 64 return 0; 65 66 case HID_UP_DIGITIZER: 67 switch (usage->hid) { 68 /* we do not want to map these for now */ 69 case HID_DG_CONTACTID: /* value is useless */ 70 case HID_DG_INPUTMODE: 71 case HID_DG_DEVICEINDEX: 72 case HID_DG_CONTACTCOUNT: 73 case HID_DG_CONTACTMAX: 74 return -1; 75 76 /* original mapping by Rafi Rubin */ 77 case HID_DG_CONFIDENCE: 78 nt_map_key_clear(BTN_TOOL_DOUBLETAP); 79 return 1; 80 81 /* width/height mapped on TouchMajor/TouchMinor/Orientation */ 82 case HID_DG_WIDTH: 83 hid_map_usage(hi, usage, bit, max, 84 EV_ABS, ABS_MT_TOUCH_MAJOR); 85 return 1; 86 case HID_DG_HEIGHT: 87 hid_map_usage(hi, usage, bit, max, 88 EV_ABS, ABS_MT_TOUCH_MINOR); 89 input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 90 0, 1, 0, 0); 91 return 1; 92 } 93 return 0; 94 95 case 0xff000000: 96 /* we do not want to map these: no input-oriented meaning */ 97 return -1; 98 } 99 100 return 0; 101} 102 103static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, 104 struct hid_field *field, struct hid_usage *usage, 105 unsigned long **bit, int *max) 106{ 107 /* No special mappings needed for the pen */ 108 if (field->application == HID_DG_PEN) 109 return 0; 110 111 if (usage->type == EV_KEY || usage->type == EV_REL 112 || usage->type == EV_ABS) 113 clear_bit(usage->code, *bit); 114 115 return 0; 116} 117 118/* 119 * this function is called upon all reports 120 * so that we can filter contact point information, 121 * decide whether we are in multi or single touch mode 122 * and call input_mt_sync after each point if necessary 123 */ 124static int ntrig_event (struct hid_device *hid, struct hid_field *field, 125 struct hid_usage *usage, __s32 value) 126{ 127 struct input_dev *input = field->hidinput->input; 128 struct ntrig_data *nd = hid_get_drvdata(hid); 129 130 /* No special handling needed for the pen */ 131 if (field->application == HID_DG_PEN) 132 return 0; 133 134 if (hid->claimed & HID_CLAIMED_INPUT) { 135 switch (usage->hid) { 136 case HID_GD_X: 137 nd->x = value; 138 nd->reading_a_point = 1; 139 break; 140 case HID_GD_Y: 141 nd->y = value; 142 break; 143 case HID_DG_CONTACTID: 144 nd->id = value; 145 /* we receive this only when in multitouch mode */ 146 nd->found_contact_id = 1; 147 break; 148 case HID_DG_WIDTH: 149 nd->w = value; 150 break; 151 case HID_DG_HEIGHT: 152 nd->h = value; 153 /* 154 * when in single touch mode, this is the last 155 * report received in a finger event. We want 156 * to emit a normal (X, Y) position 157 */ 158 if (!nd->found_contact_id) { 159 input_event(input, EV_ABS, ABS_X, nd->x); 160 input_event(input, EV_ABS, ABS_Y, nd->y); 161 } 162 break; 163 case 0xff000002: 164 /* 165 * we receive this when the device is in multitouch 166 * mode. The first of the three values tagged with 167 * this usage tells if the contact point is real 168 * or a placeholder 169 */ 170 if (!nd->reading_a_point || value != 1) 171 break; 172 /* emit a normal (X, Y) for the first point only */ 173 if (nd->id == 0) { 174 input_event(input, EV_ABS, ABS_X, nd->x); 175 input_event(input, EV_ABS, ABS_Y, nd->y); 176 } 177 input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); 178 input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); 179 if (nd->w > nd->h) { 180 input_event(input, EV_ABS, 181 ABS_MT_ORIENTATION, 1); 182 input_event(input, EV_ABS, 183 ABS_MT_TOUCH_MAJOR, nd->w); 184 input_event(input, EV_ABS, 185 ABS_MT_TOUCH_MINOR, nd->h); 186 } else { 187 input_event(input, EV_ABS, 188 ABS_MT_ORIENTATION, 0); 189 input_event(input, EV_ABS, 190 ABS_MT_TOUCH_MAJOR, nd->h); 191 input_event(input, EV_ABS, 192 ABS_MT_TOUCH_MINOR, nd->w); 193 } 194 input_mt_sync(field->hidinput->input); 195 nd->reading_a_point = 0; 196 nd->found_contact_id = 0; 197 break; 198 199 default: 200 /* fallback to the generic hidinput handling */ 201 return 0; 202 } 203 } 204 205 /* we have handled the hidinput part, now remains hiddev */ 206 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event) 207 hid->hiddev_hid_event(hid, field, usage, value); 208 209 return 1; 210} 211 212static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) 213{ 214 int ret; 215 struct ntrig_data *nd; 216 struct hid_input *hidinput; 217 struct input_dev *input; 218 219 if (id->driver_data) 220 hdev->quirks |= HID_QUIRK_MULTI_INPUT; 221 222 nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL); 223 if (!nd) { 224 dev_err(&hdev->dev, "cannot allocate N-Trig data\n"); 225 return -ENOMEM; 226 } 227 nd->reading_a_point = 0; 228 nd->found_contact_id = 0; 229 hid_set_drvdata(hdev, nd); 230 231 ret = hid_parse(hdev); 232 if (ret) { 233 dev_err(&hdev->dev, "parse failed\n"); 234 goto err_free; 235 } 236 237 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); 238 if (ret) { 239 dev_err(&hdev->dev, "hw start failed\n"); 240 goto err_free; 241 } 242 243 244 list_for_each_entry(hidinput, &hdev->inputs, list) { 245 input = hidinput->input; 246 switch (hidinput->report->field[0]->application) { 247 case HID_DG_PEN: 248 input->name = "N-Trig Pen"; 249 break; 250 case HID_DG_TOUCHSCREEN: 251 /* 252 * The physical touchscreen (single touch) 253 * input has a value for physical, whereas 254 * the multitouch only has logical input 255 * fields. 256 */ 257 input->name = 258 (hidinput->report->field[0] 259 ->physical) ? 260 "N-Trig Touchscreen" : 261 "N-Trig MultiTouch"; 262 break; 263 } 264 } 265 266 return 0; 267err_free: 268 kfree(nd); 269 return ret; 270} 271 272static void ntrig_remove(struct hid_device *hdev) 273{ 274 hid_hw_stop(hdev); 275 kfree(hid_get_drvdata(hdev)); 276} 277 278static const struct hid_device_id ntrig_devices[] = { 279 { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN), 280 .driver_data = NTRIG_DUPLICATE_USAGES }, 281 { } 282}; 283MODULE_DEVICE_TABLE(hid, ntrig_devices); 284 285static const struct hid_usage_id ntrig_grabbed_usages[] = { 286 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 287 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 } 288}; 289 290static struct hid_driver ntrig_driver = { 291 .name = "ntrig", 292 .id_table = ntrig_devices, 293 .probe = ntrig_probe, 294 .remove = ntrig_remove, 295 .input_mapping = ntrig_input_mapping, 296 .input_mapped = ntrig_input_mapped, 297 .usage_table = ntrig_grabbed_usages, 298 .event = ntrig_event, 299}; 300 301static int __init ntrig_init(void) 302{ 303 return hid_register_driver(&ntrig_driver); 304} 305 306static void __exit ntrig_exit(void) 307{ 308 hid_unregister_driver(&ntrig_driver); 309} 310 311module_init(ntrig_init); 312module_exit(ntrig_exit); 313MODULE_LICENSE("GPL"); 314