diff options
author | merge <null@invalid> | 2008-12-08 11:03:03 +0000 |
---|---|---|
committer | Andy Green <agreen@pads.home.warmcat.com> | 2008-12-08 11:03:03 +0000 |
commit | c3be736aeb24f44cf95dfad8fe3f1c7c6f367aaf (patch) | |
tree | 1ba8dbf5784f805847652d896d9ee98ceffae22b /drivers/input | |
parent | 2eb3742db1ecd3d9ffe8f02eaa8def1b2bd2a2c2 (diff) |
MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-remove-skip-filter-1228733704
pending-tracking-hist top was MERGE-via-stable-tracking-remove-skip-filter-1228733704 / 552c6fdd4c644ab2618ad27564d159ed28bbd859 ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-stable-tracking-hist-remove-skip-filter
stable-tracking-hist top was remove-skip-filter / 92bdef8636873a19efc05b2a19578a0aa93dba41 ... parent commitmessage:
From: Nelson Castillo <nelsoneci@gmail.com>
Remove skip filter
With more reliable points median and mean filters perform a better job.
We no longer need this filter.
Signed-off-by: Nelson Castillo <nelsoneci@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 8 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/s3c2410_ts.c | 119 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_group.c | 217 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_variance.c | 205 |
5 files changed, 233 insertions, 318 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 98566fd3342..a0f8599a5b2 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 ee6bd283668..9a6162cecc5 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/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index ea0f58aaf32..8e6bc0a0371 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -19,7 +19,7 @@ * ChangeLog * * 2004-09-05: Herbert Pƶtzl <herbert@13thfloor.at> - * - added clock (de-)allocation code + * - added clock (de-)allocation code * * 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org> * - h1940_ -> s3c2410 (this driver is now also used on the n30 @@ -35,11 +35,14 @@ * controller * * 2007-05-23: Harald Welte <laforge@openmoko.org> - * - Add proper support for S32440 + * - Add proper support for S32440 * * 2008-06-23: Andy Green <andy@openmoko.com> * - removed averaging system * - added generic Touchscreen filter stuff + * + * 2008-11-27: Nelson Castillo <arhuaco@freaks-unidos.net> + * - improve interrupt handling */ #include <linux/errno.h> @@ -97,13 +100,9 @@ static char *s3c2410ts_name = "s3c2410 TouchScreen"; #define TS_EVENT_FIFO_SIZE (2 << 6) /* must be a power of 2 */ #define TS_STATE_STANDBY 0 /* initial state */ -#define TS_STATE_PRESSED_PENDING 1 -#define TS_STATE_PRESSED 2 -#define TS_STATE_RELEASE_PENDING 3 -#define TS_STATE_RELEASE 4 - -#define SKIP_NHEAD 2 -#define SKIP_NTAIL 1 +#define TS_STATE_PRESSED 1 +#define TS_STATE_RELEASE_PENDING 2 +#define TS_STATE_RELEASE 3 /* * Per-touchscreen data. @@ -180,92 +179,8 @@ static void ts_input_report(int event, int coords[]) input_sync(ts.dev); } - -/* - * 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. + * Manage the state of the touchscreen. */ static void event_send_timer_f(unsigned long data); @@ -294,9 +209,6 @@ static void event_send_timer_f(unsigned long data) if (ts.state == TS_STATE_RELEASE_PENDING) /* Ignore short UP event */ ts.state = TS_STATE_PRESSED; - else - /* Defer PRESSED until we get a valid point */ - ts.state = TS_STATE_PRESSED_PENDING; break; case 'U': @@ -313,9 +225,8 @@ static void event_send_timer_f(unsigned long data) != sizeof(int) * 2)) goto ts_exit_error; - ts_skip_filter(IE_DOWN, buf); + ts_input_report(IE_DOWN, buf); ts.state = TS_STATE_PRESSED; - break; default: @@ -332,7 +243,7 @@ static void event_send_timer_f(unsigned long data) * while to avoid jitter. If we get a DOWN * event we do not send it. */ - ts_skip_filter(IE_UP, NULL); + ts_input_report(IE_UP, NULL); ts.state = TS_STATE_STANDBY; if (ts.tsf[0]) @@ -517,8 +428,6 @@ 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, @@ -710,9 +619,3 @@ static void __exit s3c2410ts_exit(void) module_init(s3c2410ts_init); module_exit(s3c2410ts_exit); -/* - Local variables: - compile-command: "make ARCH=arm CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux- -k -C ../../.." - c-basic-offset: 8 - End: -*/ diff --git a/drivers/input/touchscreen/ts_filter_group.c b/drivers/input/touchscreen/ts_filter_group.c new file mode 100644 index 00000000000..250613f9345 --- /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 <arhuaco@freaks-unidos.net> + * 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 c3352105c9f..00000000000 --- 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 <arhuaco@freaks-unidos.net> - * 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, -}; - |