提交 448c7f38 编写于 作者: H Henrik Rydberg 提交者: Dmitry Torokhov

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: NBenjamin Tissoires <benjamin.tissoires@redhat.com>
Tested-by: NBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: NHenrik Rydberg <rydberg@bitmath.org>
Signed-off-by: NDmitry Torokhov <dmitry.torokhov@gmail.com>
上级 60bcaae1
...@@ -293,7 +293,7 @@ void input_mt_sync_frame(struct input_dev *dev) ...@@ -293,7 +293,7 @@ void input_mt_sync_frame(struct input_dev *dev)
} }
EXPORT_SYMBOL(input_mt_sync_frame); EXPORT_SYMBOL(input_mt_sync_frame);
static int adjust_dual(int *begin, int step, int *end, int eq) static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
{ {
int f, *p, s, c; int f, *p, s, c;
...@@ -311,9 +311,10 @@ static int adjust_dual(int *begin, int step, int *end, int eq) ...@@ -311,9 +311,10 @@ static int adjust_dual(int *begin, int step, int *end, int eq)
s = *p; s = *p;
c = (f + s + 1) / 2; c = (f + s + 1) / 2;
if (c == 0 || (c > 0 && !eq)) if (c == 0 || (c > mu && (!eq || mu > 0)))
return 0; return 0;
if (s < 0) /* Improve convergence for positive matrices by penalizing overcovers */
if (s < 0 && mu <= 0)
c *= 2; c *= 2;
for (p = begin; p != end; p += step) for (p = begin; p != end; p += step)
...@@ -322,23 +323,24 @@ static int adjust_dual(int *begin, int step, int *end, int eq) ...@@ -322,23 +323,24 @@ static int adjust_dual(int *begin, int step, int *end, int eq)
return (c < s && s <= 0) || (f >= 0 && f < c); return (c < s && s <= 0) || (f >= 0 && f < c);
} }
static void find_reduced_matrix(int *w, int nr, int nc, int nrc) static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
{ {
int i, k, sum; int i, k, sum;
for (k = 0; k < nrc; k++) { for (k = 0; k < nrc; k++) {
for (i = 0; i < nr; i++) for (i = 0; i < nr; i++)
adjust_dual(w + i, nr, w + i + nrc, nr <= nc); adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
sum = 0; sum = 0;
for (i = 0; i < nrc; i += nr) for (i = 0; i < nrc; i += nr)
sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr); sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
if (!sum) if (!sum)
break; break;
} }
} }
static int input_mt_set_matrix(struct input_mt *mt, static int input_mt_set_matrix(struct input_mt *mt,
const struct input_mt_pos *pos, int num_pos) const struct input_mt_pos *pos, int num_pos,
int mu)
{ {
const struct input_mt_pos *p; const struct input_mt_pos *p;
struct input_mt_slot *s; struct input_mt_slot *s;
...@@ -352,7 +354,7 @@ static int input_mt_set_matrix(struct input_mt *mt, ...@@ -352,7 +354,7 @@ static int input_mt_set_matrix(struct input_mt *mt,
y = input_mt_get_value(s, ABS_MT_POSITION_Y); y = input_mt_get_value(s, ABS_MT_POSITION_Y);
for (p = pos; p != pos + num_pos; p++) { for (p = pos; p != pos + num_pos; p++) {
int dx = x - p->x, dy = y - p->y; int dx = x - p->x, dy = y - p->y;
*w++ = dx * dx + dy * dy; *w++ = dx * dx + dy * dy - mu;
} }
} }
...@@ -393,17 +395,24 @@ static void input_mt_set_slots(struct input_mt *mt, ...@@ -393,17 +395,24 @@ static void input_mt_set_slots(struct input_mt *mt,
* @slots: the slot assignment to be filled * @slots: the slot assignment to be filled
* @pos: the position array to match * @pos: the position array to match
* @num_pos: number of positions * @num_pos: number of positions
* @dmax: maximum ABS_MT_POSITION displacement (zero for infinite)
* *
* Performs a best match against the current contacts and returns * Performs a best match against the current contacts and returns
* the slot assignment list. New contacts are assigned to unused * the slot assignment list. New contacts are assigned to unused
* slots. * slots.
* *
* The assignments are balanced so that all coordinate displacements are
* below the euclidian distance dmax. If no such assignment can be found,
* some contacts are assigned to unused slots.
*
* Returns zero on success, or negative error in case of failure. * Returns zero on success, or negative error in case of failure.
*/ */
int input_mt_assign_slots(struct input_dev *dev, int *slots, int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos) const struct input_mt_pos *pos, int num_pos,
int dmax)
{ {
struct input_mt *mt = dev->mt; struct input_mt *mt = dev->mt;
int mu = 2 * dmax * dmax;
int nrc; int nrc;
if (!mt || !mt->red) if (!mt || !mt->red)
...@@ -413,8 +422,8 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots, ...@@ -413,8 +422,8 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots,
if (num_pos < 1) if (num_pos < 1)
return 0; return 0;
nrc = input_mt_set_matrix(mt, pos, num_pos); nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc); find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
input_mt_set_slots(mt, slots, num_pos); input_mt_set_slots(mt, slots, num_pos);
return 0; return 0;
......
...@@ -435,7 +435,7 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n) ...@@ -435,7 +435,7 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n)
struct alps_fields *f = &priv->f; struct alps_fields *f = &priv->f;
int i, slot[MAX_TOUCHES]; int i, slot[MAX_TOUCHES];
input_mt_assign_slots(dev, slot, f->mt, n); input_mt_assign_slots(dev, slot, f->mt, n, 0);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
......
...@@ -564,7 +564,7 @@ static int report_tp_state(struct bcm5974 *dev, int size) ...@@ -564,7 +564,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
dev->index[n++] = &f[i]; dev->index[n++] = &f[i];
} }
input_mt_assign_slots(input, dev->slots, dev->pos, n); input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
report_finger_data(input, dev->slots[i], report_finger_data(input, dev->slots[i],
......
...@@ -538,7 +538,7 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt) ...@@ -538,7 +538,7 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
pos[i].y = contact->y; pos[i].y = contact->y;
} }
input_mt_assign_slots(input, slots, pos, n); input_mt_assign_slots(input, slots, pos, n, 0);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
contact = &report_data.contacts[i]; contact = &report_data.contacts[i];
......
...@@ -809,7 +809,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, ...@@ -809,7 +809,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
pos[i].y = synaptics_invert_y(hw[i]->y); pos[i].y = synaptics_invert_y(hw[i]->y);
} }
input_mt_assign_slots(dev, slot, pos, nsemi); input_mt_assign_slots(dev, slot, pos, nsemi, 0);
for (i = 0; i < nsemi; i++) { for (i = 0; i < nsemi; i++) {
input_mt_slot(dev, slot[i]); input_mt_slot(dev, slot[i]);
......
...@@ -126,7 +126,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, ...@@ -126,7 +126,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
pos[i].y = touch->y; pos[i].y = touch->y;
} }
input_mt_assign_slots(ts->input, slots, pos, n); input_mt_assign_slots(ts->input, slots, pos, n, 0);
} }
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
......
...@@ -119,7 +119,8 @@ struct input_mt_pos { ...@@ -119,7 +119,8 @@ struct input_mt_pos {
}; };
int input_mt_assign_slots(struct input_dev *dev, int *slots, int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos); const struct input_mt_pos *pos, int num_pos,
int dmax);
int input_mt_get_slot_by_key(struct input_dev *dev, int key); int input_mt_get_slot_by_key(struct input_dev *dev, int key);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册