aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-ntrig.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/hid/hid-ntrig.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/hid/hid-ntrig.c')
-rw-r--r--drivers/hid/hid-ntrig.c230
1 files changed, 160 insertions, 70 deletions
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 49ce69d7bba7..4777bbfa1cc2 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -1,8 +1,8 @@
1/* 1/*
2 * HID driver for N-Trig touchscreens 2 * HID driver for N-Trig touchscreens
3 * 3 *
4 * Copyright (c) 2008 Rafi Rubin 4 * Copyright (c) 2008-2010 Rafi Rubin
5 * Copyright (c) 2009 Stephane Chatty 5 * Copyright (c) 2009-2010 Stephane Chatty
6 * 6 *
7 */ 7 */
8 8
@@ -15,21 +15,28 @@
15 15
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/hid.h> 17#include <linux/hid.h>
18#include <linux/usb.h>
19#include "usbhid/usbhid.h"
18#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/slab.h>
19 22
20#include "hid-ids.h" 23#include "hid-ids.h"
21 24
22#define NTRIG_DUPLICATE_USAGES 0x001 25#define NTRIG_DUPLICATE_USAGES 0x001
23 26
24#define nt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
25 EV_KEY, (c))
26
27struct ntrig_data { 27struct ntrig_data {
28 __s32 x, y, id, w, h; 28 /* Incoming raw values for a single contact */
29 char reading_a_point, found_contact_id; 29 __u16 x, y, w, h;
30 char pen_active; 30 __u16 id;
31 char finger_active; 31
32 char inverted; 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;
33}; 40};
34 41
35/* 42/*
@@ -42,8 +49,11 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
42 struct hid_field *field, struct hid_usage *usage, 49 struct hid_field *field, struct hid_usage *usage,
43 unsigned long **bit, int *max) 50 unsigned long **bit, int *max)
44{ 51{
45 switch (usage->hid & HID_USAGE_PAGE) { 52 /* No special mappings needed for the pen and single touch */
53 if (field->physical)
54 return 0;
46 55
56 switch (usage->hid & HID_USAGE_PAGE) {
47 case HID_UP_GENDESK: 57 case HID_UP_GENDESK:
48 switch (usage->hid) { 58 switch (usage->hid) {
49 case HID_GD_X: 59 case HID_GD_X:
@@ -66,18 +76,12 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
66 case HID_UP_DIGITIZER: 76 case HID_UP_DIGITIZER:
67 switch (usage->hid) { 77 switch (usage->hid) {
68 /* we do not want to map these for now */ 78 /* we do not want to map these for now */
69 case HID_DG_CONTACTID: /* value is useless */ 79 case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */
70 case HID_DG_INPUTMODE: 80 case HID_DG_INPUTMODE:
71 case HID_DG_DEVICEINDEX: 81 case HID_DG_DEVICEINDEX:
72 case HID_DG_CONTACTCOUNT:
73 case HID_DG_CONTACTMAX: 82 case HID_DG_CONTACTMAX:
74 return -1; 83 return -1;
75 84
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 */ 85 /* width/height mapped on TouchMajor/TouchMinor/Orientation */
82 case HID_DG_WIDTH: 86 case HID_DG_WIDTH:
83 hid_map_usage(hi, usage, bit, max, 87 hid_map_usage(hi, usage, bit, max,
@@ -104,6 +108,10 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
104 struct hid_field *field, struct hid_usage *usage, 108 struct hid_field *field, struct hid_usage *usage,
105 unsigned long **bit, int *max) 109 unsigned long **bit, int *max)
106{ 110{
111 /* No special mappings needed for the pen and single touch */
112 if (field->physical)
113 return 0;
114
107 if (usage->type == EV_KEY || usage->type == EV_REL 115 if (usage->type == EV_KEY || usage->type == EV_REL
108 || usage->type == EV_ABS) 116 || usage->type == EV_ABS)
109 clear_bit(usage->code, *bit); 117 clear_bit(usage->code, *bit);
@@ -123,31 +131,34 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
123 struct input_dev *input = field->hidinput->input; 131 struct input_dev *input = field->hidinput->input;
124 struct ntrig_data *nd = hid_get_drvdata(hid); 132 struct ntrig_data *nd = hid_get_drvdata(hid);
125 133
134 /* No special handling needed for the pen */
135 if (field->application == HID_DG_PEN)
136 return 0;
137
126 if (hid->claimed & HID_CLAIMED_INPUT) { 138 if (hid->claimed & HID_CLAIMED_INPUT) {
127 switch (usage->hid) { 139 switch (usage->hid) {
128 140 case 0xff000001:
129 case HID_DG_INRANGE: 141 /* Tag indicating the start of a multitouch group */
130 if (field->application & 0x3) 142 nd->reading_mt = 1;
131 nd->pen_active = (value != 0); 143 nd->first_contact_touch = 0;
132 else 144 break;
133 nd->finger_active = (value != 0); 145 case HID_DG_TIPSWITCH:
134 return 0; 146 nd->tipswitch = value;
135 147 /* Prevent emission of touch until validated */
136 case HID_DG_INVERT: 148 return 1;
137 nd->inverted = value; 149 case HID_DG_CONFIDENCE:
138 return 0; 150 nd->confidence = value;
139 151 break;
140 case HID_GD_X: 152 case HID_GD_X:
141 nd->x = value; 153 nd->x = value;
142 nd->reading_a_point = 1; 154 /* Clear the contact footer */
155 nd->mt_foot_count = 0;
143 break; 156 break;
144 case HID_GD_Y: 157 case HID_GD_Y:
145 nd->y = value; 158 nd->y = value;
146 break; 159 break;
147 case HID_DG_CONTACTID: 160 case HID_DG_CONTACTID:
148 nd->id = value; 161 nd->id = value;
149 /* we receive this only when in multitouch mode */
150 nd->found_contact_id = 1;
151 break; 162 break;
152 case HID_DG_WIDTH: 163 case HID_DG_WIDTH:
153 nd->w = value; 164 nd->w = value;
@@ -159,33 +170,17 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
159 * report received in a finger event. We want 170 * report received in a finger event. We want
160 * to emit a normal (X, Y) position 171 * to emit a normal (X, Y) position
161 */ 172 */
162 if (!nd->found_contact_id) { 173 if (!nd->reading_mt) {
163 if (nd->pen_active && nd->finger_active) { 174 /*
164 input_report_key(input, BTN_TOOL_DOUBLETAP, 0); 175 * TipSwitch indicates the presence of a
165 input_report_key(input, BTN_TOOL_DOUBLETAP, 1); 176 * finger in single touch mode.
166 } 177 */
167 input_event(input, EV_ABS, ABS_X, nd->x); 178 input_report_key(input, BTN_TOUCH,
168 input_event(input, EV_ABS, ABS_Y, nd->y); 179 nd->tipswitch);
169 } 180 input_report_key(input, BTN_TOOL_DOUBLETAP,
170 break; 181 nd->tipswitch);
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); 182 input_event(input, EV_ABS, ABS_X, nd->x);
187 input_event(input, EV_ABS, ABS_Y, nd->y); 183 input_event(input, EV_ABS, ABS_Y, nd->y);
188 input_event(input, EV_ABS, ABS_PRESSURE, value);
189 } 184 }
190 break; 185 break;
191 case 0xff000002: 186 case 0xff000002:
@@ -195,10 +190,40 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
195 * this usage tells if the contact point is real 190 * this usage tells if the contact point is real
196 * or a placeholder 191 * or a placeholder
197 */ 192 */
198 if (!nd->reading_a_point || value != 1) 193
194 /* Shouldn't get more than 4 footer packets, so skip */
195 if (nd->mt_foot_count >= 4)
199 break; 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
200 /* emit a normal (X, Y) for the first point only */ 218 /* emit a normal (X, Y) for the first point only */
201 if (nd->id == 0) { 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;
202 input_event(input, EV_ABS, ABS_X, nd->x); 227 input_event(input, EV_ABS, ABS_X, nd->x);
203 input_event(input, EV_ABS, ABS_Y, nd->y); 228 input_event(input, EV_ABS, ABS_Y, nd->y);
204 } 229 }
@@ -220,8 +245,21 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
220 ABS_MT_TOUCH_MINOR, nd->w); 245 ABS_MT_TOUCH_MINOR, nd->w);
221 } 246 }
222 input_mt_sync(field->hidinput->input); 247 input_mt_sync(field->hidinput->input);
223 nd->reading_a_point = 0; 248 break;
224 nd->found_contact_id = 0; 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 }
225 break; 263 break;
226 264
227 default: 265 default:
@@ -231,8 +269,8 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
231 } 269 }
232 270
233 /* we have handled the hidinput part, now remains hiddev */ 271 /* we have handled the hidinput part, now remains hiddev */
234 if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 272 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
235 hid->hiddev_hid_event(hid, field, usage, value); 273 hid->hiddev_hid_event(hid, field, usage, value);
236 274
237 return 1; 275 return 1;
238} 276}
@@ -241,23 +279,75 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
241{ 279{
242 int ret; 280 int ret;
243 struct ntrig_data *nd; 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;
244 288
245 nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL); 289 nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
246 if (!nd) { 290 if (!nd) {
247 dev_err(&hdev->dev, "cannot allocate N-Trig data\n"); 291 dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
248 return -ENOMEM; 292 return -ENOMEM;
249 } 293 }
250 nd->reading_a_point = 0; 294
251 nd->found_contact_id = 0; 295 nd->reading_mt = 0;
252 hid_set_drvdata(hdev, nd); 296 hid_set_drvdata(hdev, nd);
253 297
254 ret = hid_parse(hdev); 298 ret = hid_parse(hdev);
255 if (!ret) 299 if (ret) {
256 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 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 }
257 341
258 if (ret) 342 /* This is needed for devices with more recent firmware versions */
259 kfree (nd); 343 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a];
344 if (report)
345 usbhid_submit_report(hdev, report, USB_DIR_OUT);
260 346
347
348 return 0;
349err_free:
350 kfree(nd);
261 return ret; 351 return ret;
262} 352}
263 353
@@ -276,7 +366,7 @@ MODULE_DEVICE_TABLE(hid, ntrig_devices);
276 366
277static const struct hid_usage_id ntrig_grabbed_usages[] = { 367static const struct hid_usage_id ntrig_grabbed_usages[] = {
278 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 368 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
279 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 369 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
280}; 370};
281 371
282static struct hid_driver ntrig_driver = { 372static struct hid_driver ntrig_driver = {