diff options
| -rw-r--r-- | drivers/input/mouse/hgpk.c | 106 | ||||
| -rw-r--r-- | drivers/input/mouse/hgpk.h | 2 |
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 | |||
| 43 | static bool tpdebug; | 45 | static bool tpdebug; |
| 44 | module_param(tpdebug, bool, 0644); | 46 | module_param(tpdebug, bool, 0644); |
| 45 | MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); | 47 | MODULE_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."); | |||
| 47 | static int recalib_delta = 100; | 49 | static int recalib_delta = 100; |
| 48 | module_param(recalib_delta, int, 0644); | 50 | module_param(recalib_delta, int, 0644); |
| 49 | MODULE_PARM_DESC(recalib_delta, | 51 | MODULE_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 | ||
| 52 | static int jumpy_delay = 1000; | 55 | static int jumpy_delay = 20; |
| 53 | module_param(jumpy_delay, int, 0644); | 56 | module_param(jumpy_delay, int, 0644); |
| 54 | MODULE_PARM_DESC(jumpy_delay, | 57 | MODULE_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 | 104 | static 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 | */ |
| 106 | static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y) | 122 | static 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 | ||
| 120 | static void hgpk_reset_spew_detection(struct hgpk_data *priv) | 174 | static 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...) \ |
