aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/hgpk.c
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2010-11-12 01:20:02 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-11-12 01:21:19 -0500
commitc0dc8342656a1425c31dcc505072f2387f0f0c92 (patch)
tree042c9a331a54ad2095688f01dc5602ae96889dbc /drivers/input/mouse/hgpk.c
parentca94ec43540ce5d93fd30a3bf88321b6f11ed51a (diff)
Input: hgpk - rework spew detection
The old implementation of spew detection simply tracked the overall position delta of the cursor over every 100 packets. We found that this causes occasional false positives in spew detection, and also that the conditions of the spewy packets are perhaps more fixed than we once thought. Rework the spew detection to look for packets of specific small delta, and only recalibrating if the overall movement delta stays within expected bounds. Also discard duplicate packets in the advanced mode, which appear to be very common. If we don't, the spew detection kicks in far too early. If we get a large spew of duplicates, request a recalibration straight up. Based on earlier work by Paul Fox. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/mouse/hgpk.c')
-rw-r--r--drivers/input/mouse/hgpk.c122
1 files changed, 91 insertions, 31 deletions
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 3d33d958a122..222594742c39 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -54,7 +54,7 @@ module_param(jumpy_delay, int, 0644);
54MODULE_PARM_DESC(jumpy_delay, 54MODULE_PARM_DESC(jumpy_delay,
55 "delay (ms) before recal after jumpiness detected"); 55 "delay (ms) before recal after jumpiness detected");
56 56
57static int spew_delay = 1000; 57static int spew_delay = 1;
58module_param(spew_delay, int, 0644); 58module_param(spew_delay, int, 0644);
59MODULE_PARM_DESC(spew_delay, 59MODULE_PARM_DESC(spew_delay,
60 "delay (ms) before recal after packet spew detected"); 60 "delay (ms) before recal after packet spew detected");
@@ -117,6 +117,23 @@ static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
117 } 117 }
118} 118}
119 119
120static void hgpk_reset_spew_detection(struct hgpk_data *priv)
121{
122 priv->spew_count = 0;
123 priv->dupe_count = 0;
124 priv->x_tally = 0;
125 priv->y_tally = 0;
126 priv->spew_flag = NO_SPEW;
127}
128
129static void hgpk_reset_hack_state(struct psmouse *psmouse)
130{
131 struct hgpk_data *priv = psmouse->private;
132
133 priv->abs_x = priv->abs_y = -1;
134 hgpk_reset_spew_detection(priv);
135}
136
120/* 137/*
121 * We have no idea why this particular hardware bug occurs. The touchpad 138 * We have no idea why this particular hardware bug occurs. The touchpad
122 * will randomly start spewing packets without anything touching the 139 * will randomly start spewing packets without anything touching the
@@ -142,20 +159,57 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
142 if (l || r) 159 if (l || r)
143 return; 160 return;
144 161
162 /* don't track spew if the workaround feature has been turned off */
163 if (!spew_delay)
164 return;
165
166 if (abs(x) > 3 || abs(y) > 3) {
167 /* no spew, or spew ended */
168 hgpk_reset_spew_detection(priv);
169 return;
170 }
171
172 /* Keep a tally of the overall delta to the cursor position caused by
173 * the spew */
145 priv->x_tally += x; 174 priv->x_tally += x;
146 priv->y_tally += y; 175 priv->y_tally += y;
147 176
148 if (++priv->count > 100) { 177 switch (priv->spew_flag) {
178 case NO_SPEW:
179 /* we're not spewing, but this packet might be the start */
180 priv->spew_flag = MAYBE_SPEWING;
181
182 /* fall-through */
183
184 case MAYBE_SPEWING:
185 priv->spew_count++;
186
187 if (priv->spew_count < SPEW_WATCH_COUNT)
188 break;
189
190 /* excessive spew detected, request recalibration */
191 priv->spew_flag = SPEW_DETECTED;
192
193 /* fall-through */
194
195 case SPEW_DETECTED:
196 /* only recalibrate when the overall delta to the cursor
197 * is really small. if the spew is causing significant cursor
198 * movement, it is probably a case of the user moving the
199 * cursor very slowly across the screen. */
149 if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) { 200 if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
150 hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n", 201 hgpk_err(psmouse, "packet spew detected (%d,%d)\n",
151 priv->x_tally, priv->y_tally); 202 priv->x_tally, priv->y_tally);
203 priv->spew_flag = RECALIBRATING;
152 psmouse_queue_work(psmouse, &priv->recalib_wq, 204 psmouse_queue_work(psmouse, &priv->recalib_wq,
153 msecs_to_jiffies(spew_delay)); 205 msecs_to_jiffies(spew_delay));
154 } 206 }
155 /* reset every 100 packets */ 207
156 priv->count = 0; 208 break;
157 priv->x_tally = 0; 209 case RECALIBRATING:
158 priv->y_tally = 0; 210 /* we already detected a spew and requested a recalibration,
211 * just wait for the queue to kick into action. */
212 break;
159 } 213 }
160} 214}
161 215
@@ -267,30 +321,43 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
267 * If this packet says that the finger was removed, reset our position 321 * If this packet says that the finger was removed, reset our position
268 * tracking so that we don't erroneously detect a jump on next press. 322 * tracking so that we don't erroneously detect a jump on next press.
269 */ 323 */
270 if (!down) 324 if (!down) {
271 priv->abs_x = priv->abs_y = -1; 325 hgpk_reset_hack_state(priv);
326 goto done;
327 }
272 328
273 /* 329 /*
274 * Report position if finger/pen is down, but weed out duplicate 330 * Weed out duplicate packets (we get quite a few, and they mess up
275 * packets (we get quite a few in this mode, and they mess up our 331 * our jump detection)
276 * jump detection.
277 */ 332 */
278 if (down && (x != priv->abs_x || y != priv->abs_y)) { 333 if (x == priv->abs_x && y == priv->abs_y) {
279 334 if (++priv->dupe_count > SPEW_WATCH_COUNT) {
280 /* Don't apply hacks in PT mode, it seems reliable */ 335 if (tpdebug)
281 if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) { 336 hgpk_dbg(psmouse, "hard spew detected\n");
282 hgpk_jumpy_hack(psmouse, 337 priv->spew_flag = RECALIBRATING;
283 priv->abs_x - x, priv->abs_y - y); 338 psmouse_queue_work(psmouse, &priv->recalib_wq,
284 hgpk_spewing_hack(psmouse, left, right, 339 msecs_to_jiffies(spew_delay));
285 priv->abs_x - x, priv->abs_y - y);
286 } 340 }
341 goto done;
342 }
287 343
288 input_report_abs(idev, ABS_X, x); 344 /* not a duplicate, continue with position reporting */
289 input_report_abs(idev, ABS_Y, y); 345 priv->dupe_count = 0;
290 priv->abs_x = x; 346
291 priv->abs_y = y; 347 /* Don't apply hacks in PT mode, it seems reliable */
348 if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) {
349 hgpk_jumpy_hack(psmouse,
350 priv->abs_x - x, priv->abs_y - y);
351 hgpk_spewing_hack(psmouse, left, right,
352 priv->abs_x - x, priv->abs_y - y);
292 } 353 }
293 354
355 input_report_abs(idev, ABS_X, x);
356 input_report_abs(idev, ABS_Y, y);
357 priv->abs_x = x;
358 priv->abs_y = y;
359
360done:
294 input_sync(idev); 361 input_sync(idev);
295} 362}
296 363
@@ -462,13 +529,6 @@ static void hgpk_setup_input_device(struct input_dev *input,
462 } 529 }
463} 530}
464 531
465static void hgpk_reset_hack_state(struct psmouse *psmouse)
466{
467 struct hgpk_data *priv = psmouse->private;
468
469 priv->abs_x = priv->abs_y = -1;
470}
471
472static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) 532static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
473{ 533{
474 int err; 534 int err;