aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2008-09-04 22:28:23 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2008-09-04 22:57:15 -0400
commit75e21e3f3bb2b4a41bb0646a4d54eef27eb36ca5 (patch)
tree826c8c0b656ebcd65ee56f6359ea7b49b554349b /drivers
parent158e0fb6028a2329425d8287b1b2402a12ed4f28 (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/mouse/bcm5974.c70
1 files changed, 54 insertions, 16 deletions
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index ae78bb833f62..8568211c5564 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -105,7 +105,7 @@ struct tp_header {
105 105
106/* trackpad finger structure */ 106/* trackpad finger structure */
107struct tp_finger { 107struct tp_finger {
108 __le16 origin; /* left/right origin? */ 108 __le16 origin; /* zero when switching track finger */
109 __le16 abs_x; /* absolute x coodinate */ 109 __le16 abs_x; /* absolute x coodinate */
110 __le16 abs_y; /* absolute y coodinate */ 110 __le16 abs_y; /* absolute y coodinate */
111 __le16 rel_x; /* relative x coodinate */ 111 __le16 rel_x; /* relative x coodinate */
@@ -159,6 +159,7 @@ struct bcm5974 {
159 struct bt_data *bt_data; /* button transferred data */ 159 struct bt_data *bt_data; /* button transferred data */
160 struct urb *tp_urb; /* trackpad usb request block */ 160 struct urb *tp_urb; /* trackpad usb request block */
161 struct tp_data *tp_data; /* trackpad transferred data */ 161 struct tp_data *tp_data; /* trackpad transferred data */
162 int fingers; /* number of fingers on trackpad */
162}; 163};
163 164
164/* logical dimensions */ 165/* logical dimensions */
@@ -172,6 +173,10 @@ struct bcm5974 {
172#define SN_WIDTH 100 /* width signal-to-noise ratio */ 173#define SN_WIDTH 100 /* width signal-to-noise ratio */
173#define SN_COORD 250 /* coordinate signal-to-noise ratio */ 174#define SN_COORD 250 /* coordinate signal-to-noise ratio */
174 175
176/* pressure thresholds */
177#define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE)
178#define PRESSURE_HIGH (3 * PRESSURE_LOW)
179
175/* device constants */ 180/* device constants */
176static const struct bcm5974_config bcm5974_config_table[] = { 181static const struct bcm5974_config bcm5974_config_table[] = {
177 { 182 {
@@ -273,32 +278,65 @@ static int report_tp_state(struct bcm5974 *dev, int size)
273 const struct tp_finger *f = dev->tp_data->finger; 278 const struct tp_finger *f = dev->tp_data->finger;
274 struct input_dev *input = dev->input; 279 struct input_dev *input = dev->input;
275 const int fingers = (size - 26) / 28; 280 const int fingers = (size - 26) / 28;
276 int p = 0, w, x, y, n = 0; 281 int raw_p, raw_w, raw_x, raw_y;
282 int ptest = 0, origin = 0, nmin = 0, nmax = 0;
283 int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
277 284
278 if (size < 26 || (size - 26) % 28 != 0) 285 if (size < 26 || (size - 26) % 28 != 0)
279 return -EIO; 286 return -EIO;
280 287
288 /* always track the first finger; when detached, start over */
281 if (fingers) { 289 if (fingers) {
282 p = raw2int(f->force_major); 290 raw_p = raw2int(f->force_major);
283 w = raw2int(f->size_major); 291 raw_w = raw2int(f->size_major);
284 x = raw2int(f->abs_x); 292 raw_x = raw2int(f->abs_x);
285 y = raw2int(f->abs_y); 293 raw_y = raw2int(f->abs_y);
286 n = p > 0 ? fingers : 0;
287 294
288 dprintk(9, 295 dprintk(9,
289 "bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n", 296 "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n",
290 p, w, x, y, n); 297 raw_p, raw_w, raw_x, raw_y);
298
299 ptest = int2bound(&c->p, raw_p);
300 origin = raw2int(f->origin);
301 }
291 302
292 input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w)); 303 /* while tracking finger still valid, count all fingers */
293 input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin)); 304 if (ptest > PRESSURE_LOW && origin) {
294 input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y)); 305 abs_p = ptest;
306 abs_w = int2bound(&c->w, raw_w);
307 abs_x = int2bound(&c->x, raw_x - c->x.devmin);
308 abs_y = int2bound(&c->y, c->y.devmax - raw_y);
309 for (; f != dev->tp_data->finger + fingers; f++) {
310 ptest = int2bound(&c->p, raw2int(f->force_major));
311 if (ptest > PRESSURE_LOW)
312 nmax++;
313 if (ptest > PRESSURE_HIGH)
314 nmin++;
315 }
295 } 316 }
296 317
297 input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p)); 318 if (dev->fingers < nmin)
319 dev->fingers = nmin;
320 if (dev->fingers > nmax)
321 dev->fingers = nmax;
322
323 input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
324 input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
325 input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2);
298 326
299 input_report_key(input, BTN_TOOL_FINGER, n == 1); 327 input_report_abs(input, ABS_PRESSURE, abs_p);
300 input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2); 328 input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
301 input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2); 329
330 if (abs_p) {
331 input_report_abs(input, ABS_X, abs_x);
332 input_report_abs(input, ABS_Y, abs_y);
333
334 dprintk(8,
335 "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
336 "nmin: %d nmax: %d n: %d\n",
337 abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers);
338
339 }
302 340
303 input_sync(input); 341 input_sync(input);
304 342