Remove sort call from group filter
[kernel.git] / 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  * This filter mixes information from all the available dimensions. It means
24  * that for two dimensions we draw a rectangle where the though-to-be good
25  * points can be found.
26  *
27  * The implementation would be more efficient with a double-linked list but
28  * let's keep it simple for now.
29  *
30  * 1) We collect S samples and keep it in sorted sets.
31  *  - Points that are "close enough" are considered to be in the same set.
32  *    We don't actually keep the sets but ranges of points.
33  *
34  * 2) For each dimension:
35  *  - We choose the range with more elements. If more than "threshold"
36  *    points are in this range we use the minimum and the maximum point
37  *    of the range to define the valid range for this dimension [min, max],
38  *    otherwise we discard all the points and the ranges and go to step 1.
39  *
40  * 3) We consider the unsorted S samples and try to feed them to the next
41  *    filter in the chain. If one of the points of each sample
42  *    is not in the allowed range for its dimension we discard the sample.
43  *
44  */
45
46 #include <linux/kernel.h>
47 #include <linux/slab.h>
48 #include "ts_filter_group.h"
49
50 struct coord_range {
51         int min;        /* Minimum value of the range. */
52         int max;        /* Maximum value of the range  */
53         int N;          /* Number of points in the range. */
54 };
55
56 struct ts_filter_group {
57         /* Private filter configuration. */
58         struct ts_filter_group_configuration *config;
59         /* Filter API. */
60         struct ts_filter tsf;
61
62         int N;                  /* How many samples we have. */
63         int *samples[MAX_TS_FILTER_COORDS];     /* The samples: our input. */
64
65         /* Temporal values that help us compute range_min and range_max. */
66         struct coord_range *ranges[MAX_TS_FILTER_COORDS];       /* Ranges. */
67         int n_ranges[MAX_TS_FILTER_COORDS];             /* Number of ranges */
68
69         /* Computed ranges that help us filter the points. */
70         int range_max[MAX_TS_FILTER_COORDS];    /* Max. computed ranges. */
71         int range_min[MAX_TS_FILTER_COORDS];    /* Min. computed ranges. */
72
73         int tries_left;         /* We finish if we can't get enough samples. */
74         int ready;              /* If we are ready to deliver samples. */
75         int result;             /* Index of the point being returned. */
76 };
77
78 #define ts_filter_to_filter_group(f) \
79         container_of(f, struct ts_filter_group, tsf)
80
81
82 static void ts_filter_group_clear_internal(struct ts_filter_group *tsfg,
83                                            int attempts)
84 {
85         int n;
86         tsfg->N = 0;
87         tsfg->tries_left = attempts;
88         tsfg->ready = 0;
89         tsfg->result = 0;
90         for (n = 0; n < tsfg->tsf.count_coords; n++)
91                 tsfg->n_ranges[n] = 0;
92 }
93
94 static void ts_filter_group_clear(struct ts_filter *tsf)
95 {
96         struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
97
98         ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
99 }
100
101 static struct ts_filter *ts_filter_group_create(
102         struct platform_device *pdev,
103         const struct ts_filter_configuration *conf,
104         int count_coords)
105 {
106         struct ts_filter_group *tsfg;
107         int i;
108
109         tsfg = kzalloc(sizeof(struct ts_filter_group), GFP_KERNEL);
110         if (!tsfg)
111                 return NULL;
112
113         tsfg->config = container_of(conf,
114                                     struct ts_filter_group_configuration,
115                                     config);
116         tsfg->tsf.count_coords = count_coords;
117
118         BUG_ON(tsfg->config->attempts <= 0);
119         BUG_ON(tsfg->config->length < tsfg->config->threshold);
120
121         tsfg->samples[0] = kmalloc(count_coords * sizeof(int) *
122                                    tsfg->config->length, GFP_KERNEL);
123         if (!tsfg->samples[0]) {
124                 kfree(tsfg);
125                 return NULL;
126         }
127         for (i = 1; i < count_coords; ++i)
128                 tsfg->samples[i] = tsfg->samples[0] + i * tsfg->config->length;
129
130         tsfg->ranges[0] = kmalloc(count_coords * sizeof(struct coord_range) *
131                                   tsfg->config->length, GFP_KERNEL);
132         if (!tsfg->ranges[0]) {
133                 kfree(tsfg->samples[0]);
134                 kfree(tsfg);
135                 return NULL;
136         }
137         for (i = 1; i < count_coords; ++i)
138                 tsfg->ranges[i] = tsfg->ranges[0] + i * tsfg->config->length;
139
140         ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
141
142         dev_info(&pdev->dev, "Created Group filter len:%d coords:%d close:%d "
143                  "thresh:%d\n", tsfg->config->length, count_coords,
144                  tsfg->config->close_enough, tsfg->config->threshold);
145
146         return &tsfg->tsf;
147 }
148
149 static void ts_filter_group_destroy(struct ts_filter *tsf)
150 {
151         struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
152
153         kfree(tsfg->samples[0]);
154         kfree(tsfg->ranges[0]);
155         kfree(tsf);
156 }
157
158 static void ts_filter_group_prepare_next(struct ts_filter *tsf);
159
160 #define MIN(a, b) ((a) < (b) ? (a) : (b))
161 #define MAX(a, b) ((a) > (b) ? (a) : (b))
162 #define IN_RANGE(c, r) ((c) >= (r).min - tsfg->config->close_enough && \
163                         (c) <= (r).max + tsfg->config->close_enough)
164
165 static void delete_spot(struct coord_range *v, int n, int size)
166 {
167         int i;
168         for (i = n; i < size - 1; ++i)
169                 v[i] = v[i + 1];
170 }
171
172 static int ts_filter_group_process(struct ts_filter *tsf, int *coords)
173 {
174         struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
175         int n;
176         int j;
177
178         BUG_ON(tsfg->N >= tsfg->config->length);
179         BUG_ON(tsfg->ready);
180
181         for (n = 0; n < tsfg->tsf.count_coords; n++) {
182                 int i;
183                 struct coord_range *range = tsfg->ranges[n];
184                 int *n_ranges = &tsfg->n_ranges[n];
185                 int found = 0;
186
187                 tsfg->samples[n][tsfg->N] = coords[n];
188
189                 for (i = 0; i < *n_ranges; ++i) {
190                         if (IN_RANGE(coords[n], range[i])) {
191                                 range[i].min  = MIN(range[i].min, coords[n]);
192                                 range[i].max  = MAX(range[i].max, coords[n]);
193                                 range[i].N++;
194                                 found = 1;
195                                 break;
196                         } else if (coords[n] <= range[i].min)
197                                 break;  /* We need to insert a range. */
198                 }
199                 if (found) { /* We might need to melt ranges. */
200                         if (i && range[i - 1].max + tsfg->config->close_enough
201                             >= range[i].min) {
202                                 BUG_ON(range[i - 1].max >= range[i].max);
203                                 range[i - 1].max = range[i].max;
204                                 range[i - 1].N += range[i].N;
205                                 delete_spot(range, i, *n_ranges);
206                                 (*n_ranges)--;
207                                 i--;
208                         }
209                         if (i < *n_ranges - 1 && range[i + 1].min -
210                             tsfg->config->close_enough <= range[i].max) {
211                                 range[i].max = range[i + 1].max;
212                                 range[i].N += range[i + 1].N;
213                                 delete_spot(range, i + 1, *n_ranges);
214                                 (*n_ranges)--;
215                         }
216                 } else {
217                         BUG_ON((*n_ranges) >= tsfg->config->length);
218                         (*n_ranges)++;
219                         for (j = *n_ranges - 1; j > i; --j)
220                                 range[j] = range[j - 1];
221                         range[i].N = 1;
222                         range[i].min = coords[n];
223                         range[i].max = coords[n];
224                 }
225         }
226
227         if (++tsfg->N < tsfg->config->length)
228                 return 0;
229
230         for (n = 0; n < tsfg->tsf.count_coords; ++n) {
231                 int best = 0;
232                 for (j = 1; j < tsfg->n_ranges[n]; ++j)
233                         if (tsfg->ranges[n][best].N  < tsfg->ranges[n][j].N)
234                                 best = j;
235                 if (tsfg->ranges[n][best].N < tsfg->config->threshold) {
236                         /* This set of points is not good enough for us. */
237                         if (--tsfg->tries_left) {
238                                 ts_filter_group_clear_internal
239                                         (tsfg, tsfg->tries_left);
240                                 /* No errors but we need more samples. */
241                                 return 0;
242                         }
243                         return 1; /* We give up: error. */
244                 }
245                 tsfg->range_min[n] = tsfg->ranges[n][best].min;
246                 tsfg->range_max[n] = tsfg->ranges[n][best].max;
247         }
248
249         ts_filter_group_prepare_next(tsf);
250
251         return 0;
252 }
253
254 /*
255  * This private function prepares a point that will be returned
256  * in ts_filter_group_getpoint if it is available. It updates
257  * the priv->ready state also.
258  */
259 static void ts_filter_group_prepare_next(struct ts_filter *tsf)
260 {
261         struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
262         int n;
263
264         while (priv->result < priv->N) {
265                 for (n = 0; n < priv->tsf.count_coords; ++n) {
266                         if (priv->samples[n][priv->result] <
267                             priv->range_min[n] ||
268                             priv->samples[n][priv->result] > priv->range_max[n])
269                                 break;
270                 }
271
272                 if (n == priv->tsf.count_coords) /* Sample is OK. */
273                         break;
274
275                 priv->result++;
276         }
277
278         if (unlikely(priv->result >= priv->N)) { /* No sample to deliver. */
279                 ts_filter_group_clear_internal(priv, priv->config->attempts);
280                 priv->ready = 0;
281         } else {
282                 priv->ready = 1;
283         }
284 }
285
286 static int ts_filter_group_haspoint(struct ts_filter *tsf)
287 {
288         struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
289
290         return priv->ready;
291 }
292
293 static void ts_filter_group_getpoint(struct ts_filter *tsf, int *point)
294 {
295         struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
296         int n;
297
298         BUG_ON(!priv->ready);
299
300         for (n = 0; n < priv->tsf.count_coords; n++)
301                 point[n] = priv->samples[n][priv->result];
302
303         priv->result++;
304
305         /* This call will update priv->ready. */
306         ts_filter_group_prepare_next(tsf);
307 }
308
309 /*
310  * Get ready to process the next batch of points, forget
311  * points we could have delivered.
312  */
313 static void ts_filter_group_scale(struct ts_filter *tsf, int *coords)
314 {
315         struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
316
317         ts_filter_group_clear_internal(priv, priv->config->attempts);
318 }
319
320 const struct ts_filter_api ts_filter_group_api = {
321         .create =       ts_filter_group_create,
322         .destroy =      ts_filter_group_destroy,
323         .clear =        ts_filter_group_clear,
324         .process =      ts_filter_group_process,
325         .haspoint =     ts_filter_group_haspoint,
326         .getpoint =     ts_filter_group_getpoint,
327         .scale =        ts_filter_group_scale,
328 };
329 EXPORT_SYMBOL_GPL(ts_filter_group_api);
330