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 27 struct ntrig_data { 28 __s32 x, y, id, w, h; 29 char reading_a_point, found_contact_id; 30 char pen_active; 31 char finger_active; 32 char inverted; 33 }; 34 35 /* 36 * this driver is aimed at two firmware versions in circulation: 37 * - dual pen/finger single touch 38 * - finger multitouch, pen not working 39 */ 40 41 static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, 42 struct hid_field *field, struct hid_usage *usage, 43 unsigned long **bit, int *max) 44 { 45 switch (usage->hid & HID_USAGE_PAGE) { 46 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 103 static 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 if (usage->type == EV_KEY || usage->type == EV_REL 108 || usage->type == EV_ABS) 109 clear_bit(usage->code, *bit); 110 111 return 0; 112 } 113 114 /* 115 * this function is called upon all reports 116 * so that we can filter contact point information, 117 * decide whether we are in multi or single touch mode 118 * and call input_mt_sync after each point if necessary 119 */ 120 static int ntrig_event (struct hid_device *hid, struct hid_field *field, 121 struct hid_usage *usage, __s32 value) 122 { 123 struct input_dev *input = field->hidinput->input; 124 struct ntrig_data *nd = hid_get_drvdata(hid); 125 126 if (hid->claimed & HID_CLAIMED_INPUT) { 127 switch (usage->hid) { 128 129 case HID_DG_INRANGE: 130 if (field->application & 0x3) 131 nd->pen_active = (value != 0); 132 else 133 nd->finger_active = (value != 0); 134 return 0; 135 136 case HID_DG_INVERT: 137 nd->inverted = value; 138 return 0; 139 140 case HID_GD_X: 141 nd->x = value; 142 nd->reading_a_point = 1; 143 break; 144 case HID_GD_Y: 145 nd->y = value; 146 break; 147 case HID_DG_CONTACTID: 148 nd->id = value; 149 /* we receive this only when in multitouch mode */ 150 nd->found_contact_id = 1; 151 break; 152 case HID_DG_WIDTH: 153 nd->w = value; 154 break; 155 case HID_DG_HEIGHT: 156 nd->h = value; 157 /* 158 * when in single touch mode, this is the last 159 * report received in a finger event. We want 160 * to emit a normal (X, Y) position 161 */ 162 if (!nd->found_contact_id) { 163 if (nd->pen_active && nd->finger_active) { 164 input_report_key(input, BTN_TOOL_DOUBLETAP, 0); 165 input_report_key(input, BTN_TOOL_DOUBLETAP, 1); 166 } 167 input_event(input, EV_ABS, ABS_X, nd->x); 168 input_event(input, EV_ABS, ABS_Y, nd->y); 169 } 170 break; 171 case HID_DG_TIPPRESSURE: 172 /* 173 * when in single touch mode, this is the last 174 * report received in a pen event. We want 175 * to emit a normal (X, Y) position 176 */ 177 if (! nd->found_contact_id) { 178 if (nd->pen_active && nd->finger_active) { 179 input_report_key(input, 180 nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN 181 , 0); 182 input_report_key(input, 183 nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN 184 , 1); 185 } 186 input_event(input, EV_ABS, ABS_X, nd->x); 187 input_event(input, EV_ABS, ABS_Y, nd->y); 188 input_event(input, EV_ABS, ABS_PRESSURE, value); 189 } 190 break; 191 case 0xff000002: 192 /* 193 * we receive this when the device is in multitouch 194 * mode. The first of the three values tagged with 195 * this usage tells if the contact point is real 196 * or a placeholder 197 */ 198 if (!nd->reading_a_point || value != 1) 199 break; 200 /* emit a normal (X, Y) for the first point only */ 201 if (nd->id == 0) { 202 input_event(input, EV_ABS, ABS_X, nd->x); 203 input_event(input, EV_ABS, ABS_Y, nd->y); 204 } 205 input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); 206 input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); 207 if (nd->w > nd->h) { 208 input_event(input, EV_ABS, 209 ABS_MT_ORIENTATION, 1); 210 input_event(input, EV_ABS, 211 ABS_MT_TOUCH_MAJOR, nd->w); 212 input_event(input, EV_ABS, 213 ABS_MT_TOUCH_MINOR, nd->h); 214 } else { 215 input_event(input, EV_ABS, 216 ABS_MT_ORIENTATION, 0); 217 input_event(input, EV_ABS, 218 ABS_MT_TOUCH_MAJOR, nd->h); 219 input_event(input, EV_ABS, 220 ABS_MT_TOUCH_MINOR, nd->w); 221 } 222 input_mt_sync(field->hidinput->input); 223 nd->reading_a_point = 0; 224 nd->found_contact_id = 0; 225 break; 226 227 default: 228 /* fallback to the generic hidinput handling */ 229 return 0; 230 } 231 } 232 233 /* we have handled the hidinput part, now remains hiddev */ 234 if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 235 hid->hiddev_hid_event(hid, field, usage, value); 236 237 return 1; 238 } 239 240 static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) 241 { 242 int ret; 243 struct ntrig_data *nd; 244 245 nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL); 246 if (!nd) { 247 dev_err(&hdev->dev, "cannot allocate N-Trig data\n"); 248 return -ENOMEM; 249 } 250 nd->reading_a_point = 0; 251 nd->found_contact_id = 0; 252 hid_set_drvdata(hdev, nd); 253 254 ret = hid_parse(hdev); 255 if (!ret) 256 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 257 258 if (ret) 259 kfree (nd); 260 261 return ret; 262 } 263 264 static void ntrig_remove(struct hid_device *hdev) 265 { 266 hid_hw_stop(hdev); 267 kfree(hid_get_drvdata(hdev)); 268 } 269 270 static const struct hid_device_id ntrig_devices[] = { 271 { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN), 272 .driver_data = NTRIG_DUPLICATE_USAGES }, 273 { } 274 }; 275 MODULE_DEVICE_TABLE(hid, ntrig_devices); 276 277 static const struct hid_usage_id ntrig_grabbed_usages[] = { 278 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 279 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 280 }; 281 282 static struct hid_driver ntrig_driver = { 283 .name = "ntrig", 284 .id_table = ntrig_devices, 285 .probe = ntrig_probe, 286 .remove = ntrig_remove, 287 .input_mapping = ntrig_input_mapping, 288 .input_mapped = ntrig_input_mapped, 289 .usage_table = ntrig_grabbed_usages, 290 .event = ntrig_event, 291 }; 292 293 static int __init ntrig_init(void) 294 { 295 return hid_register_driver(&ntrig_driver); 296 } 297 298 static void __exit ntrig_exit(void) 299 { 300 hid_unregister_driver(&ntrig_driver); 301 } 302 303 module_init(ntrig_init); 304 module_exit(ntrig_exit); 305 MODULE_LICENSE("GPL"); 306