aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@bitmath.org>2015-02-01 14:25:14 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-01 14:50:35 -0500
commit448c7f3830ca283e485aa943279acea6bde8b270 (patch)
tree9e5b1ce72aa87035bc73595d2ce925bacec6a155
parent60bcaae15e0bd7f24d004ef2c9b3c8acb34b688d (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.c31
-rw-r--r--drivers/input/mouse/alps.c2
-rw-r--r--drivers/input/mouse/bcm5974.c2
-rw-r--r--drivers/input/mouse/cypress_ps2.c2
-rw-r--r--drivers/input/mouse/synaptics.c2
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c2
-rw-r--r--include/linux/input/mt.h3
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}
294EXPORT_SYMBOL(input_mt_sync_frame); 294EXPORT_SYMBOL(input_mt_sync_frame);
295 295
296static int adjust_dual(int *begin, int step, int *end, int eq) 296static 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
325static void find_reduced_matrix(int *w, int nr, int nc, int nrc) 326static 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
340static int input_mt_set_matrix(struct input_mt *mt, 341static 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 */
403int input_mt_assign_slots(struct input_dev *dev, int *slots, 410int 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
121int input_mt_assign_slots(struct input_dev *dev, int *slots, 121int 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
124int input_mt_get_slot_by_key(struct input_dev *dev, int key); 125int input_mt_get_slot_by_key(struct input_dev *dev, int key);
125 126