[x86] add rootwait option to the kernel command line (#6209)
[openwrt.git] / target / linux / s3c24xx / files-2.6.31 / drivers / input / touchscreen / ts_filter_linear.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; 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  * Linearly scale touchscreen values.
21  *
22  * Expose the TS_FILTER_LINEAR_NCONSTANTS for the linear transformation
23  * using sysfs.
24  *
25  */
26
27 #include <linux/kernel.h>
28 #include <linux/slab.h>
29 #include <linux/string.h>
30
31 #include <linux/touchscreen/ts_filter_linear.h>
32
33 struct ts_filter_linear;
34
35 /* Sysfs code. */
36
37 struct const_obj {
38         /* The actual private object. */
39         struct ts_filter_linear *tsfl;
40         /* Our kobject. */
41         struct kobject kobj;
42 };
43
44 #define to_const_obj(x) container_of(x, struct const_obj, kobj)
45
46 struct const_attribute {
47         struct attribute attr;
48         ssize_t (*show)(struct const_obj *const, struct const_attribute *attr,
49                         char *buf);
50         ssize_t (*store)(struct const_obj *const, struct const_attribute *attr,
51                          const char *buf, size_t count);
52 };
53
54 #define to_const_attr(x) container_of(x, struct const_attribute, attr)
55
56
57 /* Private linear filter structure. */
58
59 struct ts_filter_linear {
60         /* Private configuration for this filter. */
61         struct ts_filter_linear_configuration *config;
62
63         /* Generic filter API. */
64         struct ts_filter tsf;
65
66         /* Linear constants for the transformation. */
67         int constants[TS_FILTER_LINEAR_NCONSTANTS];
68
69         /* Sysfs. */
70
71         /* Our const_object. */
72         struct const_obj c_obj;
73         /* Our type. We will stick operations to it. */
74         struct kobj_type const_ktype;
75         /* Attrs. of the virtual files. */
76         struct const_attribute kattrs[TS_FILTER_LINEAR_NCONSTANTS];
77         /* Default Attrs. Always NULL for us. */
78         struct attribute *attrs[TS_FILTER_LINEAR_NCONSTANTS + 1];
79         /* Storage for the name of the virtual files. */
80         char attr_names[TS_FILTER_LINEAR_NCONSTANTS][2];
81 };
82
83 #define ts_filter_to_filter_linear(f) \
84         container_of(f, struct ts_filter_linear, tsf)
85
86 /* Sysfs functions. */
87
88 static ssize_t const_attr_show(struct kobject *kobj,
89                                struct attribute *attr,
90                                char *buf)
91 {
92         struct const_attribute *a = to_const_attr(attr);
93
94         return a->show(to_const_obj(kobj), a, buf);
95 }
96
97 static ssize_t const_attr_store(struct kobject *kobj,
98                                 struct attribute *attr,
99                                 const char *buf, size_t len)
100 {
101         struct const_attribute *a = to_const_attr(attr);
102
103         return a->store(to_const_obj(kobj), a, buf, len);
104 }
105
106 static struct sysfs_ops const_sysfs_ops = {
107         .show =         const_attr_show,
108         .store =        const_attr_store,
109 };
110
111 static void const_release(struct kobject *kobj)
112 {
113         kfree(to_const_obj(kobj)->tsfl);
114 }
115
116 static ssize_t const_show(struct const_obj *obj, struct const_attribute *attr,
117                           char *buf)
118 {
119         int who;
120
121         sscanf(attr->attr.name, "%d", &who);
122         return sprintf(buf, "%d\n", obj->tsfl->constants[who]);
123 }
124
125 static ssize_t const_store(struct const_obj *obj, struct const_attribute *attr,
126                            const char *buf, size_t count)
127 {
128         int who;
129
130         sscanf(attr->attr.name, "%d", &who);
131         sscanf(buf, "%d", &obj->tsfl->constants[who]);
132         return count;
133 }
134
135 /* Filter functions. */
136
137 static struct ts_filter *ts_filter_linear_create(
138         struct platform_device *pdev,
139         const struct ts_filter_configuration *conf,
140         int count_coords)
141 {
142         struct ts_filter_linear *tsfl;
143         int i;
144         int ret;
145
146         tsfl = kzalloc(sizeof(struct ts_filter_linear), GFP_KERNEL);
147         if (!tsfl)
148                 return NULL;
149
150         tsfl->config = container_of(conf,
151                                     struct ts_filter_linear_configuration,
152                                     config);
153
154         tsfl->tsf.count_coords = count_coords;
155
156         for (i = 0; i < TS_FILTER_LINEAR_NCONSTANTS; ++i) {
157                 tsfl->constants[i] = tsfl->config->constants[i];
158
159                 /* sysfs */
160                 sprintf(tsfl->attr_names[i], "%d", i);
161                 tsfl->kattrs[i].attr.name = tsfl->attr_names[i];
162                 tsfl->kattrs[i].attr.mode = 0666;
163                 tsfl->kattrs[i].show = const_show;
164                 tsfl->kattrs[i].store = const_store;
165                 tsfl->attrs[i] = &tsfl->kattrs[i].attr;
166         }
167         tsfl->attrs[i] = NULL;
168
169         tsfl->const_ktype.sysfs_ops = &const_sysfs_ops;
170         tsfl->const_ktype.release = const_release;
171         tsfl->const_ktype.default_attrs = tsfl->attrs;
172         tsfl->c_obj.tsfl = tsfl; /* kernel frees tsfl in const_release */
173
174         ret = kobject_init_and_add(&tsfl->c_obj.kobj, &tsfl->const_ktype,
175                                    &pdev->dev.kobj, "calibration");
176         if (ret) {
177                 kobject_put(&tsfl->c_obj.kobj);
178                 return NULL;
179         }
180
181         dev_info(&pdev->dev, "Created Linear filter coords:%d\n", count_coords);
182
183         return &tsfl->tsf;
184 }
185
186 static void ts_filter_linear_destroy(struct ts_filter *tsf)
187 {
188         struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf);
189
190         /* Kernel frees tsfl in const_release. */
191         kobject_put(&tsfl->c_obj.kobj);
192 }
193
194 static void ts_filter_linear_scale(struct ts_filter *tsf, int *coords)
195 {
196         struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf);
197
198         int *k = tsfl->constants;
199         int c0 = coords[tsfl->config->coord0];
200         int c1 = coords[tsfl->config->coord1];
201
202         coords[tsfl->config->coord0] = (k[2] + k[0] * c0 + k[1] * c1) / k[6];
203         coords[tsfl->config->coord1] = (k[5] + k[3] * c0 + k[4] * c1) / k[6];
204 }
205
206 const struct ts_filter_api ts_filter_linear_api = {
207         .create =       ts_filter_linear_create,
208         .destroy =      ts_filter_linear_destroy,
209         .scale =        ts_filter_linear_scale,
210 };
211 EXPORT_SYMBOL_GPL(ts_filter_linear_api);
212