diff options
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; |