diff mbox

[2/3] Input: hgpk - Rework spew detection

Message ID 20101002204239.CB11A9D401C@zog.reactivated.net (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel Drake Oct. 2, 2010, 8:42 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index de635ed..a6c4ffe 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -58,7 +58,7 @@  module_param(jumpy_delay, int, 0644);
 MODULE_PARM_DESC(jumpy_delay,
 	"delay (ms) before recal after jumpiness detected");
 
-static int spew_delay = 1000;
+static int spew_delay = 1;
 module_param(spew_delay, int, 0644);
 MODULE_PARM_DESC(spew_delay,
 	"delay (ms) before recal after packet spew detected");
@@ -95,6 +95,14 @@  static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
 	}
 }
 
+static void reset_spew_detection(struct hgpk_data *priv)
+{
+	priv->spew_count = 0;
+	priv->x_tally = 0;
+	priv->y_tally = 0;
+	priv->spew_flag = NO_SPEW;
+}
+
 /*
  * We have no idea why this particular hardware bug occurs.  The touchpad
  * will randomly start spewing packets without anything touching the
@@ -120,20 +128,57 @@  static void hgpk_spewing_hack(struct psmouse *psmouse,
 	if (l || r)
 		return;
 
+	/* don't track spew if the workaround feature has been turned off */
+	if (!spew_delay)
+		return;
+
+	if (abs(x) > 3 || abs(y) > 3) {
+		/* no spew, or spew ended */
+		reset_spew_detection(priv);
+		return;
+	}
+
+	/* Keep a tally of the overall delta to the cursor position caused by
+	 * the spew */
 	priv->x_tally += x;
 	priv->y_tally += y;
 
-	if (++priv->count > 100) {
+	switch (priv->spew_flag) {
+	case NO_SPEW:
+		/* we're not spewing, but this packet might be the start */
+		priv->spew_flag = MAYBE_SPEWING;
+
+		/* fall-through */
+
+	case MAYBE_SPEWING:
+		priv->spew_count++;
+
+		if (priv->spew_count < SPEW_WATCH_COUNT)
+			break;
+
+		/* excessive spew detected, request recalibration */
+		priv->spew_flag = SPEW_DETECTED;
+
+		/* fall-through */
+
+	case SPEW_DETECTED:
+		/* only recalibrate when the overall delta to the cursor
+		 * is really small. if the spew is causing significant cursor
+		 * movement, it is probably a case of the user moving the
+		 * cursor very slowly across the screen. */
 		if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
-			hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
+			hgpk_err(psmouse, "packet spew detected (%d,%d)\n",
 				 priv->x_tally, priv->y_tally);
+			priv->spew_flag = RECALIBRATING;
 			psmouse_queue_work(psmouse, &priv->recalib_wq,
 					   msecs_to_jiffies(spew_delay));
 		}
-		/* reset every 100 packets */
-		priv->count = 0;
-		priv->x_tally = 0;
-		priv->y_tally = 0;
+
+		break;
+	case RECALIBRATING:
+		/* we already detected a spew and requested a recalibration,
+		 * just wait for the queue to kick into action. */
+		break;
 	}
 }
 
@@ -229,9 +274,18 @@  static int process_advanced_packet(struct psmouse *psmouse, int *x, int *y,
 	 * relative calcs, and our jump detection.
 	 */
 	if (*x == priv->abs_x && *y == priv->abs_y) {
+		if (++priv->dupe_count > SPEW_WATCH_COUNT) {
+			if (tpdebug)
+				hgpk_dbg(psmouse, "hard spew detected\n");
+			priv->spew_flag = RECALIBRATING;
+			psmouse_queue_work(psmouse, &priv->recalib_wq,
+					   msecs_to_jiffies(spew_delay));
+		}
 		if (tpdebug)
 			hgpk_dbg(psmouse, "dupe\n");
 		return -1;
+	} else {
+		priv->dupe_count = 0;
 	}
 
 	/*
@@ -378,6 +432,7 @@  static int hgpk_force_recalibrate(struct psmouse *psmouse)
 	msleep(150);
 
 	priv->isdown = false;
+	reset_spew_detection(priv);
 
 	if (hgpk_advanced_mode(psmouse)) {
 		hgpk_err(psmouse, "Failed to reinit advanced mode!\n");
diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h
index 002df7b..1ec18c8 100644
--- a/drivers/input/mouse/hgpk.h
+++ b/drivers/input/mouse/hgpk.h
@@ -16,12 +16,23 @@  enum hgpk_model_t {
 	HGPK_MODEL_D = 0x50,	/* C1, mass production */
 };
 
+enum hgpk_spew_flag {
+	NO_SPEW,
+	MAYBE_SPEWING,
+	SPEW_DETECTED,
+	RECALIBRATING,
+};
+
+#define SPEW_WATCH_COUNT 42  /* at 12ms/packet, this is 1/2 second */
+
 struct hgpk_data {
 	struct psmouse *psmouse;
 	bool powered;
 	bool isdown;
-	int count, x_tally, y_tally;	/* hardware workaround stuff */
+	enum hgpk_spew_flag spew_flag;
+	int spew_count, x_tally, y_tally;	/* spew detection */
 	int abs_x, abs_y;  /* for computing delta in advanced mode  */
+	int dupe_count;
 	int buttons;
 	unsigned long recalib_window;
 	struct delayed_work recalib_wq;