Commit a309cdc7 authored by Daniel Drake's avatar Daniel Drake Committed by Dmitry Torokhov

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: default avatarDaniel Drake <dsd@laptop.org>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent c0dc8342
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include "psmouse.h" #include "psmouse.h"
#include "hgpk.h" #include "hgpk.h"
#define ILLEGAL_XY 999999
static bool tpdebug; static bool tpdebug;
module_param(tpdebug, bool, 0644); module_param(tpdebug, bool, 0644);
MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); 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,9 +49,10 @@ MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
static int recalib_delta = 100; static int recalib_delta = 100;
module_param(recalib_delta, int, 0644); module_param(recalib_delta, int, 0644);
MODULE_PARM_DESC(recalib_delta, MODULE_PARM_DESC(recalib_delta,
"packets containing a delta this large will cause a recalibration."); "packets containing a delta this large will be discarded, and a "
"recalibration may be scheduled.");
static int jumpy_delay = 1000; static int jumpy_delay = 20;
module_param(jumpy_delay, int, 0644); module_param(jumpy_delay, int, 0644);
MODULE_PARM_DESC(jumpy_delay, MODULE_PARM_DESC(jumpy_delay,
"delay (ms) before recal after jumpiness detected"); "delay (ms) before recal after jumpiness detected");
...@@ -96,25 +99,76 @@ static int hgpk_mode_from_name(const char *buf, int len) ...@@ -96,25 +99,76 @@ static int hgpk_mode_from_name(const char *buf, int len)
} }
/* /*
* When the touchpad gets ultra-sensitive, one can keep their finger 1/2" * see if new value is within 20% of half of old value
* above the pad and still have it send packets. This causes a jump cursor
* when one places their finger on the pad. We can probably detect the
* jump as we see a large deltas (>= 100px). In mouse mode, I've been
* unable to even come close to 100px deltas during normal usage, so I think
* this threshold is safe. If a large delta occurs, trigger a recalibration.
*/ */
static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y) static int approx_half(int curr, int prev)
{
int belowhalf, abovehalf;
if (curr < 5 || prev < 5)
return 0;
belowhalf = (prev * 8) / 20;
abovehalf = (prev * 12) / 20;
return belowhalf < curr && curr <= abovehalf;
}
/*
* Throw out oddly large delta packets, and any that immediately follow whose
* values are each approximately half of the previous. It seems that the ALPS
* firmware emits errant packets, and they get averaged out slowly.
*/
static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
{ {
struct hgpk_data *priv = psmouse->private; struct hgpk_data *priv = psmouse->private;
int avx, avy;
bool do_recal = false;
avx = abs(x);
avy = abs(y);
/* discard if too big, or half that but > 4 times the prev delta */
if (avx > recalib_delta ||
(avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) {
hgpk_err(psmouse, "detected %dpx jump in x\n", x);
priv->xbigj = avx;
} else if (approx_half(avx, priv->xbigj)) {
hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x);
priv->xbigj = avx;
priv->xsaw_secondary++;
} else {
if (priv->xbigj && priv->xsaw_secondary > 1)
do_recal = true;
priv->xbigj = 0;
priv->xsaw_secondary = 0;
}
if (abs(x) > recalib_delta || abs(y) > recalib_delta) { if (avy > recalib_delta ||
hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n", (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) {
recalib_delta, x, y); hgpk_err(psmouse, "detected %dpx jump in y\n", y);
/* My car gets forty rods to the hogshead and that's the priv->ybigj = avy;
* way I likes it! */ } else if (approx_half(avy, priv->ybigj)) {
hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y);
priv->ybigj = avy;
priv->ysaw_secondary++;
} else {
if (priv->ybigj && priv->ysaw_secondary > 1)
do_recal = true;
priv->ybigj = 0;
priv->ysaw_secondary = 0;
}
priv->xlast = avx;
priv->ylast = avy;
if (do_recal && jumpy_delay) {
hgpk_err(psmouse, "scheduling recalibration\n");
psmouse_queue_work(psmouse, &priv->recalib_wq, psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(jumpy_delay)); msecs_to_jiffies(jumpy_delay));
} }
return priv->xbigj || priv->ybigj;
} }
static void hgpk_reset_spew_detection(struct hgpk_data *priv) static void hgpk_reset_spew_detection(struct hgpk_data *priv)
...@@ -131,6 +185,9 @@ static void hgpk_reset_hack_state(struct psmouse *psmouse) ...@@ -131,6 +185,9 @@ static void hgpk_reset_hack_state(struct psmouse *psmouse)
struct hgpk_data *priv = psmouse->private; struct hgpk_data *priv = psmouse->private;
priv->abs_x = priv->abs_y = -1; priv->abs_x = priv->abs_y = -1;
priv->xlast = priv->ylast = ILLEGAL_XY;
priv->xbigj = priv->ybigj = 0;
priv->xsaw_secondary = priv->ysaw_secondary = 0;
hgpk_reset_spew_detection(priv); hgpk_reset_spew_detection(priv);
} }
...@@ -322,7 +379,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) ...@@ -322,7 +379,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
* tracking so that we don't erroneously detect a jump on next press. * tracking so that we don't erroneously detect a jump on next press.
*/ */
if (!down) { if (!down) {
hgpk_reset_hack_state(priv); hgpk_reset_hack_state(psmouse);
goto done; goto done;
} }
...@@ -346,10 +403,14 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) ...@@ -346,10 +403,14 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
/* Don't apply hacks in PT mode, it seems reliable */ /* Don't apply hacks in PT mode, it seems reliable */
if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) { if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) {
hgpk_jumpy_hack(psmouse, int x_diff = priv->abs_x - x;
priv->abs_x - x, priv->abs_y - y); int y_diff = priv->abs_y - y;
hgpk_spewing_hack(psmouse, left, right, if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) {
priv->abs_x - x, priv->abs_y - y); if (tpdebug)
hgpk_dbg(psmouse, "discarding\n");
goto done;
}
hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff);
} }
input_report_abs(idev, ABS_X, x); input_report_abs(idev, ABS_X, x);
...@@ -370,7 +431,12 @@ static void hgpk_process_simple_packet(struct psmouse *psmouse) ...@@ -370,7 +431,12 @@ static void hgpk_process_simple_packet(struct psmouse *psmouse)
int x = packet[1] - ((packet[0] << 4) & 0x100); int x = packet[1] - ((packet[0] << 4) & 0x100);
int y = ((packet[0] << 3) & 0x100) - packet[2]; int y = ((packet[0] << 3) & 0x100) - packet[2];
hgpk_jumpy_hack(psmouse, x, y); if (hgpk_discard_decay_hack(psmouse, x, y)) {
if (tpdebug)
hgpk_dbg(psmouse, "discarding\n");
return;
}
hgpk_spewing_hack(psmouse, left, right, x, y); hgpk_spewing_hack(psmouse, left, right, x, y);
if (tpdebug) if (tpdebug)
......
...@@ -42,6 +42,8 @@ struct hgpk_data { ...@@ -42,6 +42,8 @@ struct hgpk_data {
struct delayed_work recalib_wq; struct delayed_work recalib_wq;
int abs_x, abs_y; int abs_x, abs_y;
int dupe_count; int dupe_count;
int xbigj, ybigj, xlast, ylast; /* jumpiness detection */
int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
}; };
#define hgpk_dbg(psmouse, format, arg...) \ #define hgpk_dbg(psmouse, format, arg...) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment