aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2010-11-12 01:20:03 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-11-12 01:21:24 -0500
commita309cdc778b9eece59b34e9e1c26e41476dbbcd6 (patch)
tree40dba65fd78c058f8dd28d5972707ea4f09f0fdb
parentc0dc8342656a1425c31dcc505072f2387f0f0c92 (diff)
Input: hgpk - extend jumpiness detection
In addition to forcing recalibrations upon detection of cursor jumps (and performing them quicker than before), detect and discard errant 'jump' packets caused by a firmware bug, which are then repeated with each one being approximately half the delta of the one previously (as if it is averaging out) Based on original work by Paul Fox. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/mouse/hgpk.c106
-rw-r--r--drivers/input/mouse/hgpk.h2
2 files changed, 88 insertions, 20 deletions
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 222594742c39..b54f074ec307 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -40,6 +40,8 @@
40#include "psmouse.h" 40#include "psmouse.h"
41#include "hgpk.h" 41#include "hgpk.h"
42 42
43#define ILLEGAL_XY 999999
44
43static bool tpdebug; 45static bool tpdebug;
44module_param(tpdebug, bool, 0644); 46module_param(tpdebug, bool, 0644);
45MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); 47MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
@@ -47,9 +49,10 @@ MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
47static int recalib_delta = 100; 49static int recalib_delta = 100;
48module_param(recalib_delta, int, 0644); 50module_param(recalib_delta, int, 0644);
49MODULE_PARM_DESC(recalib_delta, 51MODULE_PARM_DESC(recalib_delta,
50 "packets containing a delta this large will cause a recalibration."); 52 "packets containing a delta this large will be discarded, and a "
53 "recalibration may be scheduled.");
51 54
52static int jumpy_delay = 1000; 55static int jumpy_delay = 20;
53module_param(jumpy_delay, int, 0644); 56module_param(jumpy_delay, int, 0644);
54MODULE_PARM_DESC(jumpy_delay, 57MODULE_PARM_DESC(jumpy_delay,
55 "delay (ms) before recal after jumpiness detected"); 58 "delay (ms) before recal after jumpiness detected");
@@ -96,25 +99,76 @@ static int hgpk_mode_from_name(const char *buf, int len)
96} 99}
97 100
98/* 101/*
99 * When the touchpad gets ultra-sensitive, one can keep their finger 1/2" 102 * see if new value is within 20% of half of old value
100 * above the pad and still have it send packets. This causes a jump cursor 103 */
101 * when one places their finger on the pad. We can probably detect the 104static int approx_half(int curr, int prev)
102 * jump as we see a large deltas (>= 100px). In mouse mode, I've been 105{
103 * unable to even come close to 100px deltas during normal usage, so I think 106 int belowhalf, abovehalf;
104 * this threshold is safe. If a large delta occurs, trigger a recalibration. 107
108 if (curr < 5 || prev < 5)
109 return 0;
110
111 belowhalf = (prev * 8) / 20;
112 abovehalf = (prev * 12) / 20;
113
114 return belowhalf < curr && curr <= abovehalf;
115}
116
117/*
118 * Throw out oddly large delta packets, and any that immediately follow whose
119 * values are each approximately half of the previous. It seems that the ALPS
120 * firmware emits errant packets, and they get averaged out slowly.
105 */ 121 */
106static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y) 122static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
107{ 123{
108 struct hgpk_data *priv = psmouse->private; 124 struct hgpk_data *priv = psmouse->private;
125 int avx, avy;
126 bool do_recal = false;
127
128 avx = abs(x);
129 avy = abs(y);
130
131 /* discard if too big, or half that but > 4 times the prev delta */
132 if (avx > recalib_delta ||
133 (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) {
134 hgpk_err(psmouse, "detected %dpx jump in x\n", x);
135 priv->xbigj = avx;
136 } else if (approx_half(avx, priv->xbigj)) {
137 hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x);
138 priv->xbigj = avx;
139 priv->xsaw_secondary++;
140 } else {
141 if (priv->xbigj && priv->xsaw_secondary > 1)
142 do_recal = true;
143 priv->xbigj = 0;
144 priv->xsaw_secondary = 0;
145 }
109 146
110 if (abs(x) > recalib_delta || abs(y) > recalib_delta) { 147 if (avy > recalib_delta ||
111 hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n", 148 (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) {
112 recalib_delta, x, y); 149 hgpk_err(psmouse, "detected %dpx jump in y\n", y);
113 /* My car gets forty rods to the hogshead and that's the 150 priv->ybigj = avy;
114 * way I likes it! */ 151 } else if (approx_half(avy, priv->ybigj)) {
152 hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y);
153 priv->ybigj = avy;
154 priv->ysaw_secondary++;
155 } else {
156 if (priv->ybigj && priv->ysaw_secondary > 1)
157 do_recal = true;
158 priv->ybigj = 0;
159 priv->ysaw_secondary = 0;
160 }
161
162 priv->xlast = avx;
163 priv->ylast = avy;
164
165 if (do_recal && jumpy_delay) {
166 hgpk_err(psmouse, "scheduling recalibration\n");
115 psmouse_queue_work(psmouse, &priv->recalib_wq, 167 psmouse_queue_work(psmouse, &priv->recalib_wq,
116 msecs_to_jiffies(jumpy_delay)); 168 msecs_to_jiffies(jumpy_delay));
117 } 169 }
170
171 return priv->xbigj || priv->ybigj;
118} 172}
119 173
120static void hgpk_reset_spew_detection(struct hgpk_data *priv) 174static void hgpk_reset_spew_detection(struct hgpk_data *priv)
@@ -131,6 +185,9 @@ static void hgpk_reset_hack_state(struct psmouse *psmouse)
131 struct hgpk_data *priv = psmouse->private; 185 struct hgpk_data *priv = psmouse->private;
132 186
133 priv->abs_x = priv->abs_y = -1; 187 priv->abs_x = priv->abs_y = -1;
188 priv->xlast = priv->ylast = ILLEGAL_XY;
189 priv->xbigj = priv->ybigj = 0;
190 priv->xsaw_secondary = priv->ysaw_secondary = 0;
134 hgpk_reset_spew_detection(priv); 191 hgpk_reset_spew_detection(priv);
135} 192}
136 193
@@ -322,7 +379,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
322 * tracking so that we don't erroneously detect a jump on next press. 379 * tracking so that we don't erroneously detect a jump on next press.
323 */ 380 */
324 if (!down) { 381 if (!down) {
325 hgpk_reset_hack_state(priv); 382 hgpk_reset_hack_state(psmouse);
326 goto done; 383 goto done;
327 } 384 }
328 385
@@ -346,10 +403,14 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
346 403
347 /* Don't apply hacks in PT mode, it seems reliable */ 404 /* Don't apply hacks in PT mode, it seems reliable */
348 if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) { 405 if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) {
349 hgpk_jumpy_hack(psmouse, 406 int x_diff = priv->abs_x - x;
350 priv->abs_x - x, priv->abs_y - y); 407 int y_diff = priv->abs_y - y;
351 hgpk_spewing_hack(psmouse, left, right, 408 if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) {
352 priv->abs_x - x, priv->abs_y - y); 409 if (tpdebug)
410 hgpk_dbg(psmouse, "discarding\n");
411 goto done;
412 }
413 hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff);
353 } 414 }
354 415
355 input_report_abs(idev, ABS_X, x); 416 input_report_abs(idev, ABS_X, x);
@@ -370,7 +431,12 @@ static void hgpk_process_simple_packet(struct psmouse *psmouse)
370 int x = packet[1] - ((packet[0] << 4) & 0x100); 431 int x = packet[1] - ((packet[0] << 4) & 0x100);
371 int y = ((packet[0] << 3) & 0x100) - packet[2]; 432 int y = ((packet[0] << 3) & 0x100) - packet[2];
372 433
373 hgpk_jumpy_hack(psmouse, x, y); 434 if (hgpk_discard_decay_hack(psmouse, x, y)) {
435 if (tpdebug)
436 hgpk_dbg(psmouse, "discarding\n");
437 return;
438 }
439
374 hgpk_spewing_hack(psmouse, left, right, x, y); 440 hgpk_spewing_hack(psmouse, left, right, x, y);
375 441
376 if (tpdebug) 442 if (tpdebug)
diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h
index bccdb26dca49..311c0e87fcbf 100644
--- a/drivers/input/mouse/hgpk.h
+++ b/drivers/input/mouse/hgpk.h
@@ -42,6 +42,8 @@ struct hgpk_data {
42 struct delayed_work recalib_wq; 42 struct delayed_work recalib_wq;
43 int abs_x, abs_y; 43 int abs_x, abs_y;
44 int dupe_count; 44 int dupe_count;
45 int xbigj, ybigj, xlast, ylast; /* jumpiness detection */
46 int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
45}; 47};
46 48
47#define hgpk_dbg(psmouse, format, arg...) \ 49#define hgpk_dbg(psmouse, format, arg...) \