diff options
Diffstat (limited to 'drivers/input/touchscreen/ts_filter_mean.c')
-rw-r--r-- | drivers/input/touchscreen/ts_filter_mean.c | 209 |
1 files changed, 102 insertions, 107 deletions
diff --git a/drivers/input/touchscreen/ts_filter_mean.c b/drivers/input/touchscreen/ts_filter_mean.c index e4e0f2ac68e..c61a5c1c3a0 100644 --- a/drivers/input/touchscreen/ts_filter_mean.c +++ b/drivers/input/touchscreen/ts_filter_mean.c @@ -13,162 +13,157 @@ * 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 Andy Green <andy@openmoko.com> + * Copyright (c) 2008,2009 + * Andy Green <andy@openmoko.com> + * Nelson Castillo <arhuaco@freaks-unidos.net> * + * Simple mean filter. * - * Mean has no effect if the samples are changing by more that the - * threshold set by averaging_threshold in the configuration. - * - * However while samples come in that don't go outside this threshold from - * the last reported sample, Mean replaces the samples with a simple mean - * of a configurable number of samples (set by bits_filter_length in config, - * which is 2^n, so 5 there makes 32 sample averaging). - * - * Mean works well if the input data is already good quality, reducing + / - 1 - * sample jitter when the stylus is still, or moving very slowly, without - * introducing abrupt transitions or reducing ability to follow larger - * movements. If you set the threshold higher than the dynamic range of the - * coordinates, you can just use it as a simple mean average. */ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/slab.h> + #include "ts_filter_mean.h" -static void ts_filter_mean_clear_internal(struct ts_filter *tsf) -{ - struct ts_filter_mean *tsfs = (struct ts_filter_mean *)tsf; - int n; +struct ts_filter_mean { + /* Copy of the private filter configuration. */ + struct ts_filter_mean_configuration *config; + /* Filter API. */ + struct ts_filter tsf; + + /* Index on a circular buffer. */ + int curr; + /* Useful to tell if the circular buffer is full(read:ready). */ + int count; + /* Sumation used to compute the mean. */ + int sum[MAX_TS_FILTER_COORDS]; + /* Keep point values and decrement them from the sum on time. */ + int *fifo[MAX_TS_FILTER_COORDS]; + /* Store the output of this filter. */ + int ready; +}; - for (n = 0; n < tsfs->tsf.count_coords; n++) { - tsfs->fhead[n] = 0; - tsfs->ftail[n] = 0; - tsfs->lowpass[n] = 0; - } -} +#define ts_filter_to_filter_mean(f) container_of(f, struct ts_filter_mean, tsf) -static void ts_filter_mean_clear(struct ts_filter *tsf) -{ - ts_filter_mean_clear_internal(tsf); - if (tsf->next) /* chain */ - (tsf->next->api->clear)(tsf->next); -} +static void ts_filter_mean_clear(struct ts_filter *tsf); static struct ts_filter *ts_filter_mean_create(struct platform_device *pdev, void *config, int count_coords) { - int *p; + struct ts_filter_mean *priv; + int *v; int n; - struct ts_filter_mean *tsfs = kzalloc( - sizeof(struct ts_filter_mean), GFP_KERNEL); - if (!tsfs) + priv = kzalloc(sizeof(struct ts_filter_mean), GFP_KERNEL); + if (!priv) return NULL; - BUG_ON((count_coords < 1) || (count_coords > MAX_TS_FILTER_COORDS)); - tsfs->tsf.count_coords = count_coords; + priv->tsf.count_coords = count_coords; + priv->config = (struct ts_filter_mean_configuration *)config; - tsfs->config = (struct ts_filter_mean_configuration *)config; + BUG_ON(priv->config->length <= 0); - tsfs->config->extent = 1 << tsfs->config->bits_filter_length; - BUG_ON((tsfs->config->extent > 256) || (!tsfs->config->extent)); - - p = kmalloc(tsfs->config->extent * sizeof(int) * count_coords, - GFP_KERNEL); - if (!p) + v = kmalloc(priv->config->length * sizeof(int) * count_coords, + GFP_KERNEL); + if (!v) return NULL; for (n = 0; n < count_coords; n++) { - tsfs->fifo[n] = p; - p += tsfs->config->extent; + priv->fifo[n] = v; + v += priv->config->length; } - if (!tsfs->config->averaging_threshold) - tsfs->config->averaging_threshold = 0xffff; /* always active */ - - ts_filter_mean_clear_internal(&tsfs->tsf); + ts_filter_mean_clear(&priv->tsf); - printk(KERN_INFO" Created Mean ts filter len %d depth %d thresh %d\n", - tsfs->config->extent, count_coords, - tsfs->config->averaging_threshold); + dev_info(&pdev->dev, "Created Mean filter len:%d coords:%d\n", + priv->config->length, count_coords); - return &tsfs->tsf; + return &priv->tsf; } -static void ts_filter_mean_destroy(struct platform_device *pdev, - struct ts_filter *tsf) +static void ts_filter_mean_destroy(struct ts_filter *tsf) { - struct ts_filter_mean *tsfs = (struct ts_filter_mean *)tsf; + struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf); - kfree(tsfs->fifo[0]); /* first guy has pointer from kmalloc */ + kfree(priv->fifo[0]); /* first guy has pointer from kmalloc */ kfree(tsf); } -static void ts_filter_mean_scale(struct ts_filter *tsf, int *coords) +static void ts_filter_mean_clear(struct ts_filter *tsf) { - if (tsf->next) /* chain */ - (tsf->next->api->scale)(tsf->next, coords); -} + struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf); -/* - * Give us the raw sample data in x and y, and if we return 1 then you can - * get a filtered coordinate from tsm->x and tsm->y. If we return 0 you didn't - * fill the filter with samples yet. - */ + priv->count = 0; + priv->curr = 0; + priv->ready = 0; + memset(priv->sum, 0, tsf->count_coords * sizeof(int)); +} static int ts_filter_mean_process(struct ts_filter *tsf, int *coords) { - struct ts_filter_mean *tsfs = (struct ts_filter_mean *)tsf; + struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf); int n; - int len; + + BUG_ON(priv->ready); for (n = 0; n < tsf->count_coords; n++) { + priv->sum[n] += coords[n]; + priv->fifo[n][priv->curr] = coords[n]; + } - /* - * Has he moved far enough away that we should abandon current - * low pass filtering state? - */ - if ((coords[n] < (tsfs->reported[n] - - tsfs->config->averaging_threshold)) || - (coords[n] > (tsfs->reported[n] + - tsfs->config->averaging_threshold))) { - tsfs->fhead[n] = 0; - tsfs->ftail[n] = 0; - tsfs->lowpass[n] = 0; - } - - /* capture this sample into fifo and sum */ - tsfs->fifo[n][tsfs->fhead[n]++] = coords[n]; - if (tsfs->fhead[n] == tsfs->config->extent) - tsfs->fhead[n] = 0; - tsfs->lowpass[n] += coords[n]; - - /* adjust the sum into an average and use that*/ - len = (tsfs->fhead[n] - tsfs->ftail[n]) & - (tsfs->config->extent - 1); - coords[n] = (tsfs->lowpass[n] + (len >> 1)) / len; - tsfs->reported[n] = coords[n]; - - /* remove oldest sample if we are full */ - if (len == (tsfs->config->extent - 1)) { - tsfs->lowpass[n] -= tsfs->fifo[n][tsfs->ftail[n]++]; - if (tsfs->ftail[n] == tsfs->config->extent) - tsfs->ftail[n] = 0; - } + if (priv->count + 1 == priv->config->length) + priv->ready = 1; + else + priv->count++; + + priv->curr = (priv->curr + 1) % priv->config->length; + + return 0; /* no error */ +} + +static int ts_filter_mean_haspoint(struct ts_filter *tsf) +{ + struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf); + + return priv->ready; +} + +static void ts_filter_mean_getpoint(struct ts_filter *tsf, int *point) +{ + struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf); + int n; + + BUG_ON(!priv->ready); + + for (n = 0; n < tsf->count_coords; n++) { + point[n] = priv->sum[n]; + priv->sum[n] -= priv->fifo[n][priv->curr]; } - if (tsf->next) /* chain */ - return (tsf->next->api->process)(tsf->next, coords); + priv->ready = 0; +} + +static void ts_filter_mean_scale(struct ts_filter *tsf, int *coords) +{ + int n; + struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf); - return 1; + for (n = 0; n < tsf->count_coords; n++) { + coords[n] += priv->config->length >> 1; /* rounding */ + coords[n] /= priv->config->length; + } } struct ts_filter_api ts_filter_mean_api = { - .create = ts_filter_mean_create, - .destroy = ts_filter_mean_destroy, - .clear = ts_filter_mean_clear, - .process = ts_filter_mean_process, - .scale = ts_filter_mean_scale, + .create = ts_filter_mean_create, + .destroy = ts_filter_mean_destroy, + .clear = ts_filter_mean_clear, + .process = ts_filter_mean_process, + .scale = ts_filter_mean_scale, + .haspoint = ts_filter_mean_haspoint, + .getpoint = ts_filter_mean_getpoint, }; + |