mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
Input: bcm5974 - improve finger tracking and counting
The problem of finger tracking, i.e., when to switch focus from one finger to another on the trackpad, has been improved by utilizing more information from the bcm5974 chip output. This results in less pointer hopping when many fingers are on the trackpad. In addition, a finger counting method based on pressure information from all fingers is introduced. Together with a pressure hysteresis window, this yields a more stable counting of the number of fingers on the trackpad. Signed-off-by: Henrik Rydberg <rydberg@euromail.se> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
parent
158e0fb602
commit
75e21e3f3b
1 changed files with 54 additions and 16 deletions
|
@ -105,7 +105,7 @@ struct tp_header {
|
|||
|
||||
/* trackpad finger structure */
|
||||
struct tp_finger {
|
||||
__le16 origin; /* left/right origin? */
|
||||
__le16 origin; /* zero when switching track finger */
|
||||
__le16 abs_x; /* absolute x coodinate */
|
||||
__le16 abs_y; /* absolute y coodinate */
|
||||
__le16 rel_x; /* relative x coodinate */
|
||||
|
@ -159,6 +159,7 @@ struct bcm5974 {
|
|||
struct bt_data *bt_data; /* button transferred data */
|
||||
struct urb *tp_urb; /* trackpad usb request block */
|
||||
struct tp_data *tp_data; /* trackpad transferred data */
|
||||
int fingers; /* number of fingers on trackpad */
|
||||
};
|
||||
|
||||
/* logical dimensions */
|
||||
|
@ -172,6 +173,10 @@ struct bcm5974 {
|
|||
#define SN_WIDTH 100 /* width signal-to-noise ratio */
|
||||
#define SN_COORD 250 /* coordinate signal-to-noise ratio */
|
||||
|
||||
/* pressure thresholds */
|
||||
#define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE)
|
||||
#define PRESSURE_HIGH (3 * PRESSURE_LOW)
|
||||
|
||||
/* device constants */
|
||||
static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
{
|
||||
|
@ -273,32 +278,65 @@ static int report_tp_state(struct bcm5974 *dev, int size)
|
|||
const struct tp_finger *f = dev->tp_data->finger;
|
||||
struct input_dev *input = dev->input;
|
||||
const int fingers = (size - 26) / 28;
|
||||
int p = 0, w, x, y, n = 0;
|
||||
int raw_p, raw_w, raw_x, raw_y;
|
||||
int ptest = 0, origin = 0, nmin = 0, nmax = 0;
|
||||
int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
|
||||
|
||||
if (size < 26 || (size - 26) % 28 != 0)
|
||||
return -EIO;
|
||||
|
||||
/* always track the first finger; when detached, start over */
|
||||
if (fingers) {
|
||||
p = raw2int(f->force_major);
|
||||
w = raw2int(f->size_major);
|
||||
x = raw2int(f->abs_x);
|
||||
y = raw2int(f->abs_y);
|
||||
n = p > 0 ? fingers : 0;
|
||||
raw_p = raw2int(f->force_major);
|
||||
raw_w = raw2int(f->size_major);
|
||||
raw_x = raw2int(f->abs_x);
|
||||
raw_y = raw2int(f->abs_y);
|
||||
|
||||
dprintk(9,
|
||||
"bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
|
||||
p, w, x, y, n);
|
||||
"bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n",
|
||||
raw_p, raw_w, raw_x, raw_y);
|
||||
|
||||
input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
|
||||
input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin));
|
||||
input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
|
||||
ptest = int2bound(&c->p, raw_p);
|
||||
origin = raw2int(f->origin);
|
||||
}
|
||||
|
||||
input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
|
||||
/* while tracking finger still valid, count all fingers */
|
||||
if (ptest > PRESSURE_LOW && origin) {
|
||||
abs_p = ptest;
|
||||
abs_w = int2bound(&c->w, raw_w);
|
||||
abs_x = int2bound(&c->x, raw_x - c->x.devmin);
|
||||
abs_y = int2bound(&c->y, c->y.devmax - raw_y);
|
||||
for (; f != dev->tp_data->finger + fingers; f++) {
|
||||
ptest = int2bound(&c->p, raw2int(f->force_major));
|
||||
if (ptest > PRESSURE_LOW)
|
||||
nmax++;
|
||||
if (ptest > PRESSURE_HIGH)
|
||||
nmin++;
|
||||
}
|
||||
}
|
||||
|
||||
input_report_key(input, BTN_TOOL_FINGER, n == 1);
|
||||
input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
|
||||
input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
|
||||
if (dev->fingers < nmin)
|
||||
dev->fingers = nmin;
|
||||
if (dev->fingers > nmax)
|
||||
dev->fingers = nmax;
|
||||
|
||||
input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
|
||||
input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
|
||||
input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2);
|
||||
|
||||
input_report_abs(input, ABS_PRESSURE, abs_p);
|
||||
input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
|
||||
|
||||
if (abs_p) {
|
||||
input_report_abs(input, ABS_X, abs_x);
|
||||
input_report_abs(input, ABS_Y, abs_y);
|
||||
|
||||
dprintk(8,
|
||||
"bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
|
||||
"nmin: %d nmax: %d n: %d\n",
|
||||
abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers);
|
||||
|
||||
}
|
||||
|
||||
input_sync(input);
|
||||
|
||||
|
|
Loading…
Reference in a new issue