[PATCH] add-skip_filter-s3c2410_ts.patch

Nelson Castillo nelsoneci at gmail.com
Tue Dec 2 07:51:34 CET 2008


Skip filter for touchscreen values.

Problem: The first and the last sample might be unreliable. We provide
this filter as a separate function in order to keep the event_send_timer_f
function simple. This filter:

* Skips NHEAD points after IE_DOWN
* Skips NTAIL points before IE_UP
* Ignores a click if we have less than (NHEAD + NTAIL + 1) points

Right now the filter is embedded in the driver. We have two #defines with
the parameters SKIP_NHEAD and SKIP_NTAIL. I didn't store their values in
struct skip_filter on purpose.

Signed-off-by: Nelson Castillo <nelsoneci at gmail.com>
---

 0 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index 5a31c4f..a880163 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -102,6 +102,9 @@ static char *s3c2410ts_name = "s3c2410 TouchScreen";
 #define TS_STATE_RELEASE_PENDING 3
 #define TS_STATE_RELEASE 4
 
+#define SKIP_NHEAD 2
+#define SKIP_NTAIL 2
+
 /*
  * Per-touchscreen data.
  */
@@ -119,6 +122,9 @@ static struct s3c2410ts ts;
 
 static void __iomem *base_addr;
 
+/*
+ * A few low level functions.
+ */
 
 static inline void s3c2410_ts_connect(void)
 {
@@ -140,18 +146,18 @@ static void s3c2410_ts_start_adc_conversion(void)
  * Just send the input events.
  */
 
-enum ts_input_event {IE_DOWN = 0, IE_UP, IE_UPDATE};
+enum ts_input_event {IE_DOWN = 0, IE_UP};
 
 static void ts_input_report(int event, int coords[])
 {
 #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
-	static char *s[] = {"down", "up", "update"};
+	static char *s[] = {"down", "up"};
 	struct timeval tv;
 
 	do_gettimeofday(&tv);
 #endif
 
-	if (event == IE_DOWN || event == IE_UPDATE) {
+	if (event == IE_DOWN) {
 		input_report_abs(ts.dev, ABS_X, coords[0]);
 		input_report_abs(ts.dev, ABS_Y, coords[1]);
 		input_report_key(ts.dev, BTN_TOUCH, 1);
@@ -174,10 +180,93 @@ static void ts_input_report(int event, int coords[])
 	input_sync(ts.dev);
 }
 
+
 /*
- * Manage state of the touchscreen and send events.
+ * Skip filter for touchscreen values.
+ *
+ * Problem: The first and the last sample might be unreliable. We provide
+ * this filter as a separate function in order to keep the event_send_timer_f
+ * function simple. This filter:
+ *
+ * - Skips NHEAD points after IE_DOWN
+ * - Skips NTAIL points before IE_UP
+ * - Ignores a click if we have less than (NHEAD + NTAILl + 1) points
  */
 
+struct skip_filter_event {
+	int coords[2];
+};
+
+struct skip_filter {
+	unsigned N;
+	unsigned M;
+	int sent;
+	struct skip_filter_event buf[SKIP_NTAIL];
+};
+
+struct skip_filter ts_skip;
+
+static void ts_skip_filter_reset(void)
+{
+	ts_skip.N = 0;
+	ts_skip.M = 0;
+	ts_skip.sent = 0;
+}
+
+static void ts_skip_filter(int event, int coords[])
+{
+	/* skip the first N samples */
+	if (ts_skip.N < SKIP_NHEAD) {
+		if (IE_UP == event)
+			ts_skip_filter_reset();
+		else
+			ts_skip.N++;
+		return;
+	}
+
+	/* We didn't send DOWN -- Ignore UP */
+	if (IE_UP == event && !ts_skip.sent) {
+		ts_skip_filter_reset();
+		return;
+	}
+
+	/* Just accept the event if NTAIL == 0 */
+	if (!SKIP_NTAIL) {
+		ts_input_report(event, coords);
+		if (IE_UP == event)
+			ts_skip_filter_reset();
+		else
+			ts_skip.sent = 1;
+		return;
+	}
+
+	/* NTAIL > 0,  Queue current point if we need to */
+	if (!ts_skip.sent && ts_skip.M < SKIP_NTAIL) {
+		memcpy(&ts_skip.buf[ts_skip.M++].coords[0], &coords[0],
+		       sizeof(int) * 2);
+		return;
+	}
+
+	/* queue full: accept one, queue one */
+
+	if (ts_skip.M >= SKIP_NTAIL)
+		ts_skip.M = 0;
+
+	ts_input_report(event, ts_skip.buf[ts_skip.M].coords);
+
+	if (event == IE_UP) {
+		ts_skip_filter_reset();
+	} else {
+		memcpy(&ts_skip.buf[ts_skip.M++].coords[0], &coords[0],
+		       sizeof(int) * 2);
+		ts_skip.sent = 1;
+	}
+}
+
+
+/*
+ * Manage the state of the touchscreen. Send events to the skip filter.
+ */
 
 static void event_send_timer_f(unsigned long data);
 
@@ -189,7 +278,6 @@ static void event_send_timer_f(unsigned long data)
 	static unsigned long running;
 	static int noop_counter;
 	int event_type;
-	static unsigned n_points;
 
 	if (unlikely(test_and_set_bit(0, &running))) {
 		mod_timer(&event_send_timer,
@@ -225,14 +313,7 @@ static void event_send_timer_f(unsigned long data)
 				     != sizeof(int) * 2))
 				goto ts_exit_error;
 
-			if (n_points++ < 2)
-				break;
-
-			if (ts.state == TS_STATE_PRESSED_PENDING)
-				ts_input_report(IE_DOWN, buf);
-			else
-				ts_input_report(IE_UPDATE, buf);
-
+			ts_skip_filter(IE_DOWN, buf);
 			ts.state = TS_STATE_PRESSED;
 
 			break;
@@ -251,11 +332,8 @@ static void event_send_timer_f(unsigned long data)
 			 * while to avoid jitter. If we get a DOWN
 			 * event we do not send it. */
 
-			if (n_points > 2)
-				ts_input_report(IE_UP, NULL);
-
+			ts_skip_filter(IE_UP, NULL);
 			ts.state = TS_STATE_STANDBY;
-			n_points = 0;
 
 			if (ts.tsf[0])
 				(ts.tsf[0]->api->clear)(ts.tsf[0]);
@@ -438,6 +516,8 @@ static int __init s3c2410ts_probe(struct platform_device *pdev)
 	ts.dev->id.version = S3C2410TSVERSION;
 	ts.state = TS_STATE_STANDBY;
 
+	ts_skip_filter_reset();
+
 	/* create the filter chain set up for the 2 coordinates we produce */
 	ret = ts_filter_create_chain(
 		(struct ts_filter_api **)&info->filter_sequence,




More information about the openmoko-kernel mailing list