diff options
author | Daniel Drake <dsd@laptop.org> | 2010-11-12 01:20:02 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-11-12 01:21:19 -0500 |
commit | c0dc8342656a1425c31dcc505072f2387f0f0c92 (patch) | |
tree | 042c9a331a54ad2095688f01dc5602ae96889dbc /drivers/input/mouse/hgpk.c | |
parent | ca94ec43540ce5d93fd30a3bf88321b6f11ed51a (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.c | 122 |
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); | |||
54 | MODULE_PARM_DESC(jumpy_delay, | 54 | MODULE_PARM_DESC(jumpy_delay, |
55 | "delay (ms) before recal after jumpiness detected"); | 55 | "delay (ms) before recal after jumpiness detected"); |
56 | 56 | ||
57 | static int spew_delay = 1000; | 57 | static int spew_delay = 1; |
58 | module_param(spew_delay, int, 0644); | 58 | module_param(spew_delay, int, 0644); |
59 | MODULE_PARM_DESC(spew_delay, | 59 | MODULE_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 | ||
120 | static 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 | |||
129 | static 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 | |||
360 | done: | ||
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 | ||
465 | static 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 | |||
472 | static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) | 532 | static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) |
473 | { | 533 | { |
474 | int err; | 534 | int err; |