diff options
Diffstat (limited to 'drivers/hid/hid-ntrig.c')
-rw-r--r-- | drivers/hid/hid-ntrig.c | 220 |
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 | ||
27 | static unsigned int min_width; | ||
28 | static unsigned int min_height; | ||
29 | static unsigned int activate_slack = 1; | ||
30 | static unsigned int deactivate_slack = 4; | ||
31 | static unsigned int activation_width = 64; | ||
32 | static unsigned int activation_height = 32; | ||
33 | |||
27 | struct ntrig_data { | 34 | struct 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); |