Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Daniel Drake and committed by
Dmitry Torokhov
a309cdc7 c0dc8342

+88 -20
+86 -20
drivers/input/mouse/hgpk.c
··· 40 40 #include "psmouse.h" 41 41 #include "hgpk.h" 42 42 43 + #define ILLEGAL_XY 999999 44 + 43 45 static bool tpdebug; 44 46 module_param(tpdebug, bool, 0644); 45 47 MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); ··· 49 47 static int recalib_delta = 100; 50 48 module_param(recalib_delta, int, 0644); 51 49 MODULE_PARM_DESC(recalib_delta, 52 - "packets containing a delta this large will cause a recalibration."); 50 + "packets containing a delta this large will be discarded, and a " 51 + "recalibration may be scheduled."); 53 52 54 - static int jumpy_delay = 1000; 53 + static int jumpy_delay = 20; 55 54 module_param(jumpy_delay, int, 0644); 56 55 MODULE_PARM_DESC(jumpy_delay, 57 56 "delay (ms) before recal after jumpiness detected"); ··· 99 96 } 100 97 101 98 /* 102 - * When the touchpad gets ultra-sensitive, one can keep their finger 1/2" 103 - * above the pad and still have it send packets. This causes a jump cursor 104 - * when one places their finger on the pad. We can probably detect the 105 - * jump as we see a large deltas (>= 100px). In mouse mode, I've been 106 - * unable to even come close to 100px deltas during normal usage, so I think 107 - * this threshold is safe. If a large delta occurs, trigger a recalibration. 99 + * see if new value is within 20% of half of old value 108 100 */ 109 - static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y) 101 + static int approx_half(int curr, int prev) 102 + { 103 + int belowhalf, abovehalf; 104 + 105 + if (curr < 5 || prev < 5) 106 + return 0; 107 + 108 + belowhalf = (prev * 8) / 20; 109 + abovehalf = (prev * 12) / 20; 110 + 111 + return belowhalf < curr && curr <= abovehalf; 112 + } 113 + 114 + /* 115 + * Throw out oddly large delta packets, and any that immediately follow whose 116 + * values are each approximately half of the previous. It seems that the ALPS 117 + * firmware emits errant packets, and they get averaged out slowly. 118 + */ 119 + static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) 110 120 { 111 121 struct hgpk_data *priv = psmouse->private; 122 + int avx, avy; 123 + bool do_recal = false; 112 124 113 - if (abs(x) > recalib_delta || abs(y) > recalib_delta) { 114 - hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n", 115 - recalib_delta, x, y); 116 - /* My car gets forty rods to the hogshead and that's the 117 - * way I likes it! */ 125 + avx = abs(x); 126 + avy = abs(y); 127 + 128 + /* discard if too big, or half that but > 4 times the prev delta */ 129 + if (avx > recalib_delta || 130 + (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) { 131 + hgpk_err(psmouse, "detected %dpx jump in x\n", x); 132 + priv->xbigj = avx; 133 + } else if (approx_half(avx, priv->xbigj)) { 134 + hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x); 135 + priv->xbigj = avx; 136 + priv->xsaw_secondary++; 137 + } else { 138 + if (priv->xbigj && priv->xsaw_secondary > 1) 139 + do_recal = true; 140 + priv->xbigj = 0; 141 + priv->xsaw_secondary = 0; 142 + } 143 + 144 + if (avy > recalib_delta || 145 + (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) { 146 + hgpk_err(psmouse, "detected %dpx jump in y\n", y); 147 + priv->ybigj = avy; 148 + } else if (approx_half(avy, priv->ybigj)) { 149 + hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y); 150 + priv->ybigj = avy; 151 + priv->ysaw_secondary++; 152 + } else { 153 + if (priv->ybigj && priv->ysaw_secondary > 1) 154 + do_recal = true; 155 + priv->ybigj = 0; 156 + priv->ysaw_secondary = 0; 157 + } 158 + 159 + priv->xlast = avx; 160 + priv->ylast = avy; 161 + 162 + if (do_recal && jumpy_delay) { 163 + hgpk_err(psmouse, "scheduling recalibration\n"); 118 164 psmouse_queue_work(psmouse, &priv->recalib_wq, 119 165 msecs_to_jiffies(jumpy_delay)); 120 166 } 167 + 168 + return priv->xbigj || priv->ybigj; 121 169 } 122 170 123 171 static void hgpk_reset_spew_detection(struct hgpk_data *priv) ··· 185 131 struct hgpk_data *priv = psmouse->private; 186 132 187 133 priv->abs_x = priv->abs_y = -1; 134 + priv->xlast = priv->ylast = ILLEGAL_XY; 135 + priv->xbigj = priv->ybigj = 0; 136 + priv->xsaw_secondary = priv->ysaw_secondary = 0; 188 137 hgpk_reset_spew_detection(priv); 189 138 } 190 139 ··· 379 322 * tracking so that we don't erroneously detect a jump on next press. 380 323 */ 381 324 if (!down) { 382 - hgpk_reset_hack_state(priv); 325 + hgpk_reset_hack_state(psmouse); 383 326 goto done; 384 327 } 385 328 ··· 403 346 404 347 /* Don't apply hacks in PT mode, it seems reliable */ 405 348 if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) { 406 - hgpk_jumpy_hack(psmouse, 407 - priv->abs_x - x, priv->abs_y - y); 408 - hgpk_spewing_hack(psmouse, left, right, 409 - priv->abs_x - x, priv->abs_y - y); 349 + int x_diff = priv->abs_x - x; 350 + int y_diff = priv->abs_y - y; 351 + if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) { 352 + if (tpdebug) 353 + hgpk_dbg(psmouse, "discarding\n"); 354 + goto done; 355 + } 356 + hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff); 410 357 } 411 358 412 359 input_report_abs(idev, ABS_X, x); ··· 431 370 int x = packet[1] - ((packet[0] << 4) & 0x100); 432 371 int y = ((packet[0] << 3) & 0x100) - packet[2]; 433 372 434 - hgpk_jumpy_hack(psmouse, x, y); 373 + if (hgpk_discard_decay_hack(psmouse, x, y)) { 374 + if (tpdebug) 375 + hgpk_dbg(psmouse, "discarding\n"); 376 + return; 377 + } 378 + 435 379 hgpk_spewing_hack(psmouse, left, right, x, y); 436 380 437 381 if (tpdebug)
+2
drivers/input/mouse/hgpk.h
··· 42 42 struct delayed_work recalib_wq; 43 43 int abs_x, abs_y; 44 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 49 #define hgpk_dbg(psmouse, format, arg...) \