aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-ntrig.c
diff options
context:
space:
mode:
authorRafi Rubin <rafi@seas.upenn.edu>2010-05-04 14:20:15 -0400
committerJiri Kosina <jkosina@suse.cz>2010-05-11 04:45:22 -0400
commit369db2a6008e8fc3cf5006fa8aab71bd58adfc1f (patch)
treed2ce4d9b692e7b313fc6f2a35bf62011141c98da /drivers/hid/hid-ntrig.c
parent94b849aaf6e22ab7bf54b0d0377a882d4892396d (diff)
HID: ntrig: add sensitivity and responsiveness support
The old rejection size thresholds were too high for the 12" devices. Larger surfaces like the Dell Studio17 exacerbated the problem since contact size is reported on the same logical scale, making a contact look smaller to the larger screen. Since we have observed erroneous ghost events from these devices we still need to filter the incoming stream. The prior size threshold filter is still in place, though with defaults set to leave it off. This patch adds the two new classes of filters, those that reject live frames before activation, and those that reject empty frames until deactivation. These filters are expressed in terms of a simple state machine for clarity (I hope). The activation filter has two components, slack and size, events are discarded until either is satisfied. Slack is defined as the number of seemingly good contacts to read before accepting the stream as valid (if the threshold is reached in the middle of a frame the remainder of that frame is still discarded). The deactivation filter discards empty frames until hitting a deactivate slack. This time measured in frames. N-Trig devices emit 5-8 (observed so far) empty frames at the end of multitouch activity. Ignoring the first few enables us to safely and gracefully handle erroneous empty frames, thus preventing a change in the tool state which would otherwise result in things like broken lines or dragged objects being dropped in bad places. Also, now that devices with different logical densities have been observed, the aforementioned sizes are scaled from physical to logical scales once those scales are identified. Hopefully this should mean that a given threshold value means the same thing across differing devices. Signed-off-by: Rafi Rubin <rafi@seas.upenn.edu> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-ntrig.c')
-rw-r--r--drivers/hid/hid-ntrig.c220
1 files changed, 211 insertions, 9 deletions
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 4777bbfa1cc2..227d01527c6a 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -24,6 +24,13 @@
24 24
25#define NTRIG_DUPLICATE_USAGES 0x001 25#define NTRIG_DUPLICATE_USAGES 0x001
26 26
27static unsigned int min_width;
28static unsigned int min_height;
29static unsigned int activate_slack = 1;
30static unsigned int deactivate_slack = 4;
31static unsigned int activation_width = 64;
32static unsigned int activation_height = 32;
33
27struct ntrig_data { 34struct ntrig_data {
28 /* Incoming raw values for a single contact */ 35 /* Incoming raw values for a single contact */
29 __u16 x, y, w, h; 36 __u16 x, y, w, h;
@@ -37,6 +44,28 @@ struct ntrig_data {
37 44
38 __u8 mt_footer[4]; 45 __u8 mt_footer[4];
39 __u8 mt_foot_count; 46 __u8 mt_foot_count;
47
48 /* The current activation state. */
49 __s8 act_state;
50
51 /* Empty frames to ignore before recognizing the end of activity */
52 __s8 deactivate_slack;
53
54 /* Frames to ignore before acknowledging the start of activity */
55 __s8 activate_slack;
56
57 /* Minimum size contact to accept */
58 __u16 min_width;
59 __u16 min_height;
60
61 /* Threshold to override activation slack */
62 __u16 activation_width;
63 __u16 activation_height;
64
65 __u16 sensor_logical_width;
66 __u16 sensor_logical_height;
67 __u16 sensor_physical_width;
68 __u16 sensor_physical_height;
40}; 69};
41 70
42/* 71/*
@@ -49,6 +78,8 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
49 struct hid_field *field, struct hid_usage *usage, 78 struct hid_field *field, struct hid_usage *usage,
50 unsigned long **bit, int *max) 79 unsigned long **bit, int *max)
51{ 80{
81 struct ntrig_data *nd = hid_get_drvdata(hdev);
82
52 /* No special mappings needed for the pen and single touch */ 83 /* No special mappings needed for the pen and single touch */
53 if (field->physical) 84 if (field->physical)
54 return 0; 85 return 0;
@@ -62,6 +93,21 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
62 input_set_abs_params(hi->input, ABS_X, 93 input_set_abs_params(hi->input, ABS_X,
63 field->logical_minimum, 94 field->logical_minimum,
64 field->logical_maximum, 0, 0); 95 field->logical_maximum, 0, 0);
96
97 if (!nd->sensor_logical_width) {
98 nd->sensor_logical_width =
99 field->logical_maximum -
100 field->logical_minimum;
101 nd->sensor_physical_width =
102 field->physical_maximum -
103 field->physical_minimum;
104 nd->activation_width = activation_width *
105 nd->sensor_logical_width /
106 nd->sensor_physical_width;
107 nd->min_width = min_width *
108 nd->sensor_logical_width /
109 nd->sensor_physical_width;
110 }
65 return 1; 111 return 1;
66 case HID_GD_Y: 112 case HID_GD_Y:
67 hid_map_usage(hi, usage, bit, max, 113 hid_map_usage(hi, usage, bit, max,
@@ -69,6 +115,21 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
69 input_set_abs_params(hi->input, ABS_Y, 115 input_set_abs_params(hi->input, ABS_Y,
70 field->logical_minimum, 116 field->logical_minimum,
71 field->logical_maximum, 0, 0); 117 field->logical_maximum, 0, 0);
118
119 if (!nd->sensor_logical_height) {
120 nd->sensor_logical_height =
121 field->logical_maximum -
122 field->logical_minimum;
123 nd->sensor_physical_height =
124 field->physical_maximum -
125 field->physical_minimum;
126 nd->activation_height = activation_height *
127 nd->sensor_logical_height /
128 nd->sensor_physical_height;
129 nd->min_height = min_height *
130 nd->sensor_logical_height /
131 nd->sensor_physical_height;
132 }
72 return 1; 133 return 1;
73 } 134 }
74 return 0; 135 return 0;
@@ -201,20 +262,68 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
201 if (nd->mt_foot_count != 4) 262 if (nd->mt_foot_count != 4)
202 break; 263 break;
203 264
204 /* Pen activity signal, trigger end of touch. */ 265 /* Pen activity signal. */
205 if (nd->mt_footer[2]) { 266 if (nd->mt_footer[2]) {
267 /*
268 * When the pen deactivates touch, we see a
269 * bogus frame with ContactCount > 0.
270 * We can
271 * save a bit of work by ensuring act_state < 0
272 * even if deactivation slack is turned off.
273 */
274 nd->act_state = deactivate_slack - 1;
206 nd->confidence = 0; 275 nd->confidence = 0;
207 break; 276 break;
208 } 277 }
209 278
210 /* If the contact was invalid */ 279 /*
211 if (!(nd->confidence && nd->mt_footer[0]) 280 * The first footer value indicates the presence of a
212 || nd->w <= 250 281 * finger.
213 || nd->h <= 190) { 282 */
214 nd->confidence = 0; 283 if (nd->mt_footer[0]) {
284 /*
285 * We do not want to process contacts under
286 * the size threshold, but do not want to
287 * ignore them for activation state
288 */
289 if (nd->w < nd->min_width ||
290 nd->h < nd->min_height)
291 nd->confidence = 0;
292 } else
215 break; 293 break;
294
295 if (nd->act_state > 0) {
296 /*
297 * Contact meets the activation size threshold
298 */
299 if (nd->w >= nd->activation_width &&
300 nd->h >= nd->activation_height) {
301 if (nd->id)
302 /*
303 * first contact, activate now
304 */
305 nd->act_state = 0;
306 else {
307 /*
308 * avoid corrupting this frame
309 * but ensure next frame will
310 * be active
311 */
312 nd->act_state = 1;
313 break;
314 }
315 } else
316 /*
317 * Defer adjusting the activation state
318 * until the end of the frame.
319 */
320 break;
216 } 321 }
217 322
323 /* Discarding this contact */
324 if (!nd->confidence)
325 break;
326
218 /* emit a normal (X, Y) for the first point only */ 327 /* emit a normal (X, Y) for the first point only */
219 if (nd->id == 0) { 328 if (nd->id == 0) {
220 /* 329 /*
@@ -227,8 +336,15 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
227 input_event(input, EV_ABS, ABS_X, nd->x); 336 input_event(input, EV_ABS, ABS_X, nd->x);
228 input_event(input, EV_ABS, ABS_Y, nd->y); 337 input_event(input, EV_ABS, ABS_Y, nd->y);
229 } 338 }
339
340 /* Emit MT events */
230 input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); 341 input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
231 input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); 342 input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
343
344 /*
345 * Translate from height and width to size
346 * and orientation.
347 */
232 if (nd->w > nd->h) { 348 if (nd->w > nd->h) {
233 input_event(input, EV_ABS, 349 input_event(input, EV_ABS,
234 ABS_MT_ORIENTATION, 1); 350 ABS_MT_ORIENTATION, 1);
@@ -248,12 +364,88 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
248 break; 364 break;
249 365
250 case HID_DG_CONTACTCOUNT: /* End of a multitouch group */ 366 case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
251 if (!nd->reading_mt) 367 if (!nd->reading_mt) /* Just to be sure */
252 break; 368 break;
253 369
254 nd->reading_mt = 0; 370 nd->reading_mt = 0;
255 371
256 if (nd->first_contact_touch) { 372
373 /*
374 * Activation state machine logic:
375 *
376 * Fundamental states:
377 * state > 0: Inactive
378 * state <= 0: Active
379 * state < -deactivate_slack:
380 * Pen termination of touch
381 *
382 * Specific values of interest
383 * state == activate_slack
384 * no valid input since the last reset
385 *
386 * state == 0
387 * general operational state
388 *
389 * state == -deactivate_slack
390 * read sufficient empty frames to accept
391 * the end of input and reset
392 */
393
394 if (nd->act_state > 0) { /* Currently inactive */
395 if (value)
396 /*
397 * Consider each live contact as
398 * evidence of intentional activity.
399 */
400 nd->act_state = (nd->act_state > value)
401 ? nd->act_state - value
402 : 0;
403 else
404 /*
405 * Empty frame before we hit the
406 * activity threshold, reset.
407 */
408 nd->act_state = nd->activate_slack;
409
410 /*
411 * Entered this block inactive and no
412 * coordinates sent this frame, so hold off
413 * on button state.
414 */
415 break;
416 } else { /* Currently active */
417 if (value && nd->act_state >=
418 nd->deactivate_slack)
419 /*
420 * Live point: clear accumulated
421 * deactivation count.
422 */
423 nd->act_state = 0;
424 else if (nd->act_state <= nd->deactivate_slack)
425 /*
426 * We've consumed the deactivation
427 * slack, time to deactivate and reset.
428 */
429 nd->act_state =
430 nd->activate_slack;
431 else { /* Move towards deactivation */
432 nd->act_state--;
433 break;
434 }
435 }
436
437 if (nd->first_contact_touch && nd->act_state <= 0) {
438 /*
439 * Check to see if we're ready to start
440 * emitting touch events.
441 *
442 * Note: activation slack will decrease over
443 * the course of the frame, and it will be
444 * inconsistent from the start to the end of
445 * the frame. However if the frame starts
446 * with slack, first_contact_touch will still
447 * be 0 and we will not get to this point.
448 */
257 input_report_key(input, BTN_TOOL_DOUBLETAP, 1); 449 input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
258 input_report_key(input, BTN_TOUCH, 1); 450 input_report_key(input, BTN_TOUCH, 1);
259 } else { 451 } else {
@@ -263,7 +455,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
263 break; 455 break;
264 456
265 default: 457 default:
266 /* fallback to the generic hidinput handling */ 458 /* fall-back to the generic hidinput handling */
267 return 0; 459 return 0;
268 } 460 }
269 } 461 }
@@ -293,6 +485,16 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
293 } 485 }
294 486
295 nd->reading_mt = 0; 487 nd->reading_mt = 0;
488 nd->min_width = 0;
489 nd->min_height = 0;
490 nd->activate_slack = activate_slack;
491 nd->act_state = activate_slack;
492 nd->deactivate_slack = -deactivate_slack;
493 nd->sensor_logical_width = 0;
494 nd->sensor_logical_height = 0;
495 nd->sensor_physical_width = 0;
496 nd->sensor_physical_height = 0;
497
296 hid_set_drvdata(hdev, nd); 498 hid_set_drvdata(hdev, nd);
297 499
298 ret = hid_parse(hdev); 500 ret = hid_parse(hdev);