This filter is useful to reject samples that are not reliable. We consider
that a sample is not reliable if it deviates form the Majority.

This filter performs better than the variance filter thus we can replace it.
I will remove the skip filter later.

I haven't seen a bad click in a while. Somebody wake me up.

Signed-off-by: Nelson Castillo <[EMAIL PROTECTED]>
---

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

diff --git a/arch/arm/configs/gta02-moredrivers-defconfig 
b/arch/arm/configs/gta02-moredrivers-defconfig
index eb7d6b7..fbaf760 100644
--- a/arch/arm/configs/gta02-moredrivers-defconfig
+++ b/arch/arm/configs/gta02-moredrivers-defconfig
@@ -980,9 +980,9 @@ CONFIG_INPUT_MOUSE=y
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_FILTER=y
+CONFIG_TOUCHSCREEN_FILTER_GROUP=y
 CONFIG_TOUCHSCREEN_FILTER_MEDIAN=y
 CONFIG_TOUCHSCREEN_FILTER_MEAN=y
-CONFIG_TOUCHSCREEN_FILTER_VARIANCE=y
 # CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 CONFIG_TOUCHSCREEN_S3C2410=y
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c 
b/arch/arm/mach-s3c2440/mach-gta02.c
index 41ba0c8..e90f82b 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -105,7 +105,7 @@
 
 #include <linux/ts_filter_mean.h>
 #include <linux/ts_filter_median.h>
-#include <linux/ts_filter_variance.h>
+#include <linux/ts_filter_group.h>
 
 /* arbitrates which sensor IRQ owns the shared SPI bus */
 static spinlock_t motion_irq_lock;
@@ -1019,35 +1019,34 @@ static struct s3c2410_udc_mach_info gta02_udc_cfg = {
 
 /* touchscreen configuration */
 
-static struct ts_filter_variance_configuration gta02_ts_variance_config = {
-       .extent = 20,
-       .window = 5,
-       .threshold = 10,        /* variance = 10, std = 3.1623 */
-       .attempts = 5,          /* try 5 times before giving up */
+static struct ts_filter_group_configuration gta02_ts_group_config = {
+       .extent = 12,
+       .close_enough = 10,
+       .threshold = 6,         /* at least half of the points in a group */
+       .attempts = 10,
 };
 
 static struct ts_filter_median_configuration gta02_ts_median_config = {
-       .extent = 31,
-       .decimation_below = 5,
+       .extent = 20,
+       .decimation_below = 3,
        .decimation_threshold = 8 * 3,
-       .decimation_above = 10,
+       .decimation_above = 4,
 };
 
 static struct ts_filter_mean_configuration gta02_ts_mean_config = {
-       .bits_filter_length = 3,
-       .averaging_threshold = 6 * 3,
+       .bits_filter_length = 2, /* 4 points */
 };
 
 static struct s3c2410_ts_mach_info gta02_ts_cfg = {
        .delay = 10000,
        .presc = 0xff, /* slow as we can go */
        .filter_sequence = {
-               [0] = &ts_filter_variance_api,
+               [0] = &ts_filter_group_api,
                [1] = &ts_filter_median_api,
                [2] = &ts_filter_mean_api,
        },
        .filter_config = {
-               [0] = &gta02_ts_variance_config,
+               [0] = &gta02_ts_group_config,
                [1] = &gta02_ts_median_config,
                [2] = &gta02_ts_mean_config,
        },
diff --git a/drivers/input/touchscreen/Kconfig 
b/drivers/input/touchscreen/Kconfig
index 98566fd..a0f8599 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -21,13 +21,13 @@ menuconfig TOUCHSCREEN_FILTER
 
 if TOUCHSCREEN_FILTER
 
-config TOUCHSCREEN_FILTER_VARIANCE
-       bool "Variance Touchscreen Filter"
+config TOUCHSCREEN_FILTER_GROUP
+       bool "Group Touchscreen Filter"
        depends on INPUT_TOUCHSCREEN && TOUCHSCREEN_FILTER
        default Y
        help
-         Say Y here if you want to use the Variance touchscreen filter, it
-         helps discarding a click if we get too much noise.
+         Say Y here if you want to use the Group touchscreen filter, it
+         avoids using atypical samples.
 
 
 config TOUCHSCREEN_FILTER_MEDIAN
diff --git a/drivers/input/touchscreen/Makefile 
b/drivers/input/touchscreen/Makefile
index ee6bd28..9a6162c 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -33,6 +33,6 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)        += wm9713.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)     += mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_FILTER)       += ts_filter.o
-obj-$(CONFIG_TOUCHSCREEN_FILTER_VARIANCE)      += ts_filter_variance.o
+obj-$(CONFIG_TOUCHSCREEN_FILTER_GROUP) += ts_filter_group.o
 obj-$(CONFIG_TOUCHSCREEN_FILTER_MEDIAN)        += ts_filter_median.o
 obj-$(CONFIG_TOUCHSCREEN_FILTER_MEAN)  += ts_filter_mean.o
diff --git a/drivers/input/touchscreen/ts_filter_group.c 
b/drivers/input/touchscreen/ts_filter_group.c
new file mode 100644
index 0000000..250613f
--- /dev/null
+++ b/drivers/input/touchscreen/ts_filter_group.c
@@ -0,0 +1,217 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2008 by Openmoko, Inc.
+ * Author: Nelson Castillo <[EMAIL PROTECTED]>
+ * All rights reserved.
+ *
+ * This filter is useful to reject samples that are not reliable. We consider
+ * that a sample is not reliable if it deviates form the Majority.
+ *
+ * 1) We collect S samples.
+ *
+ * 2) For each dimension:
+ *
+ *  - We sort the points.
+ *  - Points that are "close enough" are considered to be in the same set.
+ *  - We choose the set with more elements. If more than "threshold"
+ *    points are in this set we use the first and the last point of the set
+ *    to define the valid range for this dimension [min, max], otherwise we
+ *    discard all the points and go to step 1.
+ *
+ * 3) We consider the unsorted S samples and try to feed them to the next
+ *    filter in the chain. If one of the points of each sample
+ *    is not in the allowed range for its dimension, we discard the sample.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/ts_filter_group.h>
+
+static void ts_filter_group_clear_internal(struct ts_filter_group *tsfg,
+                                          int attempts)
+{
+       tsfg->N = 0;
+       tsfg->tries_left = attempts;
+}
+
+static void ts_filter_group_clear(struct ts_filter *tsf)
+{
+       struct ts_filter_group *tsfg = (struct ts_filter_group *)tsf;
+
+       ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
+
+       if (tsf->next) /* chain */
+               (tsf->next->api->clear)(tsf->next);
+}
+
+static struct ts_filter *ts_filter_group_create(void *conf, int count_coords)
+{
+       struct ts_filter_group *tsfg;
+       int i;
+
+       BUG_ON((count_coords < 1) || (count_coords > MAX_TS_FILTER_COORDS));
+
+       tsfg = kzalloc(sizeof(struct ts_filter_group), GFP_KERNEL);
+       if (!tsfg)
+               return NULL;
+
+       tsfg->config = (struct ts_filter_group_configuration *)conf;
+       tsfg->tsf.count_coords = count_coords;
+
+       BUG_ON(tsfg->config->attempts <= 0);
+
+       tsfg->samples[0] = kmalloc((2 + count_coords) * sizeof(int) *
+                                  tsfg->config->extent, GFP_KERNEL);
+       if (!tsfg->samples[0]) {
+               kfree(tsfg);
+               return NULL;
+       }
+       for (i = 1; i < count_coords; ++i)
+               tsfg->samples[i] = tsfg->samples[0] + i * tsfg->config->extent;
+       tsfg->sorted_samples = tsfg->samples[0] + count_coords *
+                              tsfg->config->extent;
+       tsfg->group_size = tsfg->samples[0] + (1 + count_coords) *
+                              tsfg->config->extent;
+
+       ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
+
+       printk(KERN_INFO"  Created group ts filter len %d depth %d close %d "
+                       "thresh %d\n", tsfg->config->extent, count_coords,
+                       tsfg->config->close_enough, tsfg->config->threshold);
+
+       return &tsfg->tsf;
+}
+
+static void ts_filter_group_destroy(struct ts_filter *tsf)
+{
+       struct ts_filter_group *tsfg = (struct ts_filter_group *)tsf;
+
+       kfree(tsfg->samples[0]); /* first guy has pointer from kmalloc */
+       kfree(tsf);
+}
+
+static void ts_filter_group_scale(struct ts_filter *tsf, int *coords)
+{
+       if (tsf->next)
+               (tsf->next->api->scale)(tsf->next, coords);
+}
+
+static int int_cmp(const void *_a, const void *_b)
+{
+       const int *a = _a;
+       const int *b = _b;
+
+       if (*a > *b)
+               return 1;
+       if (*a < *b)
+               return -1;
+       return 0;
+}
+
+static int ts_filter_group_process(struct ts_filter *tsf, int *coords)
+{
+       struct ts_filter_group *tsfg = (struct ts_filter_group *)tsf;
+       int n;
+       int i;
+       int ret = 0; /* ask for more samples by default */
+
+       BUG_ON(tsfg->N >= tsfg->config->extent);
+
+       for (n = 0; n < tsf->count_coords; n++)
+               tsfg->samples[n][tsfg->N] = coords[n];
+
+       if (++tsfg->N < tsfg->config->extent)
+               return 0;       /* we meed more samples */
+
+       for (n = 0; n < tsfg->tsf.count_coords; n++) {
+               int *v = tsfg->sorted_samples;
+               int ngroups = 0;
+               int best_size;
+               int best_idx = 0;
+               int idx = 0;
+
+               memcpy(v, tsfg->samples[n], tsfg->N * sizeof(int));
+               sort(v, tsfg->N, sizeof(int), int_cmp, NULL);
+
+               tsfg->group_size[0] = 1;
+               for (i = 1; i < tsfg->N; ++i) {
+                       if (v[i] - v[i - 1] <= tsfg->config->close_enough)
+                               tsfg->group_size[ngroups]++;
+                       else
+                               tsfg->group_size[++ngroups] = 1;
+               }
+               ngroups++;
+
+               best_size = tsfg->group_size[0];
+               for (i = 1; i < ngroups; i++) {
+                       idx += tsfg->group_size[i - 1];
+                       if (best_size < tsfg->group_size[i]) {
+                               best_size = tsfg->group_size[i];
+                               best_idx = idx;
+                       }
+               }
+
+               if (best_size < tsfg->config->threshold) {
+                       /* this set is not good enough for us */
+                       if (--tsfg->tries_left) {
+                               ts_filter_group_clear_internal
+                                       (tsfg, tsfg->tries_left);
+                               return 0; /* ask for more samples */
+                       }
+                       return -1; /* we give up */
+               }
+
+               tsfg->range_min[n] = v[best_idx];
+               tsfg->range_max[n] = v[best_idx + best_size - 1];
+       }
+
+       BUG_ON(!tsf->next);
+
+       for (i = 0; i < tsfg->N; ++i) {
+               int r;
+
+               for (n = 0; n < tsfg->tsf.count_coords; ++n) {
+                       coords[n] = tsfg->samples[n][i];
+                       if (coords[n] < tsfg->range_min[n] ||
+                           coords[n] > tsfg->range_max[n])
+                               break;
+               }
+
+               if (n != tsfg->tsf.count_coords) /* sample not OK */
+                       continue;
+
+               r = (tsf->next->api->process)(tsf->next, coords);
+               if (r)  {
+                       ret = r;
+                       break;
+               }
+       }
+
+       ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
+
+       return ret;
+}
+
+struct ts_filter_api ts_filter_group_api = {
+       .create = ts_filter_group_create,
+       .destroy = ts_filter_group_destroy,
+       .clear = ts_filter_group_clear,
+       .process = ts_filter_group_process,
+       .scale = ts_filter_group_scale,
+};
+
diff --git a/drivers/input/touchscreen/ts_filter_variance.c 
b/drivers/input/touchscreen/ts_filter_variance.c
deleted file mode 100644
index c335210..0000000
--- a/drivers/input/touchscreen/ts_filter_variance.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Copyright (C) 2008 by Openmoko, Inc.
- * Author: Nelson Castillo <[EMAIL PROTECTED]>
- * All rights reserved.
- *
- * This filter is useful to reject clicks that are not reliable. We
- * only care about what happens when we receive DOWN events for the fist time.
- * If this filter does not reject the first samples then it will change
- * its internal state to "passed" and the remaining samples
- * will be passed to the next filter in the chain.
- *
- * First we collect N samples, then then we sort them. We discard the borders
- * (with a window) and then compute the variance of the remaining set.
- * If the computed variance is bigger than a threshold, we reject the click.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sort.h>
-#include <linux/ts_filter_variance.h>
-
-static void ts_filter_variance_clear_internal(struct ts_filter_variance *tsfv,
-                                             int attempts)
-{
-       tsfv->N = 0;
-       tsfv->passed = 0;
-       tsfv->tries_left = attempts;
-}
-
-static void ts_filter_variance_clear(struct ts_filter *tsf)
-{
-       struct ts_filter_variance *tsfv = (struct ts_filter_variance *)tsf;
-
-       ts_filter_variance_clear_internal(tsfv, tsfv->config->attempts);
-
-       if (tsf->next) /* chain */
-               (tsf->next->api->clear)(tsf->next);
-}
-
-static struct ts_filter *ts_filter_variance_create(void *conf, int 
count_coords)
-{
-       struct ts_filter_variance *tsfv;
-       int i;
-
-       BUG_ON((count_coords < 1) || (count_coords > MAX_TS_FILTER_COORDS));
-
-       tsfv = kzalloc(sizeof(struct ts_filter_variance), GFP_KERNEL);
-       if (!tsfv)
-               return NULL;
-
-       tsfv->config = (struct ts_filter_variance_configuration *)conf;
-       tsfv->tsf.count_coords = count_coords;
-
-       BUG_ON(tsfv->config->attempts <= 0);
-
-       tsfv->samples[0] = kmalloc(count_coords * sizeof(int) *
-                                  tsfv->config->extent, GFP_KERNEL);
-       if (!tsfv->samples[0]) {
-               kfree(tsfv);
-               return NULL;
-       }
-       for (i = 1; i < count_coords; ++i)
-               tsfv->samples[i] = tsfv->samples[0] + i * tsfv->config->extent;
-
-       ts_filter_variance_clear_internal(tsfv, tsfv->config->attempts);
-
-       printk(KERN_INFO"  Created Variance ts filter len %d depth %d window"
-                       " %d thresh %d\n", tsfv->config->extent,
-                       count_coords, tsfv->config->window,
-                       tsfv->config->threshold);
-
-       /* scale the threshold to avoid divisions later */
-       tsfv->config->threshold *= tsfv->config->extent -
-                                  (tsfv->config->window << 1);
-
-       return &tsfv->tsf;
-}
-
-static void ts_filter_variance_destroy(struct ts_filter *tsf)
-{
-       struct ts_filter_variance *tsfv = (struct ts_filter_variance *)tsf;
-
-       kfree(tsfv->samples[0]); /* first guy has pointer from kmalloc */
-       kfree(tsf);
-}
-
-static void ts_filter_variance_scale(struct ts_filter *tsf, int *coords)
-{
-       struct ts_filter_variance *tsfv = (struct ts_filter_variance *)tsf;
-
-       if (!tsfv->passed)
-               return;
-
-       if (tsf->next) {
-               (tsf->next->api->scale)(tsf->next, coords);
-       } else {
-               int n;
-               for (n = 0; n < tsf->count_coords; n++) {
-                       int c = tsfv->samples[n][tsfv->N / 2] +
-                               tsfv->samples[n][tsfv->N / 2 + 1] +
-                               tsfv->samples[n][tsfv->N / 2 - 1];
-                       coords[n] = (c + 2) / 3;
-               }
-       }
-}
-
-static int int_cmp(const void *_a, const void *_b)
-{
-       const int *a = _a;
-       const int *b = _b;
-
-       if (*a > *b)
-               return 1;
-       if (*a < *b)
-               return -1;
-       return 0;
-}
-
-/* give us the raw sample data coords, and if we return 1 then you can
- * get a filtered coordinate from coords: if we return 0 you didn't
- * fill all the filters with samples yet.
- */
-
-static int ts_filter_variance_process(struct ts_filter *tsf, int *coords)
-{
-       struct ts_filter_variance *tsfv = (struct ts_filter_variance *)tsf;
-       int n;
-
-       if (tsfv->passed) { /* chain */
-               if (tsf->next)
-                       return (tsf->next->api->process)(tsf->next, coords);
-               return 1;
-       }
-
-       for (n = 0; n < tsf->count_coords; n++)
-               tsfv->samples[n][tsfv->N] = coords[n];
-
-       if (++tsfv->N < tsfv->config->extent)
-               return 0;       /* we meed more samples */
-
-       tsfv->passed = 1;
-
-       for (n = 0; n < tsfv->tsf.count_coords; n++) {
-               int i;
-               int avg = 0;
-               int variance = 0;
-
-               sort(tsfv->samples[n], tsfv->config->extent, sizeof(int),
-                    int_cmp, NULL);
-
-               for (i = tsfv->config->window; i < tsfv->config->extent -
-                                              tsfv->config->window; ++i)
-                       avg += tsfv->samples[n][i];
-
-               avg /= tsfv->config->extent - (tsfv->config->window << 1);
-
-               for (i = tsfv->config->window; i < tsfv->config->extent -
-                                                  tsfv->config->window; ++i) {
-                       int s = tsfv->samples[n][i] - avg;
-                       variance += s * s;
-               }
-
-               if (variance > tsfv->config->threshold) {
-                       tsfv->passed = 0;
-                       break;
-               }
-       }
-
-       if (tsfv->passed) /* Let's reuse the last sample */
-               return ts_filter_variance_process(tsf, coords);
-
-       if (--tsfv->tries_left) {
-               ts_filter_variance_clear_internal(tsfv, tsfv->tries_left);
-               return 0; /* ask for more samples */
-       }
-
-       /* avoid overflow if we are called again without clearing the filter */
-       ts_filter_variance_clear_internal(tsfv, tsfv->config->attempts);
-
-       return -1;
-}
-
-struct ts_filter_api ts_filter_variance_api = {
-       .create = ts_filter_variance_create,
-       .destroy = ts_filter_variance_destroy,
-       .clear = ts_filter_variance_clear,
-       .process = ts_filter_variance_process,
-       .scale = ts_filter_variance_scale,
-};
-
diff --git a/include/linux/ts_filter.h b/include/linux/ts_filter.h
index 7262bba..bfb8a22 100644
--- a/include/linux/ts_filter.h
+++ b/include/linux/ts_filter.h
@@ -4,14 +4,11 @@
 /*
  * touchscreen filter
  *
- * median
- *
  * (c) 2008 Andy Green <[EMAIL PROTECTED]>
  */
 
-/* max filters you can chain up */
-#define MAX_TS_FILTER_CHAIN 4
-#define MAX_TS_FILTER_COORDS 6
+#define MAX_TS_FILTER_CHAIN            4  /* max filters you can chain up */
+#define MAX_TS_FILTER_COORDS           3  /* Y, Y and Z (pressure) */
 
 struct ts_filter;
 
diff --git a/include/linux/ts_filter_group.h b/include/linux/ts_filter_group.h
new file mode 100644
index 0000000..1e74c8d
--- /dev/null
+++ b/include/linux/ts_filter_group.h
@@ -0,0 +1,39 @@
+#ifndef __TS_FILTER_GROUP_H__
+#define __TS_FILTER_GROUP_H__
+
+#include <linux/ts_filter.h>
+
+/*
+ * Touchscreen group filter.
+ *
+ * Copyright (C) 2008 by Openmoko, Inc.
+ * Author: Nelson Castillo <[EMAIL PROTECTED]>
+ *
+ */
+
+struct ts_filter_group_configuration {
+       int extent;
+       int close_enough;
+       int threshold;
+       int attempts;
+};
+
+struct ts_filter_group {
+       struct ts_filter tsf;
+       struct ts_filter_group_configuration *config;
+
+       int N;          /* How many samples we have */
+       int *samples[MAX_TS_FILTER_COORDS];     /* the samples, our input */
+
+       int *group_size;        /* used for temporal computations */
+       int *sorted_samples;    /* used for temporal computations */
+
+       int range_max[MAX_TS_FILTER_COORDS];    /* max computed ranges */
+       int range_min[MAX_TS_FILTER_COORDS];    /* min computed ranges */
+
+       int tries_left;         /* We finish if we don't get enough samples */
+};
+
+extern struct ts_filter_api ts_filter_group_api;
+
+#endif
diff --git a/include/linux/ts_filter_variance.h 
b/include/linux/ts_filter_variance.h
deleted file mode 100644
index 574cf90..0000000
--- a/include/linux/ts_filter_variance.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __TS_FILTER_VARIANCE_H__
-#define __TS_FILTER_VARIANCE_H__
-
-#include <linux/ts_filter.h>
-
-/*
- * touchscreen filter
- *
- * Variance
- *
- * Copyright (C) 2008 by Openmoko, Inc.
- * Author: Nelson Castillo <[EMAIL PROTECTED]>
- *
- */
-
-struct ts_filter_variance_configuration {
-       int extent;
-       int window;
-       int threshold;
-       int attempts;
-};
-
-struct ts_filter_variance {
-       struct ts_filter tsf;
-       struct ts_filter_variance_configuration *config;
-
-       int *samples[2];
-       int N;                  /* How many samples we have */
-
-       int tries_left;         /* How many times we can try to get a point */
-       int passed;             /* Did the samples pass the test? */
-};
-
-extern struct ts_filter_api ts_filter_variance_api;
-
-#endif


Reply via email to