Root/target/linux/s3c24xx/files-2.6.30/drivers/input/touchscreen/ts_filter_group.c

1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 * Copyright (C) 2008,2009 by Openmoko, Inc.
17 * Author: Nelson Castillo <arhuaco@freaks-unidos.net>
18 * All rights reserved.
19 *
20 *
21 * This filter is useful to reject samples that are not reliable. We consider
22 * that a sample is not reliable if it deviates form the Majority.
23 *
24 * 1) We collect S samples.
25 *
26 * 2) For each dimension:
27 *
28 * - We sort the points.
29 * - Points that are "close enough" are considered to be in the same set.
30 * - We choose the set with more elements. If more than "threshold"
31 * points are in this set we use the first and the last point of the set
32 * to define the valid range for this dimension [min, max], otherwise we
33 * discard all the points and go to step 1.
34 *
35 * 3) We consider the unsorted S samples and try to feed them to the next
36 * filter in the chain. If one of the points of each sample
37 * is not in the allowed range for its dimension, we discard the sample.
38 *
39 */
40
41#include <linux/kernel.h>
42#include <linux/slab.h>
43#include <linux/sort.h>
44#include <linux/touchscreen/ts_filter_group.h>
45
46struct ts_filter_group {
47    /* Private filter configuration. */
48    struct ts_filter_group_configuration *config;
49    /* Filter API. */
50    struct ts_filter tsf;
51
52    int N; /* How many samples we have. */
53    int *samples[MAX_TS_FILTER_COORDS]; /* The samples: our input. */
54
55    int *group_size; /* Used for temporal computations. */
56    int *sorted_samples; /* Used for temporal computations. */
57
58    int range_max[MAX_TS_FILTER_COORDS]; /* Max. computed ranges. */
59    int range_min[MAX_TS_FILTER_COORDS]; /* Min. computed ranges. */
60
61    int tries_left; /* We finish if we don't get enough samples. */
62    int ready; /* If we are ready to deliver samples. */
63    int result; /* Index of the point being returned. */
64};
65
66#define ts_filter_to_filter_group(f) \
67    container_of(f, struct ts_filter_group, tsf)
68
69
70static void ts_filter_group_clear_internal(struct ts_filter_group *tsfg,
71                       int attempts)
72{
73    tsfg->N = 0;
74    tsfg->tries_left = attempts;
75    tsfg->ready = 0;
76    tsfg->result = 0;
77}
78
79static void ts_filter_group_clear(struct ts_filter *tsf)
80{
81    struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
82
83    ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
84}
85
86static struct ts_filter *ts_filter_group_create(
87    struct platform_device *pdev,
88    const struct ts_filter_configuration *conf,
89    int count_coords)
90{
91    struct ts_filter_group *tsfg;
92    int i;
93
94    tsfg = kzalloc(sizeof(struct ts_filter_group), GFP_KERNEL);
95    if (!tsfg)
96        return NULL;
97
98    tsfg->config = container_of(conf,
99                    struct ts_filter_group_configuration,
100                    config);
101    tsfg->tsf.count_coords = count_coords;
102
103    BUG_ON(tsfg->config->attempts <= 0);
104
105    tsfg->samples[0] = kmalloc((2 + count_coords) * sizeof(int) *
106                   tsfg->config->length, GFP_KERNEL);
107    if (!tsfg->samples[0]) {
108        kfree(tsfg);
109        return NULL;
110    }
111    for (i = 1; i < count_coords; ++i)
112        tsfg->samples[i] = tsfg->samples[0] + i * tsfg->config->length;
113    tsfg->sorted_samples = tsfg->samples[0] + count_coords *
114                   tsfg->config->length;
115    tsfg->group_size = tsfg->samples[0] + (1 + count_coords) *
116                   tsfg->config->length;
117
118    ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
119
120    dev_info(&pdev->dev, "Created Group filter len:%d coords:%d close:%d "
121         "thresh:%d\n", tsfg->config->length, count_coords,
122         tsfg->config->close_enough, tsfg->config->threshold);
123
124    return &tsfg->tsf;
125}
126
127static void ts_filter_group_destroy(struct ts_filter *tsf)
128{
129    struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
130
131    kfree(tsfg->samples[0]); /* first guy has pointer from kmalloc */
132    kfree(tsf);
133}
134
135static int int_cmp(const void *_a, const void *_b)
136{
137    const int *a = _a;
138    const int *b = _b;
139
140    if (*a > *b)
141        return 1;
142    if (*a < *b)
143        return -1;
144    return 0;
145}
146
147static void ts_filter_group_prepare_next(struct ts_filter *tsf);
148
149static int ts_filter_group_process(struct ts_filter *tsf, int *coords)
150{
151    struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
152    int n;
153    int i;
154
155    BUG_ON(tsfg->N >= tsfg->config->length);
156    BUG_ON(tsfg->ready);
157
158    for (n = 0; n < tsf->count_coords; n++)
159        tsfg->samples[n][tsfg->N] = coords[n];
160
161    if (++tsfg->N < tsfg->config->length)
162        return 0; /* We need more samples. */
163
164    for (n = 0; n < tsfg->tsf.count_coords; n++) {
165        int *v = tsfg->sorted_samples;
166        int ngroups = 0;
167        int best_size;
168        int best_idx = 0;
169        int idx = 0;
170
171        memcpy(v, tsfg->samples[n], tsfg->N * sizeof(int));
172        /*
173         * FIXME: Remove this sort call. We already have the
174         * algorithm for this modification. The filter will
175         * need less points (about half) if there is not a
176         * lot of noise. Right now we are doing a constant
177         * amount of work no matter how much noise we are
178         * dealing with.
179         */
180        sort(v, tsfg->N, sizeof(int), int_cmp, NULL);
181
182        tsfg->group_size[0] = 1;
183        for (i = 1; i < tsfg->N; ++i) {
184            if (v[i] - v[i - 1] <= tsfg->config->close_enough)
185                tsfg->group_size[ngroups]++;
186            else
187                tsfg->group_size[++ngroups] = 1;
188        }
189        ngroups++;
190
191        best_size = tsfg->group_size[0];
192        for (i = 1; i < ngroups; i++) {
193            idx += tsfg->group_size[i - 1];
194            if (best_size < tsfg->group_size[i]) {
195                best_size = tsfg->group_size[i];
196                best_idx = idx;
197            }
198        }
199
200        if (best_size < tsfg->config->threshold) {
201            /* This set is not good enough for us. */
202            if (--tsfg->tries_left) {
203                ts_filter_group_clear_internal
204                    (tsfg, tsfg->tries_left);
205                /* No errors but we need more samples. */
206                return 0;
207            }
208            return 1; /* We give up: error. */
209        }
210
211        tsfg->range_min[n] = v[best_idx];
212        tsfg->range_max[n] = v[best_idx + best_size - 1];
213    }
214
215    ts_filter_group_prepare_next(tsf);
216
217    return 0;
218}
219
220/*
221 * This private function prepares a point that will be returned
222 * in ts_filter_group_getpoint if it is available. It updates
223 * the priv->ready state also.
224 */
225static void ts_filter_group_prepare_next(struct ts_filter *tsf)
226{
227    struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
228    int n;
229
230    while (priv->result < priv->N) {
231        for (n = 0; n < priv->tsf.count_coords; ++n) {
232            if (priv->samples[n][priv->result] <
233                priv->range_min[n] ||
234                priv->samples[n][priv->result] > priv->range_max[n])
235                break;
236        }
237
238        if (n == priv->tsf.count_coords) /* Sample is OK. */
239            break;
240
241        priv->result++;
242    }
243
244    if (unlikely(priv->result >= priv->N)) { /* No sample to deliver. */
245        ts_filter_group_clear_internal(priv, priv->config->attempts);
246        priv->ready = 0;
247    } else {
248        priv->ready = 1;
249    }
250}
251
252static int ts_filter_group_haspoint(struct ts_filter *tsf)
253{
254    struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
255
256    return priv->ready;
257}
258
259static void ts_filter_group_getpoint(struct ts_filter *tsf, int *point)
260{
261    struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
262    int n;
263
264    BUG_ON(!priv->ready);
265
266    for (n = 0; n < priv->tsf.count_coords; n++)
267        point[n] = priv->samples[n][priv->result];
268
269    priv->result++;
270
271    /* This call will update priv->ready. */
272    ts_filter_group_prepare_next(tsf);
273}
274
275/*
276 * Get ready to process the next batch of points, forget
277 * points we could have delivered.
278 */
279static void ts_filter_group_scale(struct ts_filter *tsf, int *coords)
280{
281    struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
282
283    ts_filter_group_clear_internal(priv, priv->config->attempts);
284}
285
286const struct ts_filter_api ts_filter_group_api = {
287    .create = ts_filter_group_create,
288    .destroy = ts_filter_group_destroy,
289    .clear = ts_filter_group_clear,
290    .process = ts_filter_group_process,
291    .haspoint = ts_filter_group_haspoint,
292    .getpoint = ts_filter_group_getpoint,
293    .scale = ts_filter_group_scale,
294};
295EXPORT_SYMBOL_GPL(ts_filter_group_api);
296
297

Archive Download this file



interactive