diff options
author | Henrik Rydberg <rydberg@bitmath.org> | 2015-02-01 14:25:14 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-01 14:50:35 -0500 |
commit | 448c7f3830ca283e485aa943279acea6bde8b270 (patch) | |
tree | 9e5b1ce72aa87035bc73595d2ce925bacec6a155 | |
parent | 60bcaae15e0bd7f24d004ef2c9b3c8acb34b688d (diff) |
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>
-rw-r--r-- | drivers/input/input-mt.c | 31 | ||||
-rw-r--r-- | drivers/input/mouse/alps.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/bcm5974.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/cypress_ps2.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/pixcir_i2c_ts.c | 2 | ||||
-rw-r--r-- | include/linux/input/mt.h | 3 |
7 files changed, 27 insertions, 17 deletions
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index fbe29fcb15c5..cb150a1dbaff 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c | |||
@@ -293,7 +293,7 @@ void input_mt_sync_frame(struct input_dev *dev) | |||
293 | } | 293 | } |
294 | EXPORT_SYMBOL(input_mt_sync_frame); | 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 | int f, *p, s, c; | 298 | int f, *p, s, c; |
299 | 299 | ||
@@ -311,9 +311,10 @@ static int adjust_dual(int *begin, int step, int *end, int eq) | |||
311 | s = *p; | 311 | s = *p; |
312 | 312 | ||
313 | c = (f + s + 1) / 2; | 313 | c = (f + s + 1) / 2; |
314 | if (c == 0 || (c > 0 && !eq)) | 314 | if (c == 0 || (c > mu && (!eq || mu > 0))) |
315 | return 0; | 315 | return 0; |
316 | if (s < 0) | 316 | /* Improve convergence for positive matrices by penalizing overcovers */ |
317 | if (s < 0 && mu <= 0) | ||
317 | c *= 2; | 318 | c *= 2; |
318 | 319 | ||
319 | for (p = begin; p != end; p += step) | 320 | for (p = begin; p != end; p += step) |
@@ -322,23 +323,24 @@ static int adjust_dual(int *begin, int step, int *end, int eq) | |||
322 | return (c < s && s <= 0) || (f >= 0 && f < c); | 323 | return (c < s && s <= 0) || (f >= 0 && f < c); |
323 | } | 324 | } |
324 | 325 | ||
325 | static void find_reduced_matrix(int *w, int nr, int nc, int nrc) | 326 | static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu) |
326 | { | 327 | { |
327 | int i, k, sum; | 328 | int i, k, sum; |
328 | 329 | ||
329 | for (k = 0; k < nrc; k++) { | 330 | for (k = 0; k < nrc; k++) { |
330 | for (i = 0; i < nr; i++) | 331 | for (i = 0; i < nr; i++) |
331 | adjust_dual(w + i, nr, w + i + nrc, nr <= nc); | 332 | adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu); |
332 | sum = 0; | 333 | sum = 0; |
333 | for (i = 0; i < nrc; i += nr) | 334 | for (i = 0; i < nrc; i += nr) |
334 | sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr); | 335 | sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu); |
335 | if (!sum) | 336 | if (!sum) |
336 | break; | 337 | break; |
337 | } | 338 | } |
338 | } | 339 | } |
339 | 340 | ||
340 | static int input_mt_set_matrix(struct input_mt *mt, | 341 | static int input_mt_set_matrix(struct input_mt *mt, |
341 | const struct input_mt_pos *pos, int num_pos) | 342 | const struct input_mt_pos *pos, int num_pos, |
343 | int mu) | ||
342 | { | 344 | { |
343 | const struct input_mt_pos *p; | 345 | const struct input_mt_pos *p; |
344 | struct input_mt_slot *s; | 346 | struct input_mt_slot *s; |
@@ -352,7 +354,7 @@ static int input_mt_set_matrix(struct input_mt *mt, | |||
352 | y = input_mt_get_value(s, ABS_MT_POSITION_Y); | 354 | y = input_mt_get_value(s, ABS_MT_POSITION_Y); |
353 | for (p = pos; p != pos + num_pos; p++) { | 355 | for (p = pos; p != pos + num_pos; p++) { |
354 | int dx = x - p->x, dy = y - p->y; | 356 | int dx = x - p->x, dy = y - p->y; |
355 | *w++ = dx * dx + dy * dy; | 357 | *w++ = dx * dx + dy * dy - mu; |
356 | } | 358 | } |
357 | } | 359 | } |
358 | 360 | ||
@@ -393,17 +395,24 @@ static void input_mt_set_slots(struct input_mt *mt, | |||
393 | * @slots: the slot assignment to be filled | 395 | * @slots: the slot assignment to be filled |
394 | * @pos: the position array to match | 396 | * @pos: the position array to match |
395 | * @num_pos: number of positions | 397 | * @num_pos: number of positions |
398 | * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite) | ||
396 | * | 399 | * |
397 | * Performs a best match against the current contacts and returns | 400 | * Performs a best match against the current contacts and returns |
398 | * the slot assignment list. New contacts are assigned to unused | 401 | * the slot assignment list. New contacts are assigned to unused |
399 | * slots. | 402 | * slots. |
400 | * | 403 | * |
404 | * The assignments are balanced so that all coordinate displacements are | ||
405 | * below the euclidian distance dmax. If no such assignment can be found, | ||
406 | * some contacts are assigned to unused slots. | ||
407 | * | ||
401 | * Returns zero on success, or negative error in case of failure. | 408 | * Returns zero on success, or negative error in case of failure. |
402 | */ | 409 | */ |
403 | int input_mt_assign_slots(struct input_dev *dev, int *slots, | 410 | int input_mt_assign_slots(struct input_dev *dev, int *slots, |
404 | const struct input_mt_pos *pos, int num_pos) | 411 | const struct input_mt_pos *pos, int num_pos, |
412 | int dmax) | ||
405 | { | 413 | { |
406 | struct input_mt *mt = dev->mt; | 414 | struct input_mt *mt = dev->mt; |
415 | int mu = 2 * dmax * dmax; | ||
407 | int nrc; | 416 | int nrc; |
408 | 417 | ||
409 | if (!mt || !mt->red) | 418 | if (!mt || !mt->red) |
@@ -413,8 +422,8 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots, | |||
413 | if (num_pos < 1) | 422 | if (num_pos < 1) |
414 | return 0; | 423 | return 0; |
415 | 424 | ||
416 | nrc = input_mt_set_matrix(mt, pos, num_pos); | 425 | nrc = input_mt_set_matrix(mt, pos, num_pos, mu); |
417 | find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc); | 426 | find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu); |
418 | input_mt_set_slots(mt, slots, num_pos); | 427 | input_mt_set_slots(mt, slots, num_pos); |
419 | 428 | ||
420 | return 0; | 429 | return 0; |
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f719f28d370c..f205b8be2ce4 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -435,7 +435,7 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n) | |||
435 | struct alps_fields *f = &priv->f; | 435 | struct alps_fields *f = &priv->f; |
436 | int i, slot[MAX_TOUCHES]; | 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 | for (i = 0; i < n; i++) | 439 | for (i = 0; i < n; i++) |
440 | alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); | 440 | alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); |
441 | 441 | ||
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index c329cdb0b91a..b10709f04615 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c | |||
@@ -564,7 +564,7 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
564 | dev->index[n++] = &f[i]; | 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 | for (i = 0; i < n; i++) | 569 | for (i = 0; i < n; i++) |
570 | report_finger_data(input, dev->slots[i], | 570 | report_finger_data(input, dev->slots[i], |
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index 8af34ffe208b..9118a1861a45 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c | |||
@@ -538,7 +538,7 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt) | |||
538 | pos[i].y = contact->y; | 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 | for (i = 0; i < n; i++) { | 543 | for (i = 0; i < n; i++) { |
544 | contact = &report_data.contacts[i]; | 544 | contact = &report_data.contacts[i]; |
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f89de8971bf8..a3692e3b7cab 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -809,7 +809,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, | |||
809 | pos[i].y = synaptics_invert_y(hw[i]->y); | 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 | for (i = 0; i < nsemi; i++) { | 814 | for (i = 0; i < nsemi; i++) { |
815 | input_mt_slot(dev, slot[i]); | 815 | input_mt_slot(dev, slot[i]); |
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 4fb5537fdd42..2c2107147319 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c | |||
@@ -126,7 +126,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, | |||
126 | pos[i].y = touch->y; | 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 | for (i = 0; i < n; i++) { | 132 | for (i = 0; i < n; i++) { |
diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h index f583ff639776..d7188de4db96 100644 --- a/include/linux/input/mt.h +++ b/include/linux/input/mt.h | |||
@@ -119,7 +119,8 @@ struct input_mt_pos { | |||
119 | }; | 119 | }; |
120 | 120 | ||
121 | int input_mt_assign_slots(struct input_dev *dev, int *slots, | 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 | int input_mt_get_slot_by_key(struct input_dev *dev, int key); | 125 | int input_mt_get_slot_by_key(struct input_dev *dev, int key); |
125 | 126 | ||