diff options
-rw-r--r-- | arch/arm/mach-s3c2442/mach-gta02.c | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/s3c2410_ts.c | 95 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter.c | 150 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter.h | 81 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_group.c | 166 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_group.h | 16 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_linear.c | 87 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_linear.h | 38 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_mean.c | 209 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_mean.h | 25 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_median.c | 159 | ||||
-rw-r--r-- | drivers/input/touchscreen/ts_filter_median.h | 13 |
12 files changed, 603 insertions, 438 deletions
diff --git a/arch/arm/mach-s3c2442/mach-gta02.c b/arch/arm/mach-s3c2442/mach-gta02.c index e5fb9dbcf9e..5745195db05 100644 --- a/arch/arm/mach-s3c2442/mach-gta02.c +++ b/arch/arm/mach-s3c2442/mach-gta02.c @@ -972,7 +972,7 @@ static struct ts_filter_median_configuration gta02_ts_median_config = { }; static struct ts_filter_mean_configuration gta02_ts_mean_config = { - .bits_filter_length = 2, /* 4 points */ + .length = 4, }; static struct s3c2410_ts_mach_info gta02_ts_cfg = { diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 7d5b3debbb3..d63d4eab605 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -98,6 +98,7 @@ static char *s3c2410ts_name = "s3c2410 TouchScreen"; #define TS_RELEASE_TIMEOUT (HZ >> 7 ? HZ >> 7 : 1) /* 8ms (5ms if HZ is 200) */ #define TS_EVENT_FIFO_SIZE (2 << 6) /* must be a power of 2 */ +#define TS_COORDINATES_SIZE 2 /* just X and Y for us */ #define TS_STATE_STANDBY 0 /* initial state */ #define TS_STATE_PRESSED 1 @@ -110,8 +111,7 @@ static char *s3c2410ts_name = "s3c2410 TouchScreen"; struct s3c2410ts { struct input_dev *dev; - struct ts_filter *tsf[MAX_TS_FILTER_CHAIN]; - int coords[2]; /* just X and Y for us */ + struct ts_filter **tsf; int is_down; int state; struct kfifo *event_fifo; @@ -232,15 +232,14 @@ static void event_send_timer_f(unsigned long data) if (noop_counter++ >= 1) { noop_counter = 0; if (ts.state == TS_STATE_RELEASE_PENDING) { - /* We delay the UP event for a - * while to avoid jitter. If we get a DOWN - * event we do not send it. */ - + /* + * We delay the UP event for a while to avoid jitter. + * If we get a DOWN event we do not send it. + */ ts_input_report(IE_UP, NULL); ts.state = TS_STATE_STANDBY; - if (ts.tsf[0]) - (ts.tsf[0]->api->clear)(ts.tsf[0]); + ts_filter_chain_clear(ts.tsf); } } else { mod_timer(&event_send_timer, jiffies + TS_RELEASE_TIMEOUT); @@ -288,42 +287,29 @@ static irqreturn_t stylus_action(int irq, void *dev_id) { int buf[3]; - /* grab the ADC results */ - ts.coords[0] = readl(base_addr + S3C2410_ADCDAT0) & - S3C2410_ADCDAT0_XPDATA_MASK; - ts.coords[1] = readl(base_addr + S3C2410_ADCDAT1) & - S3C2410_ADCDAT1_YPDATA_MASK; - - if (ts.tsf[0]) { /* filtering is enabled, don't use raw directly */ - switch ((ts.tsf[0]->api->process)(ts.tsf[0], &ts.coords[0])) { - case 0: /* - * no real sample came out of processing yet, - * get another raw result to feed it - */ - s3c2410_ts_start_adc_conversion(); - return IRQ_HANDLED; - case 1: /* filters are ready to deliver a sample */ - (ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]); - break; - case -1: - /* error in filters, ignore the event */ - (ts.tsf[0]->api->clear)(ts.tsf[0]); - writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC); - return IRQ_HANDLED; - default: - printk(KERN_ERR":stylus_action error\n"); - } - } + /* Grab the ADC results. */ + buf[1] = readl(base_addr + S3C2410_ADCDAT0) & + S3C2410_ADCDAT0_XPDATA_MASK; + buf[2] = readl(base_addr + S3C2410_ADCDAT1) & + S3C2410_ADCDAT1_YPDATA_MASK; - /* We use a buffer because want an atomic operation */ - buf[0] = 'P'; - buf[1] = ts.coords[0]; - buf[2] = ts.coords[1]; + switch (ts_filter_chain_feed(ts.tsf, &buf[1])) { + case 0: + s3c2410_ts_start_adc_conversion(); + return IRQ_HANDLED; + case -1: + /* Error. Ignore the event. */ + ts_filter_chain_clear(ts.tsf); + writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC); + return IRQ_HANDLED; + default: + /* We have a point from the filters or no filtering enabled. */ + buf[0] = 'P'; + }; if (unlikely(__kfifo_put(ts.event_fifo, (unsigned char *)buf, sizeof(int) * 3) != sizeof(int) * 3)) - /* should not happen */ - printk(KERN_ERR":stylus_action error\n"); + printk(KERN_ERR":stylus_action error\n"); /* happens => bug */ writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC); mod_timer(&event_send_timer, jiffies + 1); @@ -425,18 +411,14 @@ static int __init s3c2410ts_probe(struct platform_device *pdev) } /* create the filter chain set up for the 2 coordinates we produce */ - ret = ts_filter_create_chain( - pdev, (struct ts_filter_api **)&info->filter_sequence, - (void *)&info->filter_config, ts.tsf, ARRAY_SIZE(ts.coords)); - if (ret) - dev_info(&pdev->dev, "%d filter(s) initialized\n", ret); - else /* this is OK, just means there won't be any filtering */ - dev_info(&pdev->dev, "Unfiltered output selected\n"); - - if (ts.tsf[0]) - (ts.tsf[0]->api->clear)(ts.tsf[0]); - else - dev_info(&pdev->dev, "No filtering\n"); + ts.tsf = ts_filter_chain_create( + pdev, (struct ts_filter_api **)&info->filter_sequence, + (void *)&info->filter_config, TS_COORDINATES_SIZE); + + if (!ts.tsf) + goto bail2; + + ts_filter_chain_clear(ts.tsf); /* Get irqs */ if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM, @@ -455,7 +437,7 @@ static int __init s3c2410ts_probe(struct platform_device *pdev) goto bail4; } - dev_info(&pdev->dev, "successfully loaded\n"); + dev_info(&pdev->dev, "Successfully loaded\n"); /* All went ok, so register to the input system */ rc = input_register_device(ts.dev); @@ -475,7 +457,7 @@ bail5: bail4: disable_irq(IRQ_ADC); bail3: - ts_filter_destroy_chain(pdev, ts.tsf); + ts_filter_chain_destroy(ts.tsf); kfifo_free(ts.event_fifo); bail2: input_unregister_device(ts.dev); @@ -502,7 +484,7 @@ static int s3c2410ts_remove(struct platform_device *pdev) input_unregister_device(ts.dev); iounmap(base_addr); - ts_filter_destroy_chain(pdev, ts.tsf); + ts_filter_chain_destroy(ts.tsf); kfifo_free(ts.event_fifo); @@ -532,8 +514,7 @@ static int s3c2410ts_resume(struct platform_device *pdev) clk_enable(adc_clock); mdelay(1); - if (ts.tsf[0]) - (ts.tsf[0]->api->clear)(ts.tsf[0]); + ts_filter_chain_clear(ts.tsf); enable_irq(IRQ_ADC); enable_irq(IRQ_TC); diff --git a/drivers/input/touchscreen/ts_filter.c b/drivers/input/touchscreen/ts_filter.c index 832844da55f..817fff23154 100644 --- a/drivers/input/touchscreen/ts_filter.c +++ b/drivers/input/touchscreen/ts_filter.c @@ -13,61 +13,151 @@ * 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> */ #include <linux/kernel.h> #include <linux/device.h> #include "ts_filter.h" -static DEFINE_MUTEX(chain_mutex); +/* + * Tux, would you like the following function in /lib? + * It helps us avoid silly code. + */ + +/** + * sptrlen - Count how many non-null pointers are in a pointer array + * @arr: The array of pointers + */ +static int sptrlen(void *arr) +{ + int **p = arr; /* all pointers have the same size */ + int len = 0; -int ts_filter_create_chain(struct platform_device *pdev, - struct ts_filter_api **api, void **config, - struct ts_filter **arr, int count_coords) + while (*(p++)) + len++; + + return len; +} + +static struct ts_filter **revchain; /* FIXME: rename this temporal hack. */ + +struct ts_filter **ts_filter_chain_create(struct platform_device *pdev, + struct ts_filter_api **api, + void **config, + int count_coords) { + struct ts_filter **arr; int count = 0; - struct ts_filter *last = NULL; + int len; + int nrev = 0; - if (!api) - return 0; + BUG_ON((count_coords < 1)); + BUG_ON(count_coords > MAX_TS_FILTER_COORDS); - mutex_lock(&chain_mutex); + len = (sptrlen(api) + 1); + /* memory for two null-terminated arrays of filters */ + arr = kzalloc(2 * sizeof(struct ts_filter *) * len, GFP_KERNEL); + if (!arr) + goto create_err; + revchain = arr + len; while (*api) { - *arr = ((*api)->create)(pdev, *config++, count_coords); - if (!*arr) { - printk(KERN_ERR "Filter %d failed init\n", count); - return count; + /* TODO: Can get away with only sending pdev->dev? */ + /* FIXME: Avoid config (void**) */ + struct ts_filter *f = ((*api)->create)(pdev, *config++, + count_coords); + if (!f) { + dev_info(&pdev->dev, "Filter %d failed init\n", count); + goto create_err; } - (*arr)->api = *api++; - if (last) - last->next = *arr; - last = *arr; - arr++; - count++; + f->api = *(api++); + arr[count++] = f; + + /* Filters that can propagate values in the chain. */ + if (f->api->haspoint && f->api->getpoint && f->api->process) + revchain[nrev++] = f; } - mutex_unlock(&chain_mutex); + dev_info(&pdev->dev, "%d filter(s) initialized\n", count); + + return arr; + +create_err: + + dev_info(&pdev->dev, "Error in filter chain initialization\n"); - return count; + ts_filter_chain_destroy(arr); + + return NULL; } -EXPORT_SYMBOL_GPL(ts_filter_create_chain); +EXPORT_SYMBOL_GPL(ts_filter_chain_create); -void ts_filter_destroy_chain(struct platform_device *pdev, - struct ts_filter **arr) +void ts_filter_chain_destroy(struct ts_filter **arr) { - struct ts_filter **first = arr; + struct ts_filter **a = arr; + int count = 0; - mutex_lock(&chain_mutex); + while (arr && *a) { + ((*a)->api->destroy)(*a); + a++; + count++; + } + kfree(arr); +} +EXPORT_SYMBOL_GPL(ts_filter_chain_destroy); + +void ts_filter_chain_clear(struct ts_filter **arr) +{ while (*arr) { - ((*arr)->api->destroy)(pdev, *arr); + if ((*arr)->api->clear) + ((*arr)->api->clear)(*arr); arr++; } - *first = NULL; +} +EXPORT_SYMBOL_GPL(ts_filter_chain_clear); + +static void ts_filter_chain_scale(struct ts_filter **a, int *coords) +{ + while (*a) { + if ((*a)->api->scale) + ((*a)->api->scale)(*a, coords); + a++; + } +} + +int ts_filter_chain_feed(struct ts_filter **arr, int *coords) +{ + /* FIXME: only using revchain */ + int len = sptrlen(revchain); /* FIXME: save this */ + int i = len - 1; + + if (!arr[0]) + return 1; /* Nothing to do. Filtering disabled. */ + + BUG_ON(arr[0]->api->haspoint(arr[0])); + + if (arr[0]->api->process(arr[0], coords)) + return -1; + + while (i >= 0 && i < len) { + if (revchain[i]->api->haspoint(revchain[i])) { + revchain[i]->api->getpoint(revchain[i], coords); + if (++i < len && + revchain[i]->api->process(revchain[i], coords)) + return -1; /* Error. */ + } else { + i--; + } + } + + if (i >= 0) { + BUG_ON(i != len); /* FIXME: Remove BUG_ON. */ + ts_filter_chain_scale(arr, coords); /* TODO: arr! */ + } - mutex_unlock(&chain_mutex); + return i >= 0; /* Same as i == len. */ } -EXPORT_SYMBOL_GPL(ts_filter_destroy_chain); +EXPORT_SYMBOL_GPL(ts_filter_chain_feed); diff --git a/drivers/input/touchscreen/ts_filter.h b/drivers/input/touchscreen/ts_filter.h index 3746e45bccc..b5e8c7c3845 100644 --- a/drivers/input/touchscreen/ts_filter.h +++ b/drivers/input/touchscreen/ts_filter.h @@ -4,7 +4,7 @@ /* * Touchscreen filter. * - * (c) 2008 Andy Green <andy@openmoko.com> + * (c) 2008,2009 Andy Green <andy@openmoko.com> */ #include <linux/platform_device.h> @@ -17,11 +17,41 @@ struct ts_filter; /* Operations that a filter can perform. */ struct ts_filter_api { + /* Create the filter - mandatory. */ struct ts_filter * (*create)(struct platform_device *pdev, void *config, int count_coords); - void (*destroy)(struct platform_device *pdev, struct ts_filter *filter); + /* Destroy the filter - mandatory. */ + void (*destroy)(struct ts_filter *filter); + /* Clear the filter - optional. */ void (*clear)(struct ts_filter *filter); + + + /* + * The next three API functions only make sense if all of them are + * set for a filter. If a filter has the next three methods then + * it can propagate coordinates in the chain. + */ + + /* + * Process the filter. + * It returns non-zero if the filter reaches an error. + */ int (*process)(struct ts_filter *filter, int *coords); + /* + * Is the filter ready to return a point? + * Please do not code side effects in this function. + */ + int (*haspoint)(struct ts_filter *filter); + /* + * Get a point. + * Do not call unless the filter actually has a point to deliver. + */ + void (*getpoint)(struct ts_filter *filter, int *coords); + + /* + * Scale the points - optional. + * A filter could only scale coordinates. + */ void (*scale)(struct ts_filter *filter, int *coords); }; @@ -31,32 +61,43 @@ struct ts_filter_api { * the actual filter. Therefore you need one of these * at the start of your actual filter struct. */ - struct ts_filter { - struct ts_filter *next; /* Next in chain. */ - struct ts_filter_api *api; /* Operations to use for this object. */ - int count_coords; - int coords[MAX_TS_FILTER_COORDS]; + struct ts_filter_api *api; /* operations for this filter */ + int count_coords; /* how many coordinates to process */ + int coords[MAX_TS_FILTER_COORDS]; /* count_coords coordinates */ }; +#ifdef CONFIG_TOUCHSCREEN_FILTER + /* - * Helper to create a filter chain from an array of API pointers and - * array of config ints. Leaves pointers to created filters in arr - * array and fills in ->next pointers to create the chain. + * Helper to create a filter chain. It will allocate an array of + * null-terminated pointers to filters. */ - -#ifdef CONFIG_TOUCHSCREEN_FILTER -extern int ts_filter_create_chain(struct platform_device *pdev, - struct ts_filter_api **api, void **config, - struct ts_filter **arr, int count_coords); +extern struct ts_filter **ts_filter_chain_create( + struct platform_device *pdev, + struct ts_filter_api **api, void **config, int count_coords); /* Helper to destroy a whole chain from the list of filter pointers. */ +extern void ts_filter_chain_destroy(struct ts_filter **arr); + +/* Helper to call the clear API function */ +extern void ts_filter_chain_clear(struct ts_filter **arr); + +/* + * Try to get one point. Returns 0 if no points are available. + * coords will be used as temporal space, thus you supply a point + * using coords but you shouldn't rely on its value on return unless + * it returns a nonzero value that is not -1. + * If one of the filters find an error then this function will + * return -1. + */ +int ts_filter_chain_feed(struct ts_filter **arr, int *coords); -extern void ts_filter_destroy_chain(struct platform_device *pdev, - struct ts_filter **arr); -#else -#define ts_filter_create_chain(pdev, api, config, arr, count_coords) (0) -#define ts_filter_destroy_chain(pdev, arr) do { } while (0) +#else /* !CONFIG_TOUCHSCREEN_FILTER */ +#define ts_filter_chain_create(pdev, api, config, arr, count_coords) (0) +#define ts_filter_chain_destroy(pdev, arr) do { } while (0) +#define ts_filter_chain_clear(arr) do { } while (0) +#define ts_filter_chain_feed(arr, coords) (1) #endif #endif diff --git a/drivers/input/touchscreen/ts_filter_group.c b/drivers/input/touchscreen/ts_filter_group.c index f2ecd92916e..9b02c70c4bb 100644 --- a/drivers/input/touchscreen/ts_filter_group.c +++ b/drivers/input/touchscreen/ts_filter_group.c @@ -13,10 +13,11 @@ * 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. + * Copyright (C) 2008,2009 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. * @@ -42,21 +43,44 @@ #include <linux/sort.h> #include "ts_filter_group.h" +struct ts_filter_group { + /* Private filter configuration. */ + struct ts_filter_group_configuration *config; + /* Filter API. */ + struct ts_filter tsf; + + 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. */ + int ready; /* If we are ready to deliver samples. */ + int result; /* Index of the point being returned. */ +}; + +#define ts_filter_to_filter_group(f) \ + container_of(f, struct ts_filter_group, tsf) + + static void ts_filter_group_clear_internal(struct ts_filter_group *tsfg, int attempts) { tsfg->N = 0; tsfg->tries_left = attempts; + tsfg->ready = 0; + tsfg->result = 0; } static void ts_filter_group_clear(struct ts_filter *tsf) { - struct ts_filter_group *tsfg = (struct ts_filter_group *)tsf; + struct ts_filter_group *tsfg = ts_filter_to_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(struct platform_device *pdev, @@ -65,8 +89,6 @@ static struct ts_filter *ts_filter_group_create(struct platform_device *pdev, 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; @@ -91,28 +113,21 @@ static struct ts_filter *ts_filter_group_create(struct platform_device *pdev, 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); + dev_info(&pdev->dev, "Created Group filter len:%d coords:%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 platform_device *pdev, - struct ts_filter *tsf) +static void ts_filter_group_destroy(struct ts_filter *tsf) { - struct ts_filter_group *tsfg = (struct ts_filter_group *)tsf; + struct ts_filter_group *tsfg = ts_filter_to_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; @@ -125,20 +140,22 @@ static int int_cmp(const void *_a, const void *_b) return 0; } +static void ts_filter_group_prepare_next(struct ts_filter *tsf); + static int ts_filter_group_process(struct ts_filter *tsf, int *coords) { - struct ts_filter_group *tsfg = (struct ts_filter_group *)tsf; + struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf); int n; int i; - int ret = 0; /* ask for more samples by default */ BUG_ON(tsfg->N >= tsfg->config->extent); + BUG_ON(tsfg->ready); 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 */ + return 0; /* We need more samples. */ for (n = 0; n < tsfg->tsf.count_coords; n++) { int *v = tsfg->sorted_samples; @@ -148,6 +165,14 @@ static int ts_filter_group_process(struct ts_filter *tsf, int *coords) int idx = 0; memcpy(v, tsfg->samples[n], tsfg->N * sizeof(int)); + /* + * FIXME: Remove this sort call. We already have the + * algorithm for this modification. The filter will + * need less points (about half) if there is not a + * lot of noise. Right now we are doing a constant + * amount of work no matter how much noise we are + * dealing with. + */ sort(v, tsfg->N, sizeof(int), int_cmp, NULL); tsfg->group_size[0] = 1; @@ -173,49 +198,94 @@ static int ts_filter_group_process(struct ts_filter *tsf, int *coords) if (--tsfg->tries_left) { ts_filter_group_clear_internal (tsfg, tsfg->tries_left); - return 0; /* ask for more samples */ + /* No errors but we need more samples. */ + return 0; } - return -1; /* we give up */ + return 1; /* We give up: error. */ } tsfg->range_min[n] = v[best_idx]; tsfg->range_max[n] = v[best_idx + best_size - 1]; } - for (i = 0; i < tsfg->N; ++i) { - int r; + ts_filter_group_prepare_next(tsf); - 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; - } + return 0; +} - if (n != tsfg->tsf.count_coords) /* sample not OK */ - continue; +/* + * This private function prepares a point that will be returned + * in ts_filter_group_getpoint if it is available. It updates + * the priv->ready state also. + */ +static void ts_filter_group_prepare_next(struct ts_filter *tsf) +{ + struct ts_filter_group *priv = ts_filter_to_filter_group(tsf); + int n; - if (tsf->next) { - r = (tsf->next->api->process)(tsf->next, coords); - if (r) { - ret = r; + while (priv->result < priv->N) { + for (n = 0; n < priv->tsf.count_coords; ++n) { + if (priv->samples[n][priv->result] < + priv->range_min[n] || + priv->samples[n][priv->result] > priv->range_max[n]) break; - } - } else if (i == tsfg->N - 1) { - ret = 1; } + + if (n == priv->tsf.count_coords) /* Sample is OK. */ + break; + + priv->result++; } - ts_filter_group_clear_internal(tsfg, tsfg->config->attempts); + if (unlikely(priv->result >= priv->N)) { /* No sample to deliver. */ + ts_filter_group_clear_internal(priv, priv->config->attempts); + priv->ready = 0; + } else { + priv->ready = 1; + } +} + +static int ts_filter_group_haspoint(struct ts_filter *tsf) +{ + struct ts_filter_group *priv = ts_filter_to_filter_group(tsf); + + return priv->ready; +} + +static void ts_filter_group_getpoint(struct ts_filter *tsf, int *point) +{ + struct ts_filter_group *priv = ts_filter_to_filter_group(tsf); + int n; + + BUG_ON(!priv->ready); + + for (n = 0; n < priv->tsf.count_coords; n++) + point[n] = priv->samples[n][priv->result]; + + priv->result++; + + /* This call will update priv->ready. */ + ts_filter_group_prepare_next(tsf); +} + +/* + * Get ready to process the next batch of points, forget + * points we could have delivered. + */ +static void ts_filter_group_scale(struct ts_filter *tsf, int *coords) +{ + struct ts_filter_group *priv = ts_filter_to_filter_group(tsf); - return ret; + ts_filter_group_clear_internal(priv, priv->config->attempts); } 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, + .create = ts_filter_group_create, + .destroy = ts_filter_group_destroy, + .clear = ts_filter_group_clear, + .process = ts_filter_group_process, + .haspoint = ts_filter_group_haspoint, + .getpoint = ts_filter_group_getpoint, + .scale = ts_filter_group_scale, }; diff --git a/drivers/input/touchscreen/ts_filter_group.h b/drivers/input/touchscreen/ts_filter_group.h index c411080eae2..c13b0c487df 100644 --- a/drivers/input/touchscreen/ts_filter_group.h +++ b/drivers/input/touchscreen/ts_filter_group.h @@ -18,22 +18,6 @@ struct ts_filter_group_configuration { 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/drivers/input/touchscreen/ts_filter_linear.c b/drivers/input/touchscreen/ts_filter_linear.c index c336252d0ff..72a362f7567 100644 --- a/drivers/input/touchscreen/ts_filter_linear.c +++ b/drivers/input/touchscreen/ts_filter_linear.c @@ -13,7 +13,7 @@ * 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. + * Copyright (C) 2008,2009 by Openmoko, Inc. * Author: Nelson Castillo <arhuaco@freaks-unidos.net> * All rights reserved. * @@ -29,9 +29,52 @@ #include <linux/slab.h> #include <linux/string.h> +struct ts_filter_linear; -/* sysfs functions */ +/* Sysfs. */ +/* FIXME: Comment all structure attributes. */ + +struct const_obj { + struct ts_filter_linear *tsfl; + struct kobject kobj; +}; + +#define to_const_obj(x) container_of(x, struct const_obj, kobj) + +struct const_attribute { + struct attribute attr; + ssize_t (*show)(struct const_obj *const, struct const_attribute *attr, + char *buf); + ssize_t (*store)(struct const_obj *const, struct const_attribute *attr, + const char *buf, size_t count); +}; + +#define to_const_attr(x) container_of(x, struct const_attribute, attr) + + +/* Private linear filter structure. */ + +struct ts_filter_linear { + struct ts_filter tsf; /* TODO: don't use as first */ + + struct ts_filter_linear_configuration *config; + + + int constants[TS_FILTER_LINEAR_NCONSTANTS]; + + /* Sysfs. */ + struct const_obj c_obj; + struct kobj_type const_ktype; + struct const_attribute kattrs[TS_FILTER_LINEAR_NCONSTANTS]; + struct attribute *attrs[TS_FILTER_LINEAR_NCONSTANTS + 1]; + char attr_names[TS_FILTER_LINEAR_NCONSTANTS][2]; +}; + +#define ts_filter_to_filter_linear(f) \ + container_of(f, struct ts_filter_linear, tsf) + +/* Sysfs functions. */ static ssize_t const_attr_show(struct kobject *kobj, struct attribute *attr, @@ -80,7 +123,7 @@ static ssize_t const_store(struct const_obj *obj, struct const_attribute *attr, return count; } -/* filter functions */ +/* Filter functions. */ static struct ts_filter *ts_filter_linear_create(struct platform_device *pdev, void *conf, int count_coords) @@ -121,53 +164,33 @@ static struct ts_filter *ts_filter_linear_create(struct platform_device *pdev, return NULL; } - printk(KERN_INFO" Created Linear ts filter depth %d\n", count_coords); + dev_info(&pdev->dev, "Created Linear filter coords:%d\n", count_coords); return &tsfl->tsf; } -static void ts_filter_linear_destroy(struct platform_device *pdev, - struct ts_filter *tsf) +static void ts_filter_linear_destroy(struct ts_filter *tsf) { - struct ts_filter_linear *tsfl = (struct ts_filter_linear *)tsf; + struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf); - /* kernel frees tsfl in const_release */ + /* Kernel frees tsfl in const_release. */ kobject_put(&tsfl->c_obj.kobj); } -static void ts_filter_linear_clear(struct ts_filter *tsf) -{ - if (tsf->next) /* chain */ - (tsf->next->api->clear)(tsf->next); -} - - static void ts_filter_linear_scale(struct ts_filter *tsf, int *coords) { - struct ts_filter_linear *tsfl = (struct ts_filter_linear *)tsf; + struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf); + int *k = tsfl->constants; int c0 = coords[tsfl->config->coord0]; int c1 = coords[tsfl->config->coord1]; coords[tsfl->config->coord0] = (k[2] + k[0] * c0 + k[1] * c1) / k[6]; coords[tsfl->config->coord1] = (k[5] + k[3] * c0 + k[4] * c1) / k[6]; - - if (tsf->next) - (tsf->next->api->scale)(tsf->next, coords); -} - -static int ts_filter_linear_process(struct ts_filter *tsf, int *coords) -{ - if (tsf->next) - return (tsf->next->api->process)(tsf->next, coords); - - return 1; } struct ts_filter_api ts_filter_linear_api = { - .create = ts_filter_linear_create, - .destroy = ts_filter_linear_destroy, - .clear = ts_filter_linear_clear, - .process = ts_filter_linear_process, - .scale = ts_filter_linear_scale, + .create = ts_filter_linear_create, + .destroy = ts_filter_linear_destroy, + .scale = ts_filter_linear_scale, }; diff --git a/drivers/input/touchscreen/ts_filter_linear.h b/drivers/input/touchscreen/ts_filter_linear.h index fc27cf77228..9da5b82881c 100644 --- a/drivers/input/touchscreen/ts_filter_linear.h +++ b/drivers/input/touchscreen/ts_filter_linear.h @@ -14,51 +14,15 @@ #define TS_FILTER_LINEAR_NCONSTANTS 7 -/* sysfs */ - -struct ts_filter_linear; - -struct const_obj { - struct ts_filter_linear *tsfl; - struct kobject kobj; -}; - -#define to_const_obj(x) container_of(x, struct const_obj, kobj) - -struct const_attribute { - struct attribute attr; - ssize_t (*show)(struct const_obj *const, struct const_attribute *attr, - char *buf); - ssize_t (*store)(struct const_obj *const, struct const_attribute *attr, - const char *buf, size_t count); -}; - -#define to_const_attr(x) container_of(x, struct const_attribute, attr) - /* filter configuration */ +/* FIXME: comment every field. */ struct ts_filter_linear_configuration { int constants[TS_FILTER_LINEAR_NCONSTANTS]; int coord0; int coord1; }; -/* the filter */ - -struct ts_filter_linear { - struct ts_filter tsf; - struct ts_filter_linear_configuration *config; - - int constants[TS_FILTER_LINEAR_NCONSTANTS]; - - /* sysfs */ - struct const_obj c_obj; - struct kobj_type const_ktype; - struct const_attribute kattrs[TS_FILTER_LINEAR_NCONSTANTS]; - struct attribute *attrs[TS_FILTER_LINEAR_NCONSTANTS + 1]; - char attr_names[TS_FILTER_LINEAR_NCONSTANTS][2]; -}; - extern struct ts_filter_api ts_filter_linear_api; #endif 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, }; + diff --git a/drivers/input/touchscreen/ts_filter_mean.h b/drivers/input/touchscreen/ts_filter_mean.h index 44c506c99c0..5677ed89019 100644 --- a/drivers/input/touchscreen/ts_filter_mean.h +++ b/drivers/input/touchscreen/ts_filter_mean.h @@ -8,27 +8,18 @@ * * mean * - * (c) 2008 Andy Green <andy@openmoko.com> + * (c) 2008,2009 + * Andy Green <andy@openmoko.com> + * Nelson Castillo <arhuaco@freaks-unidos.net> */ +/* Configuration for this filter. */ struct ts_filter_mean_configuration { - int bits_filter_length; - int averaging_threshold; - - int extent; -}; - -struct ts_filter_mean { - struct ts_filter tsf; - struct ts_filter_mean_configuration *config; - - int reported[MAX_TS_FILTER_COORDS]; - int lowpass[MAX_TS_FILTER_COORDS]; - int *fifo[MAX_TS_FILTER_COORDS]; - int fhead[MAX_TS_FILTER_COORDS]; - int ftail[MAX_TS_FILTER_COORDS]; + /* Number of points for the mean. */ + int length; }; +/* API functions for the mean filter */ extern struct ts_filter_api ts_filter_mean_api; -#endif +#endif /* __TS_FILTER_MEAN_H__ */ diff --git a/drivers/input/touchscreen/ts_filter_median.c b/drivers/input/touchscreen/ts_filter_median.c index b3b6a9c1e5c..6187abbb803 100644 --- a/drivers/input/touchscreen/ts_filter_median.c +++ b/drivers/input/touchscreen/ts_filter_median.c @@ -34,22 +34,50 @@ #include <linux/slab.h> #include "ts_filter_median.h" +struct ts_filter_median { + /* Private configuration. */ + struct ts_filter_median_configuration *config; + /* Generic Filter API. */ + struct ts_filter tsf; + + /* Count raw samples we get. */ + int samples_count; + /* + * Remember the last coordinates we got in order to know if + * we are moving slow or fast. + */ + int last_issued[MAX_TS_FILTER_COORDS]; + /* How many samples in the sort buffer are valid. */ + int valid; + /* Samples taken for median in sorted form. */ + int *sort[MAX_TS_FILTER_COORDS]; + /* Samples taken for median. */ + int *fifo[MAX_TS_FILTER_COORDS]; + /* Where we are in the fifo sample memory. */ + int pos; + /* Do we have a sample to deliver? */ + int ready; +}; + +#define ts_filter_to_filter_median(f) \ + container_of(f, struct ts_filter_median, tsf) + + static void ts_filter_median_insert(int *p, int sample, int count) { int n; - /* search through what we got so far to find where to put sample */ + /* Search through what we got so far to find where to put sample. */ for (n = 0; n < count; n++) - /* we met somebody bigger than us? */ - if (sample < p[n]) { - /* starting from the end, push bigger guys down one */ + if (sample < p[n]) { /* We met somebody bigger than us? */ + /* Starting from the end, push bigger guys down one. */ for (count--; count >= n; count--) p[count + 1] = p[count]; - p[n] = sample; /* and put us in place of first bigger */ + p[n] = sample; /* Put us in place of first bigger. */ return; } - p[count] = sample; /* nobody was bigger than us, add us on the end */ + p[count] = sample; /* Nobody was bigger than us, add us on the end. */ } static void ts_filter_median_del(int *p, int value, int count) @@ -65,20 +93,14 @@ static void ts_filter_median_del(int *p, int value, int count) } -static void ts_filter_median_clear_internal(struct ts_filter *tsf) +static void ts_filter_median_clear(struct ts_filter *tsf) { - struct ts_filter_median *tsfm = (struct ts_filter_median *)tsf; + struct ts_filter_median *tsfm = ts_filter_to_filter_median(tsf); tsfm->pos = 0; tsfm->valid = 0; - -} -static void ts_filter_median_clear(struct ts_filter *tsf) -{ - ts_filter_median_clear_internal(tsf); - - if (tsf->next) /* chain */ - (tsf->next->api->clear)(tsf->next); + tsfm->ready = 0; + memset(&tsfm->last_issued[0], 1, tsf->count_coords * sizeof(int)); } static struct ts_filter *ts_filter_median_create(struct platform_device *pdev, @@ -93,13 +115,12 @@ static struct ts_filter *ts_filter_median_create(struct platform_device *pdev, return NULL; tsfm->config = (struct ts_filter_median_configuration *)conf; - BUG_ON((count_coords < 1) || (count_coords > MAX_TS_FILTER_COORDS)); tsfm->tsf.count_coords = count_coords; tsfm->config->midpoint = (tsfm->config->extent >> 1) + 1; p = kmalloc(2 * count_coords * sizeof(int) * (tsfm->config->extent + 1), - GFP_KERNEL); + GFP_KERNEL); if (!p) { kfree(tsfm); return NULL; @@ -112,21 +133,21 @@ static struct ts_filter *ts_filter_median_create(struct platform_device *pdev, p += tsfm->config->extent + 1; } - ts_filter_median_clear_internal(&tsfm->tsf); + ts_filter_median_clear(&tsfm->tsf); - printk(KERN_INFO" Created Median ts filter len %d depth %d dec %d\n", - tsfm->config->extent, count_coords, - tsfm->config->decimation_threshold); + dev_info(&pdev->dev, + "Created Median filter len:%d coords:%d dec_threshold:%d\n", + tsfm->config->extent, count_coords, + tsfm->config->decimation_threshold); return &tsfm->tsf; } -static void ts_filter_median_destroy(struct platform_device *pdev, - struct ts_filter *tsf) +static void ts_filter_median_destroy(struct ts_filter *tsf) { - struct ts_filter_median *tsfm = (struct ts_filter_median *)tsf; + struct ts_filter_median *tsfm = ts_filter_to_filter_median(tsf); - kfree(tsfm->sort[0]); /* first guy has pointer from kmalloc */ + kfree(tsfm->sort[0]); /* First guy has pointer from kmalloc. */ kfree(tsf); } @@ -136,9 +157,6 @@ static void ts_filter_median_scale(struct ts_filter *tsf, int *coords) for (n = 0; n < tsf->count_coords; n++) coords[n] = (coords[n] + 2) / 3; - - if (tsf->next) /* chain */ - (tsf->next->api->scale)(tsf->next, coords); } /* @@ -149,69 +167,88 @@ static void ts_filter_median_scale(struct ts_filter *tsf, int *coords) static int ts_filter_median_process(struct ts_filter *tsf, int *coords) { - struct ts_filter_median *tsfm = (struct ts_filter_median *)tsf; + struct ts_filter_median *tsfm = ts_filter_to_filter_median(tsf); int n; int movement = 1; for (n = 0; n < tsf->count_coords; n++) { - /* grab copy in insertion order to remove when oldest */ + /* Grab copy in insertion order to remove when oldest. */ tsfm->fifo[n][tsfm->pos] = coords[n]; - /* insert these samples in sorted order in the median arrays */ + /* Insert these samples in sorted order in the median arrays. */ ts_filter_median_insert(tsfm->sort[n], coords[n], tsfm->valid); } - /* move us on in the fifo */ + /* Move us on in the fifo. */ if (++tsfm->pos == (tsfm->config->extent + 1)) tsfm->pos = 0; - /* we have finished a median sampling? */ - if (++tsfm->valid != tsfm->config->extent) - return 0; /* no valid sample to use */ + /* Have we finished a median sampling? */ + if (++tsfm->valid < tsfm->config->extent) + goto process_exit; /* No valid sample to use. */ + + BUG_ON(tsfm->valid != tsfm->config->extent); - /* discard the oldest sample in median sorted array */ tsfm->valid--; /* * Sum the middle 3 in the median sorted arrays. We don't divide back * down which increases the sum resolution by a factor of 3 until the - * scale API is called. + * scale API function is called. */ - for (n = 0; n < tsfm->tsf.count_coords; n++) - /* perform the deletion of the oldest sample */ + for (n = 0; n < tsf->count_coords; n++) + /* Perform the deletion of the oldest sample. */ ts_filter_median_del(tsfm->sort[n], tsfm->fifo[n][tsfm->pos], - tsfm->valid); + tsfm->valid); - tsfm->decimation_count--; - if (tsfm->decimation_count >= 0) - return 0; + tsfm->samples_count--; + if (tsfm->samples_count >= 0) + goto process_exit; - for (n = 0; n < tsfm->tsf.count_coords; n++) { - /* give the coordinate result from summing median 3 */ + for (n = 0; n < tsf->count_coords; n++) { + /* Give the coordinate result from summing median 3. */ coords[n] = tsfm->sort[n][tsfm->config->midpoint - 1] + tsfm->sort[n][tsfm->config->midpoint] + - tsfm->sort[n][tsfm->config->midpoint + 1] - ; + tsfm->sort[n][tsfm->config->midpoint + 1]; movement += abs(tsfm->last_issued[n] - coords[n]); } - if (movement > tsfm->config->decimation_threshold) /* fast */ - tsfm->decimation_count = tsfm->config->decimation_above; + if (movement > tsfm->config->decimation_threshold) /* Moving fast. */ + tsfm->samples_count = tsfm->config->decimation_above; else - tsfm->decimation_count = tsfm->config->decimation_below; + tsfm->samples_count = tsfm->config->decimation_below; + + memcpy(&tsfm->last_issued[0], coords, tsf->count_coords * sizeof(int)); + + tsfm->ready = 1; + +process_exit: + return 0; +} + +static int ts_filter_median_haspoint(struct ts_filter *tsf) +{ + struct ts_filter_median *priv = ts_filter_to_filter_median(tsf); + + return priv->ready; +} + +static void ts_filter_median_getpoint(struct ts_filter *tsf, int *point) +{ + struct ts_filter_median *priv = ts_filter_to_filter_median(tsf); - memcpy(&tsfm->last_issued[0], coords, - tsfm->tsf.count_coords * sizeof(int)); + BUG_ON(!priv->ready); - if (tsf->next) /* chain */ - return (tsf->next->api->process)(tsf->next, coords); + memcpy(point, &priv->last_issued[0], tsf->count_coords * sizeof(int)); - return 1; + priv->ready = 0; } struct ts_filter_api ts_filter_median_api = { - .create = ts_filter_median_create, - .destroy = ts_filter_median_destroy, - .clear = ts_filter_median_clear, - .process = ts_filter_median_process, - .scale = ts_filter_median_scale, + .create = ts_filter_median_create, + .destroy = ts_filter_median_destroy, + .clear = ts_filter_median_clear, + .process = ts_filter_median_process, + .scale = ts_filter_median_scale, + .haspoint = ts_filter_median_haspoint, + .getpoint = ts_filter_median_getpoint, }; diff --git a/drivers/input/touchscreen/ts_filter_median.h b/drivers/input/touchscreen/ts_filter_median.h index 8f25e27b2aa..589bc6d996c 100644 --- a/drivers/input/touchscreen/ts_filter_median.h +++ b/drivers/input/touchscreen/ts_filter_median.h @@ -11,6 +11,7 @@ * (c) 2008 Andy Green <andy@openmoko.com> */ +/* TODO: comment every field */ struct ts_filter_median_configuration { int extent; int midpoint; @@ -19,18 +20,6 @@ struct ts_filter_median_configuration { int decimation_below; }; -struct ts_filter_median { - struct ts_filter tsf; - struct ts_filter_median_configuration *config; - - int decimation_count; - int last_issued[MAX_TS_FILTER_COORDS]; - int valid; /* how many samples in the sort buffer are valid */ - int *sort[MAX_TS_FILTER_COORDS]; /* samples taken for median */ - int *fifo[MAX_TS_FILTER_COORDS]; /* samples taken for median */ - int pos; /* where we are in the fifo sample memory */ -}; - extern struct ts_filter_api ts_filter_median_api; #endif |