2 * tslib/plugins/cy8mrln-palmpre.c
4 * Copyright (C) 2010 Frederik Sdun <frederik.sdun@googlemail.com>
5 * Thomas Zimmermann <ml@vdm-design.de>
6 * Simon Busch <morphis@gravedo.de>
8 * This file is placed under the LGPL. Please see the file
9 * COPYING for more details.
11 * Plugin for the cy8mrln touchscreen with the firmware used on the Palm Pre (Plus).
23 #include <sys/ioctl.h>
25 #include <sys/types.h>
27 #include <linux/spi/cy8mrln.h>
34 #include "tslib-private.h"
35 #include "tslib-filter.h"
38 #define SCREEN_WIDTH 319
39 #define SCREEN_HEIGHT 527
43 #define container_of(ptr, type, member) ({ \
44 const typeof( ((type*)0)->member ) *__mptr = (ptr); \
45 (type *)( (char *)__mptr - offsetof(type, member)); })
47 struct cy8mrln_palmpre_input
50 uint16_t field[H_FIELDS * V_FIELDS];
51 uint16_t ffff; /* always 0xffff */
52 uint8_t seq_nr1; /* incremented if seq_nr0 == scanrate */
53 uint16_t seq_nr2; /* incremeted if seq_nr1 == 255 */
55 uint8_t seq_nr0; /* incremented [0:scanrate] */
56 uint8_t null; /* NULL byte */
57 }__attribute__((packed));
59 struct tslib_cy8mrln_palmpre
61 struct tslib_module_info module;
62 uint16_t nulls[H_FIELDS * V_FIELDS];
65 static int scanrate = 60;
66 static int verbose = 0;
67 static int wot_threshold = 22;
68 static int sleepmode = CY8MRLN_ON_STATE;
69 static int wot_scanrate = WOT_SCANRATE_512HZ;
70 static int timestamp_mode = 1;
73 cy8mrln_palmpre_set_scanrate(struct tsdev* dev, int rate)
75 if (dev == NULL || ioctl(dev->fd,CY8MRLN_IOCTL_SET_SCANRATE,&rate) < 0)
82 printf("TSLIB: cy8mrln_palmpre: ERROR: could not set scanrate value\n");
87 cy8mrln_palmpre_set_verbose(struct tsdev* dev, int v)
89 if (dev == NULL || ioctl(dev->fd,CY8MRLN_IOCTL_SET_VERBOSE_MODE,&v) < 0)
96 printf("TSLIB: cy8mrln_palmpre: ERROR: could not set verbose value\n");
101 cy8mrln_palmpre_set_sleepmode(struct tsdev* dev, int mode)
103 if (dev == NULL || ioctl(dev->fd,CY8MRLN_IOCTL_SET_SLEEPMODE,&mode) < 0)
110 printf("TSLIB: cy8mrln_palmpre: ERROR: could not set sleepmode value\n");
115 cy8mrln_palmpre_set_wot_scanrate(struct tsdev* dev, int rate)
117 if (dev == NULL || ioctl(dev->fd,CY8MRLN_IOCTL_SET_WOT_SCANRATE,&rate) < 0)
124 printf("TSLIB: cy8mrln_palmpre: ERROR: could not set scanrate value\n");
129 cy8mrln_palmpre_set_wot_threshold(struct tsdev* dev, int v)
133 if(v < WOT_THRESHOLD_MIN || v > WOT_THRESHOLD_MAX)
135 if(ioctl(dev->fd,CY8MRLN_IOCTL_SET_WOT_THRESHOLD,&v) < 0)
142 printf("TSLIB: cy8mrln_palmpre: ERROR: could not set wot treshhold value\n");
147 cy8mrln_palmpre_set_timestamp_mode(struct tsdev* dev, int v)
150 if(dev == NULL || ioctl(dev->fd,CY8MRLN_IOCTL_SET_TIMESTAMP_MODE,&v) < 0)
156 printf("TSLIB: cy8mrln_palmpre: ERROR: could not set timestamp value\n");
161 parse_scanrate(struct tslib_module_info *info, char *str, void *data)
163 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
164 unsigned long rate = strtoul(str, NULL, 0);
166 if(rate == ULONG_MAX && errno == ERANGE)
169 return cy8mrln_palmpre_set_scanrate(i->module.dev, scanrate);
173 parse_verbose(struct tslib_module_info *info, char *str, void *data)
175 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
176 unsigned long v = strtoul(str, NULL, 0);
178 if(v == ULONG_MAX && errno == ERANGE)
181 return cy8mrln_palmpre_set_verbose(i->module.dev, scanrate);
185 parse_wot_scanrate(struct tslib_module_info *info, char *str, void *data)
187 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
188 unsigned long rate = strtoul(str, NULL, 0);
190 return cy8mrln_palmpre_set_wot_scanrate(i->module.dev, rate);
194 parse_wot_threshold(struct tslib_module_info *info, char *str, void *data)
196 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
197 unsigned long threshold = strtoul(str, NULL, 0);
199 return cy8mrln_palmpre_set_wot_threshold(i->module.dev, threshold);
203 parse_sleepmode(struct tslib_module_info *info, char *str, void *data)
205 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
206 unsigned long sleep = strtoul(str, NULL, 0);
208 return cy8mrln_palmpre_set_sleepmode(i->module.dev, sleep);
212 parse_timestamp_mode(struct tslib_module_info *info, char *str, void *data)
214 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
215 unsigned long sleep = strtoul(str, NULL, 0);
217 return cy8mrln_palmpre_set_sleepmode(i->module.dev, sleep);
220 static const struct tslib_vars raw_vars[] =
222 { "scanrate", NULL, parse_scanrate},
223 { "verbose", NULL, parse_verbose},
224 { "wot_scanrate", NULL, parse_wot_scanrate},
225 { "wot_threshold", NULL, parse_wot_threshold},
226 { "sleepmode", NULL, parse_sleepmode},
227 { "timestamp_mode", NULL, parse_timestamp_mode}
230 #define NR_VARS (sizeof(raw_vars) / sizeof(raw_vars[0]))
233 interpolate(uint16_t field[H_FIELDS * V_FIELDS], int i, struct ts_sample *out) {
234 float f11, f12, f13, f21, f22, f23, f31, f32, f33;
235 int x = SCREEN_WIDTH / H_FIELDS * (H_FIELDS - (i % H_FIELDS));
236 int y = SCREEN_HEIGHT / (V_FIELDS - 1) * (i / H_FIELDS);
237 static int dx = SCREEN_WIDTH / H_FIELDS;
238 static int dy = SCREEN_HEIGHT / V_FIELDS;
240 /* caluculate corrections for top, bottom, left and right fields */
241 f12 = (i < (H_FIELDS + 1)) ? 0.0 : 0.5 * field[i - H_FIELDS] / field[i];
242 f32 = (i > (H_FIELDS * (V_FIELDS - 2)))
243 ? 0.0 : 0.5 * field[i + H_FIELDS] / field[i];
244 f21 = (i % H_FIELDS == (H_FIELDS - 1))
245 ? 0.0 : 0.5 * field[i + 1] / field[i];
246 f23 = (i % H_FIELDS == 0) ? 0.0 : 0.5 * field[i - 1] / field[i];
248 /* correct values for the edges, shift the mesuarment point by half a
249 * field diminsion to the outside */
255 } else if (i == (H_FIELDS - 1)) {
260 } else if (i % H_FIELDS == (H_FIELDS - 1)) {
263 } else if (i % H_FIELDS == 0) {
266 } else if (i < H_FIELDS) {
269 } else if (i == (H_FIELDS * (V_FIELDS - 2))) {
274 } else if (i == (H_FIELDS * (V_FIELDS - 1) - 1)) {
279 } else if (i > (H_FIELDS * (V_FIELDS - 2))) {
284 out->x = x + (f23 - f21) * dx - (dx / 2);
285 out->y = y + (f32 - f12) * dy + (dy / 2);
287 out->pressure = field[i];
289 printf("RAW---------------------------> f22: %f (%d) f21: %f (%d), f23: %f (%d), f12: %f (%d), f32: %f (%d), \n",
291 f21, field[i - 1], f23, field[i + 1], f12,
292 field[i - H_FIELDS], f32, field[i + H_FIELDS]);
297 cy8mrln_palmpre_read(struct tslib_module_info *info, struct ts_sample *samp, int nr)
299 struct tsdev *ts = info->dev;
300 struct cy8mrln_palmpre_input *cy8mrln_evt;
301 struct tslib_cy8mrln_palmpre *cy8mrln_info;
302 int max_index = 0, max_value = 0, i = 0;
304 int ret, valid_samples = 0;
305 struct ts_sample *p = samp;
307 /* initalize all samples with proper values */
308 for (i = 0; i < nr; i++, p++)
315 cy8mrln_info = container_of(info, struct tslib_cy8mrln_palmpre, module);
317 cy8mrln_evt = alloca(sizeof(*cy8mrln_evt) * nr);
318 ret = read(ts->fd, cy8mrln_evt, sizeof(*cy8mrln_evt) * nr);
322 while(ret >= (int)sizeof(*cy8mrln_evt)) {
323 for (i = 0; i < (H_FIELDS * V_FIELDS); i++) {
324 /* auto calibrate zero values */
325 if (cy8mrln_evt->field[i] > cy8mrln_info->nulls[i])
326 cy8mrln_info->nulls[i] = cy8mrln_evt->field[i];
328 tmp_value = abs(cy8mrln_info->nulls[i] - cy8mrln_evt->field[i]);
330 /* check for the maximum value */
331 if (tmp_value > max_value) {
332 max_value = tmp_value;
336 cy8mrln_evt->field[i] = tmp_value;
338 /* only caluclate events that are not noise */
339 if (max_value > NOISE) {
340 interpolate(cy8mrln_evt->field, max_index, samp);
342 fprintf(stderr,"RAW---------------------------> %d %d %d\n",
343 samp->x, samp->y, samp->pressure);
345 gettimeofday(&samp->tv,NULL);
351 ret -= sizeof(*cy8mrln_evt);
357 return valid_samples;
361 cy8mrln_palmpre_fini(struct tslib_module_info *inf)
366 static const struct tslib_ops cy8mrln_palmpre_ops =
368 .read = cy8mrln_palmpre_read,
369 .fini = cy8mrln_palmpre_fini,
372 TSAPI struct tslib_module_info *cy8mrln_palmpre_mod_init(struct tsdev *dev, const char *params)
374 struct tslib_cy8mrln_palmpre *info;
375 struct cy8mrln_palmpre_input input;
378 info = malloc(sizeof(struct tslib_cy8mrln_palmpre));
381 info->module.ops = &cy8mrln_palmpre_ops;
383 cy8mrln_palmpre_set_verbose(dev,verbose);
384 cy8mrln_palmpre_set_scanrate(dev,scanrate);
385 cy8mrln_palmpre_set_timestamp_mode(dev,timestamp_mode);
386 cy8mrln_palmpre_set_sleepmode(dev,sleepmode);
387 cy8mrln_palmpre_set_wot_scanrate(dev,wot_scanrate);
388 cy8mrln_palmpre_set_wot_threshold(dev,wot_threshold);
390 if (tslib_parse_vars(&info->module, raw_vars, NR_VARS, params)) {
395 /* We need the intial values the touchscreen repots with no touch input for
398 ret = read(dev->fd, &input, sizeof(input));
401 memcpy(info->nulls, input.field, H_FIELDS * V_FIELDS * sizeof(uint16_t));
403 return &(info->module);
406 #ifndef TSLIB_STATIC_CY8MRLN_MODULE
407 TSLIB_MODULE_INIT(cy8mrln_palmpre_mod_init);