Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: MT - add support for balanced slot assignment

Some devices are not fast enough to differentiate between a fast-moving
contact and a new contact. This problem cannot be fully resolved because
information is truly missing, but it is possible to safe-guard against
obvious mistakes by restricting movement with a maximum displacement.

The new problem formulation for dmax > 0 cannot benefit from the speedup
for positive definite matrices, but since the convergence is faster, the
result is about the same. For a handful of contacts, the latency difference
is truly negligible.

Suggested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Henrik Rydberg <rydberg@bitmath.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Henrik Rydberg and committed by
Dmitry Torokhov
448c7f38 60bcaae1

+27 -17
+20 -11
drivers/input/input-mt.c
··· 293 293 } 294 294 EXPORT_SYMBOL(input_mt_sync_frame); 295 295 296 - static int adjust_dual(int *begin, int step, int *end, int eq) 296 + static int adjust_dual(int *begin, int step, int *end, int eq, int mu) 297 297 { 298 298 int f, *p, s, c; 299 299 ··· 311 311 s = *p; 312 312 313 313 c = (f + s + 1) / 2; 314 - if (c == 0 || (c > 0 && !eq)) 314 + if (c == 0 || (c > mu && (!eq || mu > 0))) 315 315 return 0; 316 - if (s < 0) 316 + /* Improve convergence for positive matrices by penalizing overcovers */ 317 + if (s < 0 && mu <= 0) 317 318 c *= 2; 318 319 319 320 for (p = begin; p != end; p += step) ··· 323 322 return (c < s && s <= 0) || (f >= 0 && f < c); 324 323 } 325 324 326 - static void find_reduced_matrix(int *w, int nr, int nc, int nrc) 325 + static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu) 327 326 { 328 327 int i, k, sum; 329 328 330 329 for (k = 0; k < nrc; k++) { 331 330 for (i = 0; i < nr; i++) 332 - adjust_dual(w + i, nr, w + i + nrc, nr <= nc); 331 + adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu); 333 332 sum = 0; 334 333 for (i = 0; i < nrc; i += nr) 335 - sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr); 334 + sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu); 336 335 if (!sum) 337 336 break; 338 337 } 339 338 } 340 339 341 340 static int input_mt_set_matrix(struct input_mt *mt, 342 - const struct input_mt_pos *pos, int num_pos) 341 + const struct input_mt_pos *pos, int num_pos, 342 + int mu) 343 343 { 344 344 const struct input_mt_pos *p; 345 345 struct input_mt_slot *s; ··· 354 352 y = input_mt_get_value(s, ABS_MT_POSITION_Y); 355 353 for (p = pos; p != pos + num_pos; p++) { 356 354 int dx = x - p->x, dy = y - p->y; 357 - *w++ = dx * dx + dy * dy; 355 + *w++ = dx * dx + dy * dy - mu; 358 356 } 359 357 } 360 358 ··· 395 393 * @slots: the slot assignment to be filled 396 394 * @pos: the position array to match 397 395 * @num_pos: number of positions 396 + * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite) 398 397 * 399 398 * Performs a best match against the current contacts and returns 400 399 * the slot assignment list. New contacts are assigned to unused 401 400 * slots. 402 401 * 402 + * The assignments are balanced so that all coordinate displacements are 403 + * below the euclidian distance dmax. If no such assignment can be found, 404 + * some contacts are assigned to unused slots. 405 + * 403 406 * Returns zero on success, or negative error in case of failure. 404 407 */ 405 408 int input_mt_assign_slots(struct input_dev *dev, int *slots, 406 - const struct input_mt_pos *pos, int num_pos) 409 + const struct input_mt_pos *pos, int num_pos, 410 + int dmax) 407 411 { 408 412 struct input_mt *mt = dev->mt; 413 + int mu = 2 * dmax * dmax; 409 414 int nrc; 410 415 411 416 if (!mt || !mt->red) ··· 422 413 if (num_pos < 1) 423 414 return 0; 424 415 425 - nrc = input_mt_set_matrix(mt, pos, num_pos); 426 - find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc); 416 + nrc = input_mt_set_matrix(mt, pos, num_pos, mu); 417 + find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu); 427 418 input_mt_set_slots(mt, slots, num_pos); 428 419 429 420 return 0;
+1 -1
drivers/input/mouse/alps.c
··· 435 435 struct alps_fields *f = &priv->f; 436 436 int i, slot[MAX_TOUCHES]; 437 437 438 - input_mt_assign_slots(dev, slot, f->mt, n); 438 + input_mt_assign_slots(dev, slot, f->mt, n, 0); 439 439 for (i = 0; i < n; i++) 440 440 alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); 441 441
+1 -1
drivers/input/mouse/bcm5974.c
··· 564 564 dev->index[n++] = &f[i]; 565 565 } 566 566 567 - input_mt_assign_slots(input, dev->slots, dev->pos, n); 567 + input_mt_assign_slots(input, dev->slots, dev->pos, n, 0); 568 568 569 569 for (i = 0; i < n; i++) 570 570 report_finger_data(input, dev->slots[i],
+1 -1
drivers/input/mouse/cypress_ps2.c
··· 538 538 pos[i].y = contact->y; 539 539 } 540 540 541 - input_mt_assign_slots(input, slots, pos, n); 541 + input_mt_assign_slots(input, slots, pos, n, 0); 542 542 543 543 for (i = 0; i < n; i++) { 544 544 contact = &report_data.contacts[i];
+1 -1
drivers/input/mouse/synaptics.c
··· 809 809 pos[i].y = synaptics_invert_y(hw[i]->y); 810 810 } 811 811 812 - input_mt_assign_slots(dev, slot, pos, nsemi); 812 + input_mt_assign_slots(dev, slot, pos, nsemi, 0); 813 813 814 814 for (i = 0; i < nsemi; i++) { 815 815 input_mt_slot(dev, slot[i]);
+1 -1
drivers/input/touchscreen/pixcir_i2c_ts.c
··· 126 126 pos[i].y = touch->y; 127 127 } 128 128 129 - input_mt_assign_slots(ts->input, slots, pos, n); 129 + input_mt_assign_slots(ts->input, slots, pos, n, 0); 130 130 } 131 131 132 132 for (i = 0; i < n; i++) {
+2 -1
include/linux/input/mt.h
··· 119 119 }; 120 120 121 121 int input_mt_assign_slots(struct input_dev *dev, int *slots, 122 - const struct input_mt_pos *pos, int num_pos); 122 + const struct input_mt_pos *pos, int num_pos, 123 + int dmax); 123 124 124 125 int input_mt_get_slot_by_key(struct input_dev *dev, int key); 125 126