Merge openembedded@openembedded.bkbits.net:packages
authorChris Larson <clarson@kergoth.com>
Fri, 30 Jan 2004 06:09:28 +0000 (06:09 +0000)
committerChris Larson <clarson@kergoth.com>
Fri, 30 Jan 2004 06:09:28 +0000 (06:09 +0000)
into direwolf.itg.ti.com:/home/kergoth/coding/projects/user/oe-metadata/packages

2004/01/30 00:08:43-06:00 ti.com!kergoth
tslib patch cleanup.. making the raw patches, among others, apply on top of the new patch from Andrew Zabolotny.

BKrev: 4019f518rIvSI5i-3tsO1t0-Jg0OFg

tslib/tslib.oe
tslib/tslib/doc.patch [moved from tslib/tslib/configure.patch with 100% similarity]
tslib/tslib/pthres.patch
tslib/tslib/raw-hwread.patch [moved from tslib/tslib/envvar_doc.patch with 100% similarity]
tslib/tslib/raw.patch
tslib/tslib/zap.patch

index 7303fe9..cc62df3 100644 (file)
@@ -5,16 +5,16 @@ RDEPENDS = libc6
 
 SRC_URI = cvs://cvs:@pubcvs.arm.linux.org.uk/mnt/src/cvsroot;module=tslib
 SRC_URI_append=" file://${FILESDIR}/automake.patch;patch=1"
+SRC_URI_append=" file://${FILESDIR}/doc.patch;patch=1"
 SRC_URI_append=" file://${FILESDIR}/zap.patch;patch=1"
 SRC_URI_append=" file://${FILESDIR}/pthres.patch;patch=1"
+SRC_URI_append=" file://${FILESDIR}/raw.patch;patch=1"
+SRC_URI_append=" file://${FILESDIR}/raw-hwread.patch;patch=1"
 #SRC_URI_append=" file://${FILESDIR}/collie-module.patch;patch=1"
-#SRC_URI_append=" file://${FILESDIR}/configure.patch;patch=1"
 #SRC_URI_append=" file://${FILESDIR}/devfs.patch;patch=1"
-#SRC_URI_append=" file://${FILESDIR}/envvar_doc.patch;patch=1"
 #SRC_URI_append=" file://${FILESDIR}/event1.patch;patch=1"
 #SRC_URI_append=" file://${FILESDIR}/multievent.patch;patch=1"
 #SRC_URI_append=" file://${FILESDIR}/pointercal.patch;patch=1"
-#SRC_URI_append=" file://${FILESDIR}/raw.patch;patch=1"
 #SRC_URI_append=" file://${FILESDIR}/ts_calibrate.patch;patch=1"
 S = ${WORKDIR}/${PN}
 
index e69de29..b4bafcb 100644 (file)
@@ -0,0 +1,295 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- tslib/configure.in~tslib-pthres
++++ tslib/configure.in
+@@ -10,6 +10,8 @@
+   [ "x$enableval" = "xyes" ] && PLUGINS="$PLUGINS dejitter.la", PLUGINS="$PLUGINS dejitter.la")
+ AC_ARG_ENABLE(variance, [  --enable-variance       Enable building of variance filter [default=yes]],
+   [ "x$enableval" = "xyes" ] && PLUGINS="$PLUGINS variance.la", PLUGINS="$PLUGINS variance.la")
++AC_ARG_ENABLE(pthres, [  --enable-pthres       Enable building of pthres filter [default=yes]],
++  [ "x$enableval" = "xyes" ] && PLUGINS="$PLUGINS pthres.la", PLUGINS="$PLUGINS pthres.la")
+ AC_MSG_CHECKING(--enable-debug argument)
+ AC_ARG_ENABLE(debug,    [  --enable-debug          Enable debug messages from filters [default=no]], 
+--- tslib/plugins/Makefile.am~tslib-pthres
++++ tslib/plugins/Makefile.am
+@@ -19,7 +19,7 @@
+ LIBS                  =
+ plugindir             = $(PLUGIN_DIR)
+-EXTRA_LTLIBRARIES     = variance.la dejitter.la linear.la
++EXTRA_LTLIBRARIES     = variance.la dejitter.la linear.la pthres.la
+ plugin_LTLIBRARIES    = $(PLUGINS)
+ variance_la_SOURCES   = variance.c
+@@ -30,3 +30,6 @@
+ linear_la_SOURCES     = linear.c
+ linear_la_LDFLAGS     = -module $(LTVSN)
++
++pthres_la_SOURCES     = pthres.c
++pthres_la_LDFLAGS     = -module $(LTVSN)
+--- /dev/null
++++ tslib/plugins/pthres.c
+@@ -0,0 +1,157 @@
++/*
++ *  tslib/plugins/pthres.c
++ *
++ *  Copyright (C) 2003 Texas Instruments, Inc.
++ *
++ *  Based on:
++ *    tslib/plugins/linear.c
++ *    Copyright (C) 2001 Russell King.
++ *
++ * This file is placed under the LGPL.  Please see the file
++ * COPYING for more details.
++ *
++ * Ensure a release is always pressure 0, and that a press is always >=1.
++ */
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include <limits.h>
++
++#include "tslib.h"
++#include "tslib-filter.h"
++
++struct tslib_pthres {
++      struct tslib_module_info module;
++      int     pmin;
++      int     pmax;
++};
++
++static int
++pthres_read(struct tslib_module_info *info, struct ts_sample *samp, int nr)
++{
++      struct tslib_pthres *p = (struct tslib_pthres *)info;
++      int ret;
++      static int xsave = 0, ysave = 0;
++      static int press = 0;
++
++      ret = info->next->ops->read(info->next, samp, nr);
++      if (ret >= 0) {
++              int nr = 0, i;
++              struct ts_sample *s;
++
++              for (s = samp, i = 0; i < ret; i++, s++) {
++                      if (s->pressure < p->pmin) {
++                              if (press != 0) {
++                                      /* release */
++                                      press = 0;
++                                      s->pressure = 0;
++                                      s->x = xsave;
++                                      s->y = ysave;
++                              } else {
++                                      /* release with no press, outside bounds, dropping */
++                                      int left = ret - nr - 1;
++                                      if (left > 0) {
++                                              memmove(s, s + 1, left * sizeof(struct ts_sample));
++                                              s--;
++                                              continue;
++                                      }
++                                      break;
++                              }
++                      } else {
++                              if (s->pressure > p->pmax) {
++                                      /* pressure outside bounds, dropping */
++                                      int left = ret - nr - 1;
++                                      if (left > 0) {
++                                              memmove(s, s + 1, left * sizeof(struct ts_sample));
++                                              s--;
++                                              continue;
++                                      }
++                                      break;
++                              }
++                              /* press */
++                              press = 1;
++                              xsave = s->x;
++                              ysave = s->y;
++                      }
++                      nr++;
++              }
++              return nr;
++      }
++      return ret;
++}
++
++static int pthres_fini(struct tslib_module_info *info)
++{
++      free(info);
++      return 0;
++}
++
++static const struct tslib_ops pthres_ops =
++{
++      read:           pthres_read,
++      fini:           pthres_fini,
++};
++
++static int threshold_vars(struct tslib_module_info *inf, char *str, void *data)
++{
++      struct tslib_pthres *p = (struct tslib_pthres *)inf;
++      unsigned long v;
++      int err = errno;
++
++      v = strtoul(str, NULL, 0);
++
++      if (v == ULONG_MAX && errno == ERANGE)
++              return -1;
++
++      errno = err;
++      switch ((int)data) {
++      case 0:
++              p->pmin = v;
++              break;
++
++      case 1:
++              p->pmax = v;
++              break;
++
++      default:
++              return -1;
++      }
++      return 0;
++}
++
++
++static const struct tslib_vars pthres_vars[] =
++{
++      { "pmin",       (void *)0, threshold_vars },
++      { "pmax",       (void *)1, threshold_vars }
++};
++
++#define NR_VARS (sizeof(pthres_vars) / sizeof(pthres_vars[0]))
++
++struct tslib_module_info *mod_init(struct tsdev *dev, const char *params)
++{
++
++      struct tslib_pthres *p;
++
++      p = malloc(sizeof(struct tslib_pthres));
++      if (p == NULL)
++              return NULL;
++
++      p->module.ops = &pthres_ops;
++
++      p->pmin = 1;
++      p->pmax = INT_MAX;
++
++      /*
++       * Parse the parameters.
++       */
++      if (tslib_parse_vars(&p->module, pthres_vars, NR_VARS, params)) {
++              free(p);
++              return NULL;
++      }
++
++      return &p->module;
++}
+--- tslib/etc/ts.conf~tslib-pthres
++++ tslib/etc/ts.conf
+@@ -1,3 +1,4 @@
+-module variance delta=30 pthreshold=1
+-module dejitter delta=100 pthreshold=1
++module pthres pmin=1
++module variance delta=30
++module dejitter delta=100
+ module linear
+--- tslib/plugins/variance.c~tslib-pthres
++++ tslib/plugins/variance.c
+@@ -33,7 +33,6 @@
+ struct tslib_variance {
+       struct tslib_module_info module;
+-      unsigned int pthreshold;
+       unsigned int delta;
+         struct ts_sample last;
+         struct ts_sample noise;
+@@ -62,7 +61,7 @@
+               } else if (!info->next->ops->read(info->next, &cur, 1))
+                       return count;
+-              if (cur.pressure < var->pthreshold) {
++              if (cur.pressure == 0) {
+                       /* Flush the queue immediately when the pen is just
+                        * released, otherwise the previous layer will
+                        * get the pen up notification too late. This 
+@@ -151,10 +150,6 @@
+               var->delta = v;
+               break;
+-      case 2:
+-              var->pthreshold = v;
+-              break;
+-
+       default:
+               return -1;
+       }
+@@ -164,7 +159,6 @@
+ static const struct tslib_vars variance_vars[] =
+ {
+       { "delta",      (void *)1, variance_limit },
+-      { "pthreshold", (void *)2, variance_limit }
+ };
+ #define NR_VARS (sizeof(variance_vars) / sizeof(variance_vars[0]))
+@@ -180,7 +174,6 @@
+       var->module.ops = &variance_ops;
+       var->delta = 30;
+-      var->pthreshold = 1;
+       var->flags = 0;
+       if (tslib_parse_vars(&var->module, variance_vars, NR_VARS, params)) {
+--- tslib/plugins/dejitter.c~tslib-pthres
++++ tslib/plugins/dejitter.c
+@@ -63,7 +63,6 @@
+ struct tslib_dejitter {
+       struct tslib_module_info module;
+-      unsigned int pthreshold;
+       unsigned int delta;
+       unsigned int x;
+       unsigned int y;
+@@ -110,7 +109,7 @@
+       ret = info->next->ops->read(info->next, samp, nr);
+       for (s = samp; ret > 0; s++, ret--) {
+-              if (s->pressure < djt->pthreshold) {
++              if (s->pressure == 0) {
+                       /*
+                        * Pen was released. Reset the state and
+                        * forget all history events.
+@@ -184,10 +183,6 @@
+               djt->delta = v;
+               break;
+-      case 2:
+-              djt->pthreshold = v;
+-              break;
+-
+       default:
+               return -1;
+       }
+@@ -197,7 +192,6 @@
+ static const struct tslib_vars dejitter_vars[] =
+ {
+       { "delta",      (void *)1, dejitter_limit },
+-      { "pthreshold", (void *)2, dejitter_limit }
+ };
+ #define NR_VARS (sizeof(dejitter_vars) / sizeof(dejitter_vars[0]))
+@@ -213,7 +207,6 @@
+       djt->module.ops = &dejitter_ops;
+       djt->delta = 100;
+-      djt->pthreshold = 1;
+         djt->head = 0;
+       if (tslib_parse_vars(&djt->module, dejitter_vars, NR_VARS, params)) {
index e69de29..8f7f0df 100644 (file)
@@ -0,0 +1,923 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- tslib/src/tslib-private.h~raw
++++ tslib/src/tslib-private.h
+@@ -21,6 +21,9 @@
+ struct tsdev {
+       int fd;
+       struct tslib_module_info *list;
++      struct tslib_module_info *list_raw; /* points to position in 'list' where raw reads
++                                             come from.  default is the position of the
++                                             ts_read_raw module. */
+ #ifdef USE_INPUT_API
+       int current_x;
+       int current_y;
+@@ -29,7 +32,9 @@
+ };
+ int __ts_attach(struct tsdev *ts, struct tslib_module_info *info);
++int __ts_attach_raw(struct tsdev *ts, struct tslib_module_info *info);
+ int ts_load_module(struct tsdev *dev, const char *module, const char *params);
++int ts_load_module_raw(struct tsdev *dev, const char *module, const char *params);
+ int ts_error(const char *fmt, ...);
+ #ifdef __cplusplus
+--- tslib/src/ts_attach.c~raw
++++ tslib/src/ts_attach.c
+@@ -10,6 +10,8 @@
+  *
+  * Attach a filter to a touchscreen device.
+  */
++#include <stdlib.h>
++
+ #include "config.h"
+ #include "tslib-private.h"
+@@ -22,3 +24,30 @@
+       return 0;
+ }
++
++int __ts_attach_raw(struct tsdev *ts, struct tslib_module_info *info)
++{
++      struct tslib_module_info *next, *prev, *prev_list = ts->list_raw;
++      info->dev = ts;
++      info->next = prev_list;
++      ts->list_raw = info;
++
++      /* 
++       * ensure the last item in the normal list now points to the
++       * top of the raw list.
++       */
++
++      if (ts->list == NULL || ts->list == prev_list) { /* main list is empty, ensure it points here */
++              ts->list = info;
++              return 0;
++      }
++
++      next = ts->list;
++      
++      while (next != NULL && next != prev_list)
++              prev = next, next = prev->next;
++
++      prev->next = info;
++
++      return 0;
++}
+--- tslib/src/ts_config.c~raw
++++ tslib/src/ts_config.c
+@@ -11,6 +11,7 @@
+  * Read the configuration and load the appropriate drivers.
+  */
+ #include "config.h"
++#include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+@@ -29,8 +30,16 @@
+       return ts_load_module(ts, tok, rest);
+ }
++static int ts_opt_module_raw(struct tsdev *ts, char *rest)
++{
++      char *tok = strsep(&rest, " \t");
++
++      return ts_load_module_raw(ts, tok, rest);
++}
++
+ static struct opt options[] = {
+       { "module", ts_opt_module },
++      { "module_raw", ts_opt_module_raw },
+ };
+ #define NR_OPTS (sizeof(options) / sizeof(options[0]))
+--- tslib/src/ts_load_module.c~raw
++++ tslib/src/ts_load_module.c
+@@ -21,7 +21,7 @@
+ #include "tslib-private.h"
+-int ts_load_module(struct tsdev *ts, const char *module, const char *params)
++int __ts_load_module(struct tsdev *ts, const char *module, const char *params, int raw)
+ {
+       struct tslib_module_info * (*init)(struct tsdev *, const char *);
+       struct tslib_module_info *info;
+@@ -63,7 +63,11 @@
+       info->handle = handle;
+-      ret = __ts_attach(ts, info);
++      if (raw) {
++              ret = __ts_attach_raw(ts, info);
++      } else {
++              ret = __ts_attach(ts, info);
++      }
+       if (ret) {
+               info->ops->fini(info);
+               dlclose(handle);
+@@ -71,3 +75,14 @@
+       return ret;
+ }
++
++
++int ts_load_module(struct tsdev *ts, const char *module, const char *params)
++{
++      __ts_load_module(ts, module, params, 0);
++}
++
++int ts_load_module_raw(struct tsdev *ts, const char *module, const char *params)
++{
++      __ts_load_module(ts, module, params, 1);
++}
+--- tslib/src/ts_open.c~raw
++++ tslib/src/ts_open.c
+@@ -60,7 +60,7 @@
+                       goto close;
+ #endif /* USE_INPUT_API */
+-              __ts_attach(ts, &__ts_raw);
++              __ts_attach_raw(ts, &__ts_raw);
+       }
+       return ts;
+--- tslib/src/Makefile.am~raw
++++ tslib/src/Makefile.am
+@@ -17,7 +17,7 @@
+ lib_LTLIBRARIES  = libts.la
+ libts_la_SOURCES = ts_attach.c ts_close.c ts_config.c ts_error.c \
+                  ts_fd.c ts_load_module.c ts_open.c ts_parse_vars.c \
+-                 ts_read.c ts_read_raw.c
++                 ts_read.c ts_read_raw.c ts_read_raw_module.c
+ libts_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+                  -release $(LT_RELEASE) -export-dynamic
+ libts_la_LIBADD  = -ldl
+--- tslib/src/ts_read_raw.c~raw
++++ tslib/src/ts_read_raw.c
+@@ -1,378 +1,28 @@
+ /*
+  *  tslib/src/ts_read_raw.c
+  *
+- *  Original version:
+- *  Copyright (C) 2001 Russell King.
+- *
+- *  Rewritten for the Linux input device API:
+- *  Copyright (C) 2002 Nicolas Pitre
++ *  Copyright (C) 2003 Chris Larson.
+  *
+  * This file is placed under the LGPL.  Please see the file
+  * COPYING for more details.
+  *
+- * $Id$
+- *
+  * Read raw pressure, x, y, and timestamp from a touchscreen device.
+  */
+ #include "config.h"
+-#include <stdio.h>
++#include "tslib-private.h"
++#ifdef DEBUG
+ #include <stdlib.h>
+-#ifdef HAVE_UNISTD_H
+-#include <unistd.h>
++#include <stdio.h>
++#include <string.h>
+ #endif
+-#include <sys/time.h>
+-#include <sys/types.h>
+-
+-#ifdef USE_INPUT_API
+-#include <linux/input.h>
+-#else
+-struct ts_event  {   /* Used in UCB1x00 style touchscreens (the default) */
+-      unsigned short pressure;
+-      unsigned short x;
+-      unsigned short y;
+-      unsigned short pad;
+-      struct timeval stamp;
+-};
+-struct h3600_ts_event { /* Used in the Compaq IPAQ */
+-      unsigned short pressure;
+-      unsigned short x;
+-      unsigned short y;
+-      unsigned short pad;
+-};
+-struct mk712_ts_event { /* Used in the Hitachi Webpad */
+-      unsigned int header;
+-      unsigned int x;
+-      unsigned int y;
+-      unsigned int reserved;
+-};
+-struct arctic2_ts_event { /* Used in the IBM Arctic II */
+-      signed short pressure;
+-      signed int x;
+-      signed int y;
+-      int millisecs;
+-      int flags;
+-};
+-struct collie_ts_event { /* Used in the Sharp Zaurus SL-5000d and SL-5500 */
+-      long y;
+-      long x;
+-      long pressure;
+-      long long millisecs;
+-};
+-struct corgi_ts_event { /* Used in the Sharp Zaurus SL-C700 */
+-      short pressure;
+-      short x;
+-      short y;
+-      short millisecs;
+-};
+-#endif /* USE_INPUT_API */
+-
+-#include "tslib-private.h"
+ int ts_read_raw(struct tsdev *ts, struct ts_sample *samp, int nr)
+ {
+-#ifdef USE_INPUT_API
+-      struct input_event ev;
+-#else
+-      struct ts_event *evt;
+-      struct h3600_ts_event *hevt;
+-      struct mk712_ts_event *mevt;
+-      struct arctic2_ts_event *aevt;
+-      struct collie_ts_event *collie_evt;
+-      struct corgi_ts_event *corgi_evt;
+-      char *tseventtype=NULL;
+-      char *defaulttseventtype="UCB1x00";
+-#endif /* USE_INPUT_API */
+-      int ret;
+-      int total = 0;
+-
+-#ifdef USE_INPUT_API
+-#ifdef EV_SYN
+-        /* This version uses EV_SYN */
+-      while (total < nr) {
+-              ret = read(ts->fd, &ev, sizeof(struct input_event));
+-              if (ret < sizeof(struct input_event)) {
+-                      total = -1;
+-                      break;
+-              }
+-
+-              switch (ev.type) {
+-              case EV_SYN:
+-                      /* Fill out a new complete event */
+-                      samp->x = ts->current_x;
+-                      samp->y = ts->current_y;
+-                      samp->pressure = ts->current_p;
+-                      samp->tv = ev.time;
+-#ifdef DEBUG
+-                      fprintf(stderr,"RAW---------------------> %d %d %d %d.%d\n",
+-                              samp->x, samp->y, samp->pressure, samp->tv.tv_sec, samp->tv.tv_usec);
+-#endif /*DEBUG*/
+-                      samp++;
+-                      total++;
+-                      break;
+-              case EV_ABS:
+-                      switch (ev.code) {
+-                      case ABS_X:
+-                              ts->current_x = ev.value;
+-                              break;
+-                      case ABS_Y:
+-                              ts->current_y = ev.value;
+-                              break;
+-                      case ABS_PRESSURE:
+-                              ts->current_p = ev.value;
+-                              break;
+-                      }
+-                      break;
+-              }
+-      }
+-      ret = total;
+-#else   /* This version doesn't use EV_SYN */
+-      /* warning: maybe those static vars should be part of the tsdev struct? */
+-      static int curr_x = 0, curr_y = 0, curr_p = 0;
+-      static int got_curr_x = 0, got_curr_y = 0;
+-      int got_curr_p = 0;
+-      int next_x, next_y;
+-      int got_next_x = 0, got_next_y = 0;
+-      int got_tstamp = 0;
+-
+-      while (total < nr) {
+-              ret = read(ts->fd, &ev, sizeof(struct input_event));
+-              if (ret < sizeof(struct input_event)) break;
+-
+-              /*
+-               * We must filter events here.  We need to look for
+-               * a set of input events that will correspond to a
+-               * complete ts event.  Also need to be aware that
+-               * repeated input events are filtered out by the kernel.
+-               * 
+-               * We assume the normal sequence is: 
+-               * ABS_X -> ABS_Y -> ABS_PRESSURE
+-               * If that sequence goes backward then we got a different
+-               * ts event.  If some are missing then they didn't change.
+-               */
+-              if (ev.type == EV_ABS) switch (ev.code) {
+-              case ABS_X:
+-                      if (!got_curr_x && !got_curr_y) {
+-                              got_curr_x = 1;
+-                              curr_x = ev.value;
+-                      } else {
+-                              got_next_x = 1;
+-                              next_x = ev.value;
+-                      }
+-                      break;
+-              case ABS_Y:
+-                      if (!got_curr_y) {
+-                              got_curr_y = 1;
+-                              curr_y = ev.value;
+-                      } else {
+-                              got_next_y = 1;
+-                              next_y = ev.value;
+-                      }
+-                      break;
+-              case ABS_PRESSURE:
+-                      got_curr_p = 1;
+-                      curr_p = ev.value;
+-                      break;
+-              }
+-
+-              /* go back if we just got irrelevant events so far */
+-              if (!got_curr_x && !got_curr_y && !got_curr_p) continue;
+-
+-              /* time stamp with the first valid event only */
+-              if (!got_tstamp) {
+-                      got_tstamp = 1;
+-                      samp->tv = ev.time;
+-              }
+-
+-              if ( (!got_curr_x || !got_curr_y) && !got_curr_p &&
+-                   !got_next_x && !got_next_y ) {
+-                      /*
+-                       * The current event is not complete yet.
+-                       * Give the kernel a chance to feed us more.
+-                       */
+-                      struct timeval tv = {0, 0};
+-                      fd_set fdset;
+-                      FD_ZERO(&fdset);
+-                      FD_SET(ts->fd, &fdset);
+-                      ret = select(ts->fd+1, &fdset, NULL, NULL, &tv);
+-                      if (ret == 1) continue;
+-                      if (ret == -1) break;
+-              }
+-
+-              /* We consider having a complete ts event */
+-              samp->x = curr_x;
+-              samp->y = curr_y;
+-              samp->pressure = curr_p;
++      int result = ts->list_raw->ops->read(ts->list, samp, nr);
+ #ifdef DEBUG
+-        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
+-#endif /*DEBUG*/
+-              samp++;
+-              total++;
+-        
+-              /* get ready for next event */
+-              if (got_next_x) curr_x = next_x; else got_curr_x = 0;
+-              if (got_next_y) curr_y = next_y; else got_curr_y = 0;
+-              got_next_x = got_next_y = got_tstamp = 0;
+-      }
+-
+-      if (ret) ret = -1;
+-      if (total) ret = total;
++      fprintf(stderr,"TS_READ_RAW----> x = %d, y = %d, pressure = %d\n", samp->x, samp->y, samp->pressure);
+ #endif
+-
+-#else
+-      tseventtype = getenv("TSLIB_TSEVENTTYPE");
+-      if(tseventtype==NULL) tseventtype=defaulttseventtype;
+-
+-      if( strcmp(tseventtype,"H3600") == 0) { /* iPAQ style h3600 touchscreen events */
+-              hevt = alloca(sizeof(*hevt) * nr);
+-              ret = read(ts->fd, hevt, sizeof(*hevt) * nr);
+-              if(ret > 0) {
+-                      int nr = ret / sizeof(*hevt);
+-                      while(ret >= sizeof(*hevt)) {
+-                              samp->x = hevt->x;
+-                              samp->y = hevt->y;
+-                              samp->pressure = hevt->pressure;
+-#ifdef DEBUG
+-        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
+-#endif /*DEBUG*/
+-                              gettimeofday(&samp->tv,NULL);
+-                              samp++;
+-                              hevt++;
+-                              ret -= sizeof(*hevt);
+-                      }
+-              } else {
+-                      return -1;
+-              }
+-      } else if( strcmp(tseventtype,"MK712") == 0) { /* Hitachi Webpad events */
+-              mevt = alloca(sizeof(*mevt) * nr);
+-              ret = read(ts->fd, mevt, sizeof(*mevt) * nr);
+-              if(ret > 0) {
+-                      int nr = ret / sizeof(*mevt);
+-                      while(ret >= sizeof(*mevt)) {
+-                              samp->x = (short)mevt->x;
+-                              samp->y = (short)mevt->y;
+-                              if(mevt->header==0)
+-                                      samp->pressure=1;
+-                              else
+-                                      samp->pressure=0;
+-#ifdef DEBUG
+-        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
+-#endif /*DEBUG*/
+-                              gettimeofday(&samp->tv,NULL);
+-                              samp++;
+-                              mevt++;
+-                              ret -= sizeof(*mevt);
+-                      }
+-              } else {
+-                      return -1;
+-              }
+-
+-      } else if( strcmp(tseventtype,"ARCTIC2") == 0) { /* IBM Arctic II events */
+-              aevt = alloca(sizeof(*aevt) * nr);
+-              ret = read(ts->fd, aevt, sizeof(*aevt) * nr);
+-              if(ret > 0) {
+-                      int nr = ret / sizeof(*aevt);
+-                      while(ret >= sizeof(*aevt)) {
+-                              samp->x = (short)aevt->x;
+-                              samp->y = (short)aevt->y;
+-                              samp->pressure = aevt->pressure;
+-#ifdef DEBUG
+-        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
+-#endif /*DEBUG*/
+-                              gettimeofday(&samp->tv,NULL);
+-                              samp++;
+-                              aevt++;
+-                              ret -= sizeof(*aevt);
+-                      }
+-              } else {
+-                      return -1;
+-              }
+-
+-      } else if( strcmp(tseventtype,"COLLIE") == 0) { /* Sharp Zaurus SL-5000d/5500 events */
+-              collie_evt = alloca(sizeof(*collie_evt) * nr);
+-              ret = read(ts->fd, collie_evt, sizeof(*collie_evt) * nr);
+-              if(ret > 0) {
+-                      int nr = ret / sizeof(*collie_evt);
+-                      while(ret >= sizeof(*collie_evt)) {
+-                              samp->x = collie_evt->x;
+-                              samp->y = collie_evt->y;
+-                              samp->pressure = collie_evt->pressure;
+-#ifdef DEBUG
+-        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
+-#endif /*DEBUG*/
+-                              samp->tv.tv_usec = collie_evt->millisecs % 1000;
+-                              samp->tv.tv_sec = collie_evt->millisecs / 1000;
+-                              samp++;
+-                              collie_evt++;
+-                              ret -= sizeof(*collie_evt);
+-                      }
+-              } else {
+-                      return -1;
+-              }
+-
+-      } else if( strcmp(tseventtype,"CORGI") == 0) { /* Sharp Zaurus SL-C700 events */
+-              corgi_evt = alloca(sizeof(*corgi_evt) * nr);
+-              ret = read(ts->fd, corgi_evt, sizeof(*corgi_evt) * nr);
+-              if(ret > 0) {
+-                      int nr = ret / sizeof(*corgi_evt);
+-                      while(ret >= sizeof(*corgi_evt)) {
+-                              samp->x = corgi_evt->x;
+-                              samp->y = corgi_evt->y;
+-                              samp->pressure = corgi_evt->pressure;
+-#ifdef DEBUG
+-        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
+-#endif /*DEBUG*/
+-                              samp->tv.tv_usec = corgi_evt->millisecs % 1000;
+-                              samp->tv.tv_sec = corgi_evt->millisecs / 1000;
+-                              samp++;
+-                              corgi_evt++;
+-                              ret -= sizeof(*corgi_evt);
+-                      }
+-              } else {
+-                      return -1;
+-              }
+-
+-      } else { /* Use normal UCB1x00 type events */
+-              evt = alloca(sizeof(*evt) * nr);
+-              ret = read(ts->fd, evt, sizeof(*evt) * nr);
+-              if(ret > 0) {
+-                      int nr = ret / sizeof(*evt);
+-                      while(ret >= sizeof(*evt)) {
+-                              samp->x = evt->x;
+-                              samp->y = evt->y;
+-                              samp->pressure = evt->pressure;
+-#ifdef DEBUG
+-        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
+-#endif /*DEBUG*/
+-                              samp->tv.tv_usec = evt->stamp.tv_usec;
+-                              samp->tv.tv_sec = evt->stamp.tv_sec;
+-                              samp++;
+-                              evt++;
+-                              ret -= sizeof(*evt);
+-                      }
+-              } else {
+-                      return -1;
+-              }
+-      }
+-      ret = nr;
+-#endif /* USE_INPUT_API */
+-
+-      return ret;
+-}
+-
+-static int __ts_read_raw(struct tslib_module_info *inf, struct ts_sample *samp, int nr)
+-{
+-      return ts_read_raw(inf->dev, samp, nr);
++      return result;
+ }
+-
+-static const struct tslib_ops __ts_raw_ops =
+-{
+-      read:   __ts_read_raw,
+-};
+-
+-struct tslib_module_info __ts_raw =
+-{
+-      next:   NULL,
+-      ops:    &__ts_raw_ops,
+-};
+--- /dev/null
++++ tslib/src/ts_read_raw_module.c
+@@ -0,0 +1,374 @@
++/*
++ *  tslib/src/ts_read_raw_module.c
++ *
++ *  Original version:
++ *  Copyright (C) 2001 Russell King.
++ *
++ *  Rewritten for the Linux input device API:
++ *  Copyright (C) 2002 Nicolas Pitre
++ *
++ * This file is placed under the LGPL.  Please see the file
++ * COPYING for more details.
++ *
++ * $Id$
++ *
++ * Read raw pressure, x, y, and timestamp from a touchscreen device.
++ */
++#include "config.h"
++
++#include <stdio.h>
++
++#include <stdlib.h>
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <sys/time.h>
++#include <sys/types.h>
++
++#ifdef USE_INPUT_API
++#include <linux/input.h>
++#else
++struct ts_event  {   /* Used in UCB1x00 style touchscreens (the default) */
++      unsigned short pressure;
++      unsigned short x;
++      unsigned short y;
++      unsigned short pad;
++      struct timeval stamp;
++};
++struct h3600_ts_event { /* Used in the Compaq IPAQ */
++      unsigned short pressure;
++      unsigned short x;
++      unsigned short y;
++      unsigned short pad;
++};
++struct mk712_ts_event { /* Used in the Hitachi Webpad */
++      unsigned int header;
++      unsigned int x;
++      unsigned int y;
++      unsigned int reserved;
++};
++struct arctic2_ts_event { /* Used in the IBM Arctic II */
++      signed short pressure;
++      signed int x;
++      signed int y;
++      int millisecs;
++      int flags;
++};
++struct collie_ts_event { /* Used in the Sharp Zaurus SL-5000d and SL-5500 */
++      long y;
++      long x;
++      long pressure;
++      long long millisecs;
++};
++struct corgi_ts_event { /* Used in the Sharp Zaurus SL-C700 */
++      short pressure;
++      short x;
++      short y;
++      short millisecs;
++};
++#endif /* USE_INPUT_API */
++
++#include "tslib-private.h"
++
++static int __ts_read_raw(struct tslib_module_info *inf, struct ts_sample *samp, int nr)
++{
++      struct tsdev *ts = inf->dev;
++#ifdef USE_INPUT_API
++      struct input_event ev;
++#else
++      struct ts_event *evt;
++      struct h3600_ts_event *hevt;
++      struct mk712_ts_event *mevt;
++      struct arctic2_ts_event *aevt;
++      struct collie_ts_event *collie_evt;
++      struct corgi_ts_event *corgi_evt;
++      char *tseventtype=NULL;
++      char *defaulttseventtype="UCB1x00";
++#endif /* USE_INPUT_API */
++      int ret;
++      int total = 0;
++
++#ifdef USE_INPUT_API
++#ifdef EV_SYN
++        /* This version uses EV_SYN */
++      while (total < nr) {
++              ret = read(ts->fd, &ev, sizeof(struct input_event));
++              if (ret < sizeof(struct input_event)) {
++                      total = -1;
++                      break;
++              }
++
++              switch (ev.type) {
++              case EV_SYN:
++                      /* Fill out a new complete event */
++                      samp->x = ts->current_x;
++                      samp->y = ts->current_y;
++                      samp->pressure = ts->current_p;
++                      samp->tv = ev.time;
++#ifdef DEBUG
++                      fprintf(stderr,"RAW---------------------> %d %d %d %d.%d\n",
++                              samp->x, samp->y, samp->pressure, samp->tv.tv_sec, samp->tv.tv_usec);
++#endif /*DEBUG*/
++                      samp++;
++                      total++;
++                      break;
++              case EV_ABS:
++                      switch (ev.code) {
++                      case ABS_X:
++                              ts->current_x = ev.value;
++                              break;
++                      case ABS_Y:
++                              ts->current_y = ev.value;
++                              break;
++                      case ABS_PRESSURE:
++                              ts->current_p = ev.value;
++                              break;
++                      }
++                      break;
++              }
++      }
++      ret = total;
++#else   /* This version doesn't use EV_SYN */
++      /* warning: maybe those static vars should be part of the tsdev struct? */
++      static int curr_x = 0, curr_y = 0, curr_p = 0;
++      static int got_curr_x = 0, got_curr_y = 0;
++      int got_curr_p = 0;
++      int next_x, next_y;
++      int got_next_x = 0, got_next_y = 0;
++      int got_tstamp = 0;
++
++      while (total < nr) {
++              ret = read(ts->fd, &ev, sizeof(struct input_event));
++              if (ret < sizeof(struct input_event)) break;
++
++              /*
++               * We must filter events here.  We need to look for
++               * a set of input events that will correspond to a
++               * complete ts event.  Also need to be aware that
++               * repeated input events are filtered out by the kernel.
++               * 
++               * We assume the normal sequence is: 
++               * ABS_X -> ABS_Y -> ABS_PRESSURE
++               * If that sequence goes backward then we got a different
++               * ts event.  If some are missing then they didn't change.
++               */
++              if (ev.type == EV_ABS) switch (ev.code) {
++              case ABS_X:
++                      if (!got_curr_x && !got_curr_y) {
++                              got_curr_x = 1;
++                              curr_x = ev.value;
++                      } else {
++                              got_next_x = 1;
++                              next_x = ev.value;
++                      }
++                      break;
++              case ABS_Y:
++                      if (!got_curr_y) {
++                              got_curr_y = 1;
++                              curr_y = ev.value;
++                      } else {
++                              got_next_y = 1;
++                              next_y = ev.value;
++                      }
++                      break;
++              case ABS_PRESSURE:
++                      got_curr_p = 1;
++                      curr_p = ev.value;
++                      break;
++              }
++
++              /* go back if we just got irrelevant events so far */
++              if (!got_curr_x && !got_curr_y && !got_curr_p) continue;
++
++              /* time stamp with the first valid event only */
++              if (!got_tstamp) {
++                      got_tstamp = 1;
++                      samp->tv = ev.time;
++              }
++
++              if ( (!got_curr_x || !got_curr_y) && !got_curr_p &&
++                   !got_next_x && !got_next_y ) {
++                      /*
++                       * The current event is not complete yet.
++                       * Give the kernel a chance to feed us more.
++                       */
++                      struct timeval tv = {0, 0};
++                      fd_set fdset;
++                      FD_ZERO(&fdset);
++                      FD_SET(ts->fd, &fdset);
++                      ret = select(ts->fd+1, &fdset, NULL, NULL, &tv);
++                      if (ret == 1) continue;
++                      if (ret == -1) break;
++              }
++
++              /* We consider having a complete ts event */
++              samp->x = curr_x;
++              samp->y = curr_y;
++              samp->pressure = curr_p;
++#ifdef DEBUG
++        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
++#endif /*DEBUG*/
++              samp++;
++              total++;
++        
++              /* get ready for next event */
++              if (got_next_x) curr_x = next_x; else got_curr_x = 0;
++              if (got_next_y) curr_y = next_y; else got_curr_y = 0;
++              got_next_x = got_next_y = got_tstamp = 0;
++      }
++
++      if (ret) ret = -1;
++      if (total) ret = total;
++#endif
++
++#else
++      tseventtype = getenv("TSLIB_TSEVENTTYPE");
++      if(tseventtype==NULL) tseventtype=defaulttseventtype;
++
++      if( strcmp(tseventtype,"H3600") == 0) { /* iPAQ style h3600 touchscreen events */
++              hevt = alloca(sizeof(*hevt) * nr);
++              ret = read(ts->fd, hevt, sizeof(*hevt) * nr);
++              if(ret > 0) {
++                      int nr = ret / sizeof(*hevt);
++                      while(ret >= sizeof(*hevt)) {
++                              samp->x = hevt->x;
++                              samp->y = hevt->y;
++                              samp->pressure = hevt->pressure;
++#ifdef DEBUG
++        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
++#endif /*DEBUG*/
++                              gettimeofday(&samp->tv,NULL);
++                              samp++;
++                              hevt++;
++                              ret -= sizeof(*hevt);
++                      }
++              } else {
++                      return -1;
++              }
++      } else if( strcmp(tseventtype,"MK712") == 0) { /* Hitachi Webpad events */
++              mevt = alloca(sizeof(*mevt) * nr);
++              ret = read(ts->fd, mevt, sizeof(*mevt) * nr);
++              if(ret > 0) {
++                      int nr = ret / sizeof(*mevt);
++                      while(ret >= sizeof(*mevt)) {
++                              samp->x = (short)mevt->x;
++                              samp->y = (short)mevt->y;
++                              if(mevt->header==0)
++                                      samp->pressure=1;
++                              else
++                                      samp->pressure=0;
++#ifdef DEBUG
++        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
++#endif /*DEBUG*/
++                              gettimeofday(&samp->tv,NULL);
++                              samp++;
++                              mevt++;
++                              ret -= sizeof(*mevt);
++                      }
++              } else {
++                      return -1;
++              }
++
++      } else if( strcmp(tseventtype,"ARCTIC2") == 0) { /* IBM Arctic II events */
++              aevt = alloca(sizeof(*aevt) * nr);
++              ret = read(ts->fd, aevt, sizeof(*aevt) * nr);
++              if(ret > 0) {
++                      int nr = ret / sizeof(*aevt);
++                      while(ret >= sizeof(*aevt)) {
++                              samp->x = (short)aevt->x;
++                              samp->y = (short)aevt->y;
++                              samp->pressure = aevt->pressure;
++#ifdef DEBUG
++        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
++#endif /*DEBUG*/
++                              gettimeofday(&samp->tv,NULL);
++                              samp++;
++                              aevt++;
++                              ret -= sizeof(*aevt);
++                      }
++              } else {
++                      return -1;
++              }
++
++      } else if( strcmp(tseventtype,"COLLIE") == 0) { /* Sharp Zaurus SL-5000d/5500 events */
++              collie_evt = alloca(sizeof(*collie_evt) * nr);
++              ret = read(ts->fd, collie_evt, sizeof(*collie_evt) * nr);
++              if(ret > 0) {
++                      int nr = ret / sizeof(*collie_evt);
++                      while(ret >= sizeof(*collie_evt)) {
++                              samp->x = collie_evt->x;
++                              samp->y = collie_evt->y;
++                              samp->pressure = collie_evt->pressure;
++#ifdef DEBUG
++        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
++#endif /*DEBUG*/
++                              samp->tv.tv_usec = collie_evt->millisecs % 1000;
++                              samp->tv.tv_sec = collie_evt->millisecs / 1000;
++                              samp++;
++                              collie_evt++;
++                              ret -= sizeof(*collie_evt);
++                      }
++              } else {
++                      return -1;
++              }
++
++      } else if( strcmp(tseventtype,"CORGI") == 0) { /* Sharp Zaurus SL-C700 events */
++              corgi_evt = alloca(sizeof(*corgi_evt) * nr);
++              ret = read(ts->fd, corgi_evt, sizeof(*corgi_evt) * nr);
++              if(ret > 0) {
++                      int nr = ret / sizeof(*corgi_evt);
++                      while(ret >= sizeof(*corgi_evt)) {
++                              samp->x = corgi_evt->x;
++                              samp->y = corgi_evt->y;
++                              samp->pressure = corgi_evt->pressure;
++#ifdef DEBUG
++        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
++#endif /*DEBUG*/
++                              samp->tv.tv_usec = corgi_evt->millisecs % 1000;
++                              samp->tv.tv_sec = corgi_evt->millisecs / 1000;
++                              samp++;
++                              corgi_evt++;
++                              ret -= sizeof(*corgi_evt);
++                      }
++              } else {
++                      return -1;
++              }
++
++      } else { /* Use normal UCB1x00 type events */
++              evt = alloca(sizeof(*evt) * nr);
++              ret = read(ts->fd, evt, sizeof(*evt) * nr);
++              if(ret > 0) {
++                      int nr = ret / sizeof(*evt);
++                      while(ret >= sizeof(*evt)) {
++                              samp->x = evt->x;
++                              samp->y = evt->y;
++                              samp->pressure = evt->pressure;
++#ifdef DEBUG
++        fprintf(stderr,"RAW---------------------------> %d %d %d\n",samp->x,samp->y,samp->pressure);
++#endif /*DEBUG*/
++                              samp->tv.tv_usec = evt->stamp.tv_usec;
++                              samp->tv.tv_sec = evt->stamp.tv_sec;
++                              samp++;
++                              evt++;
++                              ret -= sizeof(*evt);
++                      }
++              } else {
++                      return -1;
++              }
++      }
++      ret = nr;
++#endif /* USE_INPUT_API */
++
++      return ret;
++}
++
++static const struct tslib_ops __ts_raw_ops =
++{
++      read:   __ts_read_raw,
++};
++
++struct tslib_module_info __ts_raw =
++{
++      next:   NULL,
++      ops:    &__ts_raw_ops,
++};
index e69de29..1c57b7b 100644 (file)
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- tslib/etc/ts.conf~tslib
++++ tslib/etc/ts.conf
+@@ -1,3 +1,3 @@
+-module variance xlimit=50 ylimit=50 pthreshold=1
+-module dejitter xdelta=10 ydelta=10 pthreshold=1
++module variance delta=30 pthreshold=1
++module dejitter delta=100 pthreshold=1
+ module linear
+--- tslib/plugins/dejitter.c~tslib
++++ tslib/plugins/dejitter.c
+@@ -1,5 +1,5 @@
+ /*
+- *  tslib/plugins/threshold.c
++ *  tslib/plugins/dejitter.c
+  *
+  *  Copyright (C) 2001 Russell King.
+  *
+@@ -8,7 +8,19 @@
+  *
+  * $Id$
+  *
+- * Threshold filter for touchscreen values
++ * Problem: some touchscreens read the X/Y values from ADC with a
++ * great level of noise in their lowest bits. This produces "jitter"
++ * in touchscreen output, e.g. even if we hold the stylus still,
++ * we get a great deal of X/Y coordinate pairs that are close enough
++ * but not equal. Also if we try to draw a straight line in a painter
++ * program, we'll get a line full of spikes.
++ *
++ * Solution: we apply a smoothing filter on the last several values
++ * thus excluding spikes from output. If we detect a substantial change
++ * in coordinates, we reset the backlog of pen positions, thus avoiding
++ * smoothing coordinates that are not supposed to be smoothed. This
++ * supposes all noise has been filtered by the lower-level filter,
++ * e.g. by the "variance" module.
+  */
+ #include <errno.h>
+ #include <stdlib.h>
+@@ -20,74 +32,144 @@
+ #include "tslib.h"
+ #include "tslib-filter.h"
+-#define NR_LAST       4
++/**
++ * This filter works as follows: we keep track of latest N samples,
++ * and average them with certain weights. The oldest samples have the
++ * least weight and the most recent samples have the most weight.
++ * This helps remove the jitter and at the same time doesn't influence
++ * responsivity because for each input sample we generate one output
++ * sample; pen movement becomes just somehow more smooth.
++ */
+-struct tslib_threshold {
+-      struct tslib_module_info        module;
+-      int                     pthreshold;
+-      int                     xdelta;
+-      int                     ydelta;
+-      int                     delta2;
+-      unsigned int                    x;
+-      unsigned int                    y;
+-      unsigned int                    down;
++#define NR_SAMPHISTLEN        4
++
++/* To keep things simple (avoiding division) we ensure that
++ * SUM(weight) = power-of-two. Also we must know how to approximate
++ * measurements when we have less than NR_SAMPHISTLEN samples.
++ */
++static const unsigned char weight [NR_SAMPHISTLEN - 1][NR_SAMPHISTLEN + 1] =
++{
++      /* The last element is pow2(SUM(0..3)) */
++      { 5, 3, 0, 0, 3 },      /* When we have 2 samples ... */
++      { 8, 5, 3, 0, 4 },      /* When we have 3 samples ... */
++      { 6, 4, 3, 3, 4 },      /* When we have 4 samples ... */
+ };
+-static int threshold_read(struct tslib_module_info *info, struct ts_sample *samp, int nr)
++struct ts_hist {
++      int x;
++      int y;
++      int p;
++};
++
++struct tslib_dejitter {
++      struct tslib_module_info module;
++      unsigned int pthreshold;
++      unsigned int delta;
++      unsigned int x;
++      unsigned int y;
++      unsigned int down;
++      unsigned int nr;
++      unsigned int head;
++      struct ts_hist hist[NR_SAMPHISTLEN];
++};
++
++static int sqr (int x)
+ {
+-      struct tslib_threshold *thr = (struct tslib_threshold *)info;
++      return x * x;
++}
++
++static void average (struct tslib_dejitter *djt, struct ts_sample *samp)
++{
++      const unsigned char *w;
++      int sn = djt->head;
++      int i, x = 0, y = 0, p = 0;
++
++        w = weight [djt->nr - 2];
++
++      for (i = 0; i < djt->nr; i++) {
++              x += djt->hist [sn].x * w [i];
++              y += djt->hist [sn].y * w [i];
++              p += djt->hist [sn].p * w [i];
++              sn = (sn - 1) & (NR_SAMPHISTLEN - 1);
++      }
++
++      samp->x = x >> w [NR_SAMPHISTLEN];
++      samp->y = y >> w [NR_SAMPHISTLEN];
++      samp->pressure = p >> w [NR_SAMPHISTLEN];
++#ifdef DEBUG
++      fprintf(stderr,"DEJITTER----------------> %d %d %d\n",
++              samp->x, samp->y, samp->pressure);
++#endif
++}
++
++static int dejitter_read(struct tslib_module_info *info, struct ts_sample *samp, int nr)
++{
++        struct tslib_dejitter *djt = (struct tslib_dejitter *)info;
+       struct ts_sample *s;
+-      int ret;
++      int count = 0, ret;
+       ret = info->next->ops->read(info->next, samp, nr);
+-      if (ret >= 0) {
+-              int nr = 0;
++      for (s = samp; ret > 0; s++, ret--) {
++              if (s->pressure < djt->pthreshold) {
++                      /*
++                       * Pen was released. Reset the state and
++                       * forget all history events.
++                       */
++                      djt->nr = 0;
++                      samp [count++] = *s;
++                        continue;
++              }
+-              for (s = samp; s < samp + ret; s++) {
+-                      int dr2;
++                /* If the pen moves too fast, reset the backlog. */
++              if (djt->nr) {
++                      int prev = (djt->head - 1) & (NR_SAMPHISTLEN - 1);
++                      if (sqr (s->x - djt->hist [prev].x) +
++                          sqr (s->y - djt->hist [prev].y) > djt->delta) {
+ #ifdef DEBUG
+-                      fprintf(stderr,"BEFORE DEJITTER---------------> %d %d %d\n",s->x,s->y,s->pressure);
+-#endif /*DEBUG*/
+-                      thr->down = (s->pressure >= thr->pthreshold);
+-                      if (thr->down) {
+-                              dr2 = (thr->x - s->x)*(thr->x - s->x) 
+-                                      + (thr->y - s->y)*(thr->y - s->y);
+-                              if(dr2 < thr->delta2) {
+-                                      s->x = thr->x;
+-                                      s->y = thr->y;
+-                              } else {
+-                                      thr->x = s->x;
+-                                      thr->y = s->y;
+-                              }
+-
+-                      } else {
+-                              s->x = thr->x;
+-                              s->y = thr->y;
++                              fprintf (stderr, "DEJITTER: pen movement exceeds threshold\n");
++#endif
++                                djt->nr = 0;
+                       }
++              }
++              djt->hist[djt->head].x = s->x;
++              djt->hist[djt->head].y = s->y;
++              djt->hist[djt->head].p = s->pressure;
++              if (djt->nr < NR_SAMPHISTLEN)
++                      djt->nr++;
+-                      samp[nr++] = *s;
++              /* We'll pass through the very first sample since
++               * we can't average it (no history yet).
++               */
++              if (djt->nr == 1)
++                      samp [count] = *s;
++              else {
++                      average (djt, samp + count);
++                      samp [count].tv = s->tv;
+               }
++              count++;
+-              ret = nr;
++              djt->head = (djt->head + 1) & (NR_SAMPHISTLEN - 1);
+       }
+-      return ret;
++
++      return count;
+ }
+-static int threshold_fini(struct tslib_module_info *info)
++static int dejitter_fini(struct tslib_module_info *info)
+ {
+       free(info);
++      return 0;
+ }
+-static const struct tslib_ops threshold_ops =
++static const struct tslib_ops dejitter_ops =
+ {
+-      read:   threshold_read,
+-      fini:   threshold_fini,
++      read:   dejitter_read,
++      fini:   dejitter_fini,
+ };
+-static int threshold_limit(struct tslib_module_info *inf, char *str, void *data)
++static int dejitter_limit(struct tslib_module_info *inf, char *str, void *data)
+ {
+-      struct tslib_threshold *thr = (struct tslib_threshold *)inf;
++      struct tslib_dejitter *djt = (struct tslib_dejitter *)inf;
+       unsigned long v;
+       int err = errno;
+@@ -99,15 +181,11 @@
+       errno = err;
+       switch ((int)data) {
+       case 1:
+-              thr->xdelta = v;
++              djt->delta = v;
+               break;
+       case 2:
+-              thr->ydelta = v;
+-              break;
+-
+-      case 3:
+-              thr->pthreshold = v;
++              djt->pthreshold = v;
+               break;
+       default:
+@@ -116,35 +194,33 @@
+       return 0;
+ }
+-static const struct tslib_vars threshold_vars[] =
++static const struct tslib_vars dejitter_vars[] =
+ {
+-      { "xdelta",     (void *)1, threshold_limit },
+-      { "ydelta",     (void *)2, threshold_limit },
+-      { "pthreshold", (void *)3, threshold_limit }
++      { "delta",      (void *)1, dejitter_limit },
++      { "pthreshold", (void *)2, dejitter_limit }
+ };
+-//#define NR_VARS (sizeof(threshold_vars) / sizeof(threshold_vars[0]))
+-#define NR_VARS 3
++#define NR_VARS (sizeof(dejitter_vars) / sizeof(dejitter_vars[0]))
+ struct tslib_module_info *mod_init(struct tsdev *dev, const char *params)
+ {
+-      struct tslib_threshold *thr;
++      struct tslib_dejitter *djt;
+-      thr = malloc(sizeof(struct tslib_threshold));
+-      if (thr == NULL)
++      djt = malloc(sizeof(struct tslib_dejitter));
++      if (djt == NULL)
+               return NULL;
+-      thr->module.ops = &threshold_ops;
++      djt->module.ops = &dejitter_ops;
+-      thr->xdelta = 10;
+-      thr->ydelta = 10;
+-      thr->pthreshold = 100;
++      djt->delta = 100;
++      djt->pthreshold = 1;
++        djt->head = 0;
+-      if (tslib_parse_vars(&thr->module, threshold_vars, NR_VARS, params)) {
+-              free(thr);
++      if (tslib_parse_vars(&djt->module, dejitter_vars, NR_VARS, params)) {
++              free(djt);
+               return NULL;
+       }
+-      thr->delta2 = (thr->xdelta)*(thr->xdelta) + (thr->ydelta)*(thr->ydelta);
++      djt->delta = sqr (djt->delta);
+-      return &thr->module;
++      return &djt->module;
+ }
+--- tslib/plugins/linear.c~tslib
++++ tslib/plugins/linear.c
+@@ -74,6 +74,7 @@
+ static int linear_fini(struct tslib_module_info *info)
+ {
+       free(info);
++      return 0;
+ }
+ static const struct tslib_ops linear_ops =
+@@ -104,7 +105,6 @@
+       struct tslib_linear *lin;
+       struct stat sbuf;
+       int pcal_fd;
+-      int a[7];
+       char pcalbuf[200];
+       int index;
+       char *tokptr;
+--- tslib/plugins/variance.c~tslib
++++ tslib/plugins/variance.c
+@@ -8,165 +8,124 @@
+  *
+  * $Id$
+  *
+- * Variance filter for touchscreen values
++ * Variance filter for touchscreen values.
++ *
++ * Problem: some touchscreens are sampled very roughly, thus even if
++ * you hold the pen still, the samples can differ, sometimes substantially.
++ * The worst happens when electric noise during sampling causes the result
++ * to be substantially different from the real pen position; this causes
++ * the mouse cursor to suddenly "jump" and then return back.
++ *
++ * Solution: delay sampled data by one timeslot. If we see that the last
++ * sample read differs too much, we mark it as "suspicious". If next sample
++ * read is close to the sample before the "suspicious", the suspicious sample
++ * is dropped, otherwise we consider that a quick pen movement is in progress
++ * and pass through both the "suspicious" sample and the sample after it.
+  */
+ #include <errno.h>
++#include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <limits.h>
+-#include <stdio.h>
+-
+ #include "tslib.h"
+ #include "tslib-filter.h"
+-#define NR_LAST       4
+-
+ struct tslib_variance {
+-      struct tslib_module_info        module;
+-      int                             nr;
+-      unsigned int                    pthreshold;
+-      unsigned int                    xlimit;
+-      unsigned int                    ylimit;
+-      struct ts_sample                last[NR_LAST];
++      struct tslib_module_info module;
++      unsigned int pthreshold;
++      unsigned int delta;
++        struct ts_sample last;
++        struct ts_sample noise;
++      unsigned int flags;
++#define VAR_PENDOWN           0x00000001
++#define VAR_LASTVALID         0x00000002
++#define VAR_NOISEVALID                0x00000004
++#define VAR_SUBMITNOISE               0x00000008
+ };
+-/*
+- * We have 4 complete samples.  Calculate the variance between each,
+- * treating X and Y values separately.  Then pick the two with the
+- * least variance, and average them.
+- */
+-static int
+-variance_calculate(struct tslib_variance *var, struct ts_sample *samp,
+-                 struct ts_sample *s)
++static int sqr (int x)
+ {
+-      int i, j;
+-      int diff_x, min_x, i_x, j_x;
+-      int diff_y, min_y, i_y, j_y;
+-      int diff_p, min_p, i_p, j_p;
+-
+-      min_x = INT_MAX;
+-      min_y = INT_MAX;
+-      min_p = INT_MAX;
+-
+-      for (i = 0; i < var->nr - 1; i++) {
+-              for (j = i + 1; j < var->nr; j++) {
+-                      /*
+-                       * Calculate the variance between sample 'i'
+-                       * and sample 'j'.  X and Y values are treated
+-                       * separately.
+-                       */
+-                      diff_x = var->last[i].x - var->last[j].x;
+-                      if (diff_x < 0)
+-                              diff_x = -diff_x;
+-
+-                      diff_y = var->last[i].y - var->last[j].y;
+-                      if (diff_y < 0)
+-                              diff_y = -diff_y;
+-
+-                      diff_p = var->last[i].pressure - var->last[j].pressure;
+-                      if (diff_p < 0)
+-                              diff_p = -diff_p;
+-
+-                      /*
+-                       * Is the variance between any two samples too large?
+-                       */
+-                      if (diff_x > var->xlimit || diff_y > var->ylimit)
+-                              return 0;
+-
+-                      /*
+-                       * Find the minimum X variance.
+-                       */
+-                      if (min_x > diff_x) {
+-                              min_x = diff_x;
+-                              i_x = i;
+-                              j_x = j;
+-                      }
+-
+-                      /*
+-                       * Find the minimum Y variance.
+-                       */
+-                      if (min_y > diff_y) {
+-                              min_y = diff_y;
+-                              i_y = i;
+-                              j_y = j;
+-                      }
+-
+-                      if (min_p > diff_p) {
+-                              min_p = diff_p;
+-                              i_p = i;
+-                              j_p = j;
+-                      }
+-              }
+-      }
+-
+-      samp->x          = (var->last[i_x].x + var->last[j_x].x) / 2;
+-      samp->y          = (var->last[i_y].y + var->last[j_y].y) / 2;
+-      samp->pressure   = (var->last[i_p].pressure + var->last[j_p].pressure) / 2;
+-      samp->tv.tv_sec  = s->tv.tv_sec;
+-      samp->tv.tv_usec = s->tv.tv_usec;
+-
+-      return 1;
++      return x * x;
+ }
+ static int variance_read(struct tslib_module_info *info, struct ts_sample *samp, int nr)
+ {
+       struct tslib_variance *var = (struct tslib_variance *)info;
+-      struct ts_sample *s;
+-      int ret;
+-
+-      ret = info->next->ops->read(info->next, samp, nr);
+-      if (ret >= 0) {
+-              int nr = 0;
+-
+-              for (s = samp; s < samp + ret; s++) {
+-                      if (s->pressure < var->pthreshold) {
+-                              /*
+-                               * Pen was released.  Reset our state and
+-                               * pass up the release information.
+-                               */
+-//                            samp[nr].x = 0;
+-//                            samp[nr].y = 0;
+-                              samp[nr].pressure = s->pressure;
+-                              samp[nr].tv.tv_sec = s->tv.tv_sec;
+-                              samp[nr].tv.tv_usec = s->tv.tv_usec;
++      struct ts_sample cur;
++      int count = 0, dist;
+-                              nr++;
++      while (count < nr) {
++              if (var->flags & VAR_SUBMITNOISE) {
++                      cur = var->noise;
++                      var->flags &= ~VAR_SUBMITNOISE;
++              } else if (!info->next->ops->read(info->next, &cur, 1))
++                      return count;
+-                              var->nr = 0;
+-                              continue;
+-                      } else if (var->nr == -1) {
+-                              /*
+-                               * Pen was pressed.  Inform upper layers
+-                               * immediately.
+-                               */
+-                              samp[nr] = *s;
+-                              nr++;
++              if (cur.pressure < var->pthreshold) {
++                      /* Flush the queue immediately when the pen is just
++                       * released, otherwise the previous layer will
++                       * get the pen up notification too late. This 
++                       * will happen if info->next->ops->read() blocks.
++                       */
++                      if (var->flags & VAR_PENDOWN) {
++                              var->flags |= VAR_SUBMITNOISE;
++                              var->noise = cur;
+                       }
++                      /* Reset the state machine on pen up events. */
++                      var->flags &= ~(VAR_PENDOWN | VAR_NOISEVALID);
++                      /* drop the previous event.. the only way to ensure
++                       * that this release is communicated in -this- ts_read,
++                       * rather than the next -CL */
++                      var->last.pressure = cur.pressure;
++                      goto acceptsample;
++              } else
++                      var->flags |= VAR_PENDOWN;
+-                      if (var->nr >= 0) {
+-                              var->last[var->nr].x = s->x;
+-                              var->last[var->nr].y = s->y;
+-                              var->last[var->nr].pressure = s->pressure;
+-                      }
++              if (!(var->flags & VAR_LASTVALID)) {
++                      var->last = cur;
++                      var->flags |= VAR_LASTVALID;
++                      continue;
++              }
+-                      var->nr++;
++              if (var->flags & VAR_PENDOWN) {
++                      /* Compute the distance between last sample and current */
++                      dist = sqr (cur.x - var->last.x) +
++                             sqr (cur.y - var->last.y);
+-                      if (var->nr == NR_LAST) {
+-                              if (variance_calculate(var, samp + nr, s))
+-                                      nr++;
+-                              var->nr = 0;
+-                      }
++                      if (dist > var->delta) {
++                              /* Do we suspect the previous sample was a noise? */
++                              if (var->flags & VAR_NOISEVALID) {
++                                      /* Two "noises": it's just a quick pen movement */
++                                      samp [count++] = var->last = var->noise;
++                                      var->flags = (var->flags & ~VAR_NOISEVALID) |
++                                              VAR_SUBMITNOISE;
++                              } else
++                                      var->flags |= VAR_NOISEVALID;
++
++                              /* The pen jumped too far, maybe it's a noise ... */
++                              var->noise = cur;
++                              continue;
++                      } else
++                              var->flags &= ~VAR_NOISEVALID;
+               }
+-              ret = nr;
++acceptsample:
++#ifdef DEBUG
++              fprintf(stderr,"VARIANCE----------------> %d %d %d\n",
++                      var->last.x, var->last.y, var->last.pressure);
++#endif
++              samp [count++] = var->last;
++              var->last = cur;
+       }
+-      return ret;
++
++      return count;
+ }
+ static int variance_fini(struct tslib_module_info *info)
+ {
+       free(info);
++        return 0;
+ }
+ static const struct tslib_ops variance_ops =
+@@ -189,14 +148,10 @@
+       errno = err;
+       switch ((int)data) {
+       case 1:
+-              var->xlimit = v;
++              var->delta = v;
+               break;
+       case 2:
+-              var->ylimit = v;
+-              break;
+-
+-      case 3:
+               var->pthreshold = v;
+               break;
+@@ -208,9 +163,8 @@
+ static const struct tslib_vars variance_vars[] =
+ {
+-      { "xlimit",     (void *)1, variance_limit },
+-      { "ylimit",     (void *)2, variance_limit },
+-      { "pthreshold", (void *)3, variance_limit }
++      { "delta",      (void *)1, variance_limit },
++      { "pthreshold", (void *)2, variance_limit }
+ };
+ #define NR_VARS (sizeof(variance_vars) / sizeof(variance_vars[0]))
+@@ -225,15 +179,16 @@
+       var->module.ops = &variance_ops;
+-      var->nr = -1;
+-      var->xlimit = 160;
+-      var->ylimit = 160;
+-      var->pthreshold = 100;
++      var->delta = 30;
++      var->pthreshold = 1;
++      var->flags = 0;
+       if (tslib_parse_vars(&var->module, variance_vars, NR_VARS, params)) {
+               free(var);
+               return NULL;
+       }
++        var->delta = sqr (var->delta);
++
+       return &var->module;
+ }
+--- tslib/src/ts_config.c~tslib
++++ tslib/src/ts_config.c
+@@ -13,6 +13,7 @@
+ #include "config.h"
+ #include <stdio.h>
+ #include <string.h>
++#include <stdlib.h>
+ #include "tslib-private.h"
+--- tslib/src/ts_load_module.c~tslib
++++ tslib/src/ts_load_module.c
+@@ -42,6 +42,9 @@
+       strcat(fn, module);
+       strcat(fn, ".so");
++#ifdef DEBUG
++      printf ("Loading module %s\n", fn);
++#endif
+       handle = dlopen(fn, RTLD_NOW);
+       if (!handle)
+               return -1;
+--- tslib/src/ts_read.c~tslib
++++ tslib/src/ts_read.c
+@@ -40,7 +40,8 @@
+ //            samp[i] = ts_read_private_samples[i];
+ //    }
+ #ifdef DEBUG
+-      fprintf(stderr,"TS_READ----> x = %d, y = %d, pressure = %d\n", samp->x, samp->y, samp->pressure);
++      if (result)
++              fprintf(stderr,"TS_READ----> x = %d, y = %d, pressure = %d\n", samp->x, samp->y, samp->pressure);
+ #endif
+       return result;
+--- tslib/src/ts_read_raw.c~tslib
++++ tslib/src/ts_read_raw.c
+@@ -81,14 +81,53 @@
+       struct arctic2_ts_event *aevt;
+       struct collie_ts_event *collie_evt;
+       struct corgi_ts_event *corgi_evt;
++      char *tseventtype=NULL;
++      char *defaulttseventtype="UCB1x00";
+ #endif /* USE_INPUT_API */
+       int ret;
+       int total = 0;
+-      char *tseventtype=NULL;
+-      char *defaulttseventtype="UCB1x00";
+-
+ #ifdef USE_INPUT_API
++#ifdef EV_SYN
++        /* This version uses EV_SYN */
++      while (total < nr) {
++              ret = read(ts->fd, &ev, sizeof(struct input_event));
++              if (ret < sizeof(struct input_event)) {
++                      total = -1;
++                      break;
++              }
++
++              switch (ev.type) {
++              case EV_SYN:
++                      /* Fill out a new complete event */
++                      samp->x = ts->current_x;
++                      samp->y = ts->current_y;
++                      samp->pressure = ts->current_p;
++                      samp->tv = ev.time;
++#ifdef DEBUG
++                      fprintf(stderr,"RAW---------------------> %d %d %d %d.%d\n",
++                              samp->x, samp->y, samp->pressure, samp->tv.tv_sec, samp->tv.tv_usec);
++#endif /*DEBUG*/
++                      samp++;
++                      total++;
++                      break;
++              case EV_ABS:
++                      switch (ev.code) {
++                      case ABS_X:
++                              ts->current_x = ev.value;
++                              break;
++                      case ABS_Y:
++                              ts->current_y = ev.value;
++                              break;
++                      case ABS_PRESSURE:
++                              ts->current_p = ev.value;
++                              break;
++                      }
++                      break;
++              }
++      }
++      ret = total;
++#else   /* This version doesn't use EV_SYN */
+       /* warning: maybe those static vars should be part of the tsdev struct? */
+       static int curr_x = 0, curr_y = 0, curr_p = 0;
+       static int got_curr_x = 0, got_curr_y = 0;
+@@ -179,6 +218,8 @@
+       if (ret) ret = -1;
+       if (total) ret = total;
++#endif
++
+ #else
+       tseventtype = getenv("TSLIB_TSEVENTTYPE");
+       if(tseventtype==NULL) tseventtype=defaulttseventtype;
+--- tslib/src/tslib-private.h~tslib
++++ tslib/src/tslib-private.h
+@@ -21,6 +21,11 @@
+ struct tsdev {
+       int fd;
+       struct tslib_module_info *list;
++#ifdef USE_INPUT_API
++      int current_x;
++      int current_y;
++      int current_p;
++#endif
+ };
+ int __ts_attach(struct tsdev *ts, struct tslib_module_info *info);
+--- tslib/tests/fbutils.c~tslib
++++ tslib/tests/fbutils.c
+@@ -14,22 +14,34 @@
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
+ #include <sys/fcntl.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/time.h>
+-#include <linux/fb.h>
+-#include <linux/kd.h>
++
+ #include <linux/vt.h>
++#include <linux/kd.h>
++#include <linux/fb.h>
+ #include "font.h"
++#include "fbutils.h"
++
++union multiptr {
++      unsigned char *p8;
++      unsigned short *p16;
++      unsigned long *p32;
++};
+ static int con_fd, fb_fd, last_vt = -1;
+ static struct fb_fix_screeninfo fix;
+ static struct fb_var_screeninfo var;
+-static struct fb_cmap cmap;
+-static char *fbuffer;
++static unsigned char *fbuffer;
++static unsigned char **line_addr;
+ static int fb_fd=0;
++static int bytes_per_pixel;
++static unsigned colormap [256];
+ int xres, yres;
+ static char *defaultfbdevice = "/dev/fb0";
+@@ -39,26 +51,26 @@
+ int open_framebuffer(void)
+ {
+-        struct vt_stat vts;
+-        char vtname[128];
+-        int fd, nr;
+-      unsigned short col[2];
++      struct vt_stat vts;
++      char vtname[128];
++      int fd, nr;
++      unsigned y, addr;
+-      if( (fbdevice = getenv("TSLIB_FBDEVICE")) == NULL)
++      if ((fbdevice = getenv ("TSLIB_FBDEVICE")) == NULL)
+               fbdevice = defaultfbdevice;
+-      if( (consoledevice = getenv("TSLIB_CONSOLEDEVICE")) == NULL)
++      if ((consoledevice = getenv ("TSLIB_CONSOLEDEVICE")) == NULL)
+               consoledevice = defaultconsoledevice;
+-      if(strcmp(consoledevice,"none")!=0) {
+-              sprintf(vtname,"%s%d", consoledevice, 1);
+-              fd = open(vtname, O_WRONLY);
++      if (strcmp (consoledevice, "none") != 0) {
++              sprintf (vtname,"%s%d", consoledevice, 1);
++              fd = open (vtname, O_WRONLY);
+               if (fd < 0) {
+                       perror("open consoledevice");
+                       return -1;
+               }
+-              if (ioctl(fd, VT_OPENQRY, &nr) < 0) {
++              if (ioctl(fd, VT_OPENQRY, &nr) < 0) {
+                       perror("ioctl VT_OPENQRY");
+                       return -1;
+               }
+@@ -115,32 +127,20 @@
+       xres = var.xres;
+       yres = var.yres;
+-      cmap.start = 0;
+-      cmap.len = 2;
+-      cmap.red = col;
+-      cmap.green = col;
+-      cmap.blue = col;
+-      cmap.transp = NULL;
+-
+-      col[0] = 0;
+-      col[1] = 0xffff;
+-
+-      if(var.bits_per_pixel==8) {
+-              if (ioctl(fb_fd, FBIOPUTCMAP, &cmap) < 0) {
+-                      perror("ioctl FBIOPUTCMAP");
+-                      close(fb_fd);
+-                      return -1;
+-              }
+-      }
+-
+       fbuffer = mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fb_fd, 0);
+-      if (fbuffer == (char *)-1) {
++      if (fbuffer == (unsigned char *)-1) {
+               perror("mmap framebuffer");
+               close(fb_fd);
+               return -1;
+       }
+       memset(fbuffer,0,fix.smem_len);
++      bytes_per_pixel = (var.bits_per_pixel + 7) / 8;
++      line_addr = malloc (sizeof (unsigned) * var.yres_virtual);
++      addr = 0;
++      for (y = 0; y < var.yres_virtual; y++, addr += fix.line_length)
++              line_addr [y] = fbuffer + addr;
++
+       return 0;
+ }
+@@ -161,135 +161,231 @@
+               close(con_fd);
+       }
++
++        free (line_addr);
+ }
+-void put_cross(int x, int y, int c)
++void put_cross(int x, int y, unsigned colidx)
+ {
+-      int off, i, s, e, loc;
++      line (x - 10, y, x - 2, y, colidx);
++      line (x + 2, y, x + 10, y, colidx);
++      line (x, y - 10, x, y - 2, colidx);
++      line (x, y + 2, x, y + 10, colidx);
+-      if (x < 0) x = 0;
+-      if (y < 0) y = 0;
+-      if (x >= var.xres) x = var.xres - 1;
+-      if (y >= var.yres) y = var.yres - 1;
++#if 1
++      line (x - 6, y - 9, x - 9, y - 9, colidx + 1);
++      line (x - 9, y - 8, x - 9, y - 6, colidx + 1);
++      line (x - 9, y + 6, x - 9, y + 9, colidx + 1);
++      line (x - 8, y + 9, x - 6, y + 9, colidx + 1);
++      line (x + 6, y + 9, x + 9, y + 9, colidx + 1);
++      line (x + 9, y + 8, x + 9, y + 6, colidx + 1);
++      line (x + 9, y - 6, x + 9, y - 9, colidx + 1);
++      line (x + 8, y - 9, x + 6, y - 9, colidx + 1);
++#else
++      line (x - 7, y - 7, x - 4, y - 4, colidx + 1);
++      line (x - 7, y + 7, x - 4, y + 4, colidx + 1);
++      line (x + 4, y - 4, x + 7, y - 7, colidx + 1);
++      line (x + 4, y + 4, x + 7, y + 7, colidx + 1);
++#endif
++}
+-      s = x - 10;
+-      if(s<0) s=0;
+-      e = x + 10;
+-      if(e>var.xres) e= var.xres;
+-      for(i=s;i<e;i++) {
+-              loc = (i + var.xoffset)*(var.bits_per_pixel/8)
+-                      + (y + var.yoffset)*fix.line_length;
+-              switch(var.bits_per_pixel) {
+-                      case 8:
+-                      default:
+-                              //fbuffer[loc] = c;
+-                              fbuffer[loc] = fbuffer[loc] ? 0 : 1;
+-                              break;
+-                      case 16:
+-                              *((unsigned short *)(fbuffer + loc)) = *((unsigned short *)(fbuffer + loc)) ? 0 : 0xffff;
+-                              break;
+-                      case 24:
+-                      case 32:
+-                              *((unsigned int *)(fbuffer + loc)) = *((unsigned int *)(fbuffer + loc)) ? 0 : 0xffffffff;
+-                              break;
+-              }
+-      }
+-      s = y - 10;
+-      if(s<0) s=0;
+-      e = y + 10;
+-      if(e>var.yres) e = var.yres;
+-      for(i=s;i<e;i++) {
+-              loc = (x + var.xoffset)*(var.bits_per_pixel/8)
+-                      + (i + var.yoffset)*fix.line_length;
+-              switch(var.bits_per_pixel) {
+-                      case 8:
+-                      default:
+-                              //fbuffer[loc] = c;
+-                              fbuffer[loc] = fbuffer[loc] ? 0 : 1;
+-                              break;
+-                      case 16:
+-                              *((unsigned short *)(fbuffer + loc)) = *((unsigned short *)(fbuffer + loc)) ? 0 : 0xffff;
+-                              break;
+-                      case 24:
+-                      case 32:
+-                              *((unsigned int *)(fbuffer + loc)) = *((unsigned int *)(fbuffer + loc)) ? 0 : 0xffffffff;
+-                              break;
+-              }
++void put_char(int x, int y, int c, int colidx)
++{
++      int i,j,bits;
++
++      for (i = 0; i < font_vga_8x8.height; i++) {
++              bits = font_vga_8x8.data [font_vga_8x8.height * c + i];
++              for (j = 0; j < font_vga_8x8.width; j++, bits <<= 1)
++                      if (bits & 0x80)
++                              pixel (x + j, y + i, colidx);
+       }
+-      return;
+ }
+-void put_char(int x, int y, int c, int color)
++void put_string(int x, int y, char *s, unsigned colidx)
+ {
+-      int i,j,bits,loc;
++      int i;
++      for (i = 0; *s; i++, x += font_vga_8x8.width, s++)
++              put_char (x, y, *s, colidx);
++}
+-      for(i=0;i<font_vga_8x8.height;i++) {
+-              bits = font_vga_8x8.data[font_vga_8x8.height*c + i];
+-              for(j=0;j<8;j++) {
+-                      loc = (x + j + var.xoffset)*(var.bits_per_pixel/8)
+-                              + (y + i + var.yoffset)*fix.line_length;
+-                      if(loc>=0 && loc<fix.smem_len && ((bits >> (7-j)) & 1)) {
+-                              switch(var.bits_per_pixel) {
+-                                      case 8:
+-                                      default:
+-                                              if(color==0)
+-                                                      fbuffer[loc] = 0;
+-                                              else
+-                                                      fbuffer[loc] = 1;
+-                                              break;
+-                                      case 16:
+-                                              if(color==0)
+-                                                      *((unsigned short *)(fbuffer + loc)) = 0;
+-                                              else
+-                                                      *((unsigned short *)(fbuffer + loc)) = 0xffff;
+-                                              break;
+-                                      case 24:
+-                                      case 32:
+-                                              if(color==0)
+-                                                      *((unsigned int *)(fbuffer + loc)) = 0;
+-                                              else
+-                                                      *((unsigned int *)(fbuffer + loc)) = 0xffffffff;
+-                                              break;
+-                              }
+-                      }       
+-              }
+-      }
++void put_string_center(int x, int y, char *s, unsigned colidx)
++{
++      size_t sl = strlen (s);
++        put_string (x - (sl / 2) * font_vga_8x8.width,
++                    y - font_vga_8x8.height / 2, s, colidx);
+ }
+-              
++void setcolor(unsigned colidx, unsigned value)
++{
++      unsigned res;
++      unsigned short red, green, blue;
++      struct fb_cmap cmap;
+-void put_string(int x, int y, char *s, int color)
++#ifdef DEBUG
++      if (colidx > 255) {
++              fprintf (stderr, "WARNING: color index = %u, must be <256\n",
++                       colidx);
++              return;
++      }
++#endif
++
++      switch (bytes_per_pixel) {
++      default:
++      case 1:
++              res = colidx;
++              red = (value >> 8) & 0xff00;
++              green = value & 0xff00;
++              blue = (value << 8) & 0xff00;
++              cmap.start = colidx;
++              cmap.len = 1;
++              cmap.red = &red;
++              cmap.green = &green;
++              cmap.blue = &blue;
++              cmap.transp = NULL;
++
++              if (ioctl (fb_fd, FBIOPUTCMAP, &cmap) < 0)
++                      perror("ioctl FBIOPUTCMAP");
++              break;
++      case 2:
++      case 4:
++              red = (value >> 16) & 0xff;
++              green = (value >> 8) & 0xff;
++              blue = value & 0xff;
++              res = ((red >> (8 - var.red.length)) << var.red.offset) |
++                      ((green >> (8 - var.green.length)) << var.green.offset) |
++                      ((blue >> (8 - var.blue.length)) << var.blue.offset);
++      }
++        colormap [colidx] = res;
++}
++
++static inline void __setpixel (union multiptr loc, unsigned xormode, unsigned color)
+ {
+-      int i;
+-      for(i=0;i<strlen(s);i++) {
+-              put_char( (x + font_vga_8x8.width* (i - strlen(s)/2)), y, s[i], color);
++      switch(bytes_per_pixel) {
++      case 1:
++      default:
++              if (xormode)
++                      *loc.p8 ^= color;
++              else
++                      *loc.p8 = color;
++              break;
++      case 2:
++              if (xormode)
++                      *loc.p16 ^= color;
++              else
++                      *loc.p16 = color;
++              break;
++      case 4:
++              if (xormode)
++                      *loc.p32 ^= color;
++              else
++                      *loc.p32 = color;
++              break;
+       }
+ }
+-void setcolors(int bgcolor, int fgcolor) {
+-/* No longer implemented
+-      unsigned short red[2], green[2], blue[2];
++void pixel (int x, int y, unsigned colidx)
++{
++      unsigned xormode;
++      union multiptr loc;
+-      red[0] = ( (bgcolor >> 16) & 0xff ) << 8;
+-      red[1] = ( (fgcolor >> 16) & 0xff ) << 8;
+-      green[0] = ( (bgcolor >> 8) & 0xff ) << 8;
+-      green[1] = ( (fgcolor >> 8) & 0xff ) << 8;
+-      blue[0] = ( bgcolor & 0xff ) << 8;
+-      blue[1] = ( fgcolor & 0xff ) << 8;
+-        cmap.start = 0;
+-        cmap.len = 2;
+-        cmap.red = red;
+-        cmap.green = green;
+-        cmap.blue = blue;
+-        cmap.transp = NULL;
++      if ((x < 0) || (x >= var.xres_virtual) ||
++          (y < 0) || (y >= var.yres_virtual))
++              return;
+-      if(var.bits_per_pixel==8) {
+-              if (ioctl(fb_fd, FBIOPUTCMAP, &cmap) < 0) {
+-                      perror("ioctl FBIOPUTCMAP");
+-                      close(fb_fd);
++      xormode = colidx & XORMODE;
++      colidx &= ~XORMODE;
++
++#ifdef DEBUG
++      if (colidx > 255) {
++              fprintf (stderr, "WARNING: color value = %u, must be <256\n",
++                       colidx);
++              return;
++      }
++#endif
++
++      loc.p8 = line_addr [y] + x * bytes_per_pixel;
++      __setpixel (loc, xormode, colormap [colidx]);
++}
++
++void line (int x1, int y1, int x2, int y2, unsigned colidx)
++{
++      int tmp;
++      int dx = x2 - x1;
++      int dy = y2 - y1;
++
++      if (abs (dx) < abs (dy)) {
++              if (y1 > y2) {
++                      tmp = x1; x1 = x2; x2 = tmp;
++                      tmp = y1; y1 = y2; y2 = tmp;
++                      dx = -dx; dy = -dy;
++              }
++              x1 <<= 16;
++              /* dy is apriori >0 */
++              dx = (dx << 16) / dy;
++              while (y1 <= y2) {
++                      pixel (x1 >> 16, y1, colidx);
++                      x1 += dx;
++                      y1++;
++              }
++      } else {
++              if (x1 > x2) {
++                      tmp = x1; x1 = x2; x2 = tmp;
++                      tmp = y1; y1 = y2; y2 = tmp;
++                      dx = -dx; dy = -dy;
++              }
++              y1 <<= 16;
++              dy = dx ? (dy << 16) / dx : 0;
++              while (x1 <= x2) {
++                      pixel (x1, y1 >> 16, colidx);
++                      y1 += dy;
++                      x1++;
+               }
+       }
+-*/
+ }
++void rect (int x1, int y1, int x2, int y2, unsigned colidx)
++{
++      line (x1, y1, x2, y1, colidx);
++      line (x2, y1, x2, y2, colidx);
++      line (x2, y2, x1, y2, colidx);
++      line (x1, y2, x1, y1, colidx);
++}
++
++void fillrect (int x1, int y1, int x2, int y2, unsigned colidx)
++{
++      int tmp;
++      unsigned xormode;
++      union multiptr loc;
++
++      /* Clipping and sanity checking */
++      if (x1 > x2) { tmp = x1; x1 = x2; x2 = tmp; }
++      if (y1 > y2) { tmp = y1; y1 = y2; y2 = tmp; }
++      if (x1 < 0) x1 = 0; if (x1 >= xres) x1 = xres - 1;
++      if (x2 < 0) x2 = 0; if (x2 >= xres) x2 = xres - 1;
++      if (y1 < 0) y1 = 0; if (y1 >= yres) y1 = yres - 1;
++      if (y2 < 0) y2 = 0; if (y2 >= yres) y2 = yres - 1;
++      if ((x1 > x2) || (y1 > y2))
++              return;
++
++      xormode = colidx & XORMODE;
++      colidx &= ~XORMODE;
++
++#ifdef DEBUG
++      if (colidx > 255) {
++              fprintf (stderr, "WARNING: color value = %u, must be <256\n",
++                       colidx);
++              return;
++      }
++#endif
++
++      colidx = colormap [colidx];
++
++      for (; y1 <= y2; y1++) {
++              loc.p8 = line_addr [y1] + x1 * bytes_per_pixel;
++              for (tmp = x1; tmp <= x2; tmp++) {
++                      __setpixel (loc, xormode, colidx);
++                      loc.p8 += bytes_per_pixel;
++              }
++      }
++}
+--- tslib/tests/fbutils.h~tslib
++++ tslib/tests/fbutils.h
+@@ -10,10 +10,26 @@
+  *
+  */
++#ifndef _FBUTILS_H
++#define _FBUTILS_H
++
++/* This constant, being ORed with the color index tells the library
++ * to draw in exclusive-or mode (that is, drawing the same second time
++ * in the same place will remove the element leaving the background intact).
++ */
++#define XORMODE       0x80000000
++
+ extern int xres, yres;
+ int open_framebuffer(void);
+ void close_framebuffer(void);
+-void put_cross(int x, int y, int c);
+-void put_string(int x, int y, char *s, int color);
+-void setcolors(int bgcolor, int fgcolor);
++void setcolor(unsigned colidx, unsigned value);
++void put_cross(int x, int y, unsigned colidx);
++void put_string(int x, int y, char *s, unsigned colidx);
++void put_string_center(int x, int y, char *s, unsigned colidx);
++void pixel (int x, int y, unsigned colidx);
++void line (int x1, int y1, int x2, int y2, unsigned colidx);
++void rect (int x1, int y1, int x2, int y2, unsigned colidx);
++void fillrect (int x1, int y1, int x2, int y2, unsigned colidx);
++
++#endif /* _FBUTILS_H */
+--- tslib/tests/ts_calibrate.c~tslib
++++ tslib/tests/ts_calibrate.c
+@@ -15,18 +15,26 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <signal.h>
++#include <string.h>
++#include <unistd.h>
+ #include <sys/fcntl.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/time.h>
+-#include <linux/fb.h>
+ #include <linux/kd.h>
+ #include <linux/vt.h>
++#include <linux/fb.h>
+ #include "tslib.h"
+ #include "fbutils.h"
++static int palette [] =
++{
++      0x000000, 0xffe080, 0xffffff, 0xe0c0a0
++};
++#define NR_COLORS (sizeof (palette) / sizeof (palette [0]))
++
+ typedef struct {
+       int x[5], xfb[5];
+       int y[5], yfb[5];
+@@ -35,22 +43,24 @@
+ static void sig(int sig)
+ {
+-      close_framebuffer();
+-      fflush(stderr);
+-      printf("signal %d caught\n", sig);
+-      fflush(stdout);
+-      exit(1);
++      close_framebuffer ();
++      fflush (stderr);
++      printf ("signal %d caught\n", sig);
++      fflush (stdout);
++      exit (1);
+ }
+ static int sort_by_x(const void* a, const void *b)
+ {
+       return (((struct ts_sample *)a)->x - ((struct ts_sample *)b)->x);
+ }
++
+ static int sort_by_y(const void* a, const void *b)
+ {
+       return (((struct ts_sample *)a)->y - ((struct ts_sample *)b)->y);
+ }
+-static int getxy(struct tsdev *ts, int *x, int *y)
++
++static void getxy(struct tsdev *ts, int *x, int *y)
+ {
+ #define MAX_SAMPLES 128
+       struct ts_sample samp[MAX_SAMPLES];
+@@ -104,7 +114,7 @@
+               else
+                       *x = (samp[middle-1].x + samp[middle].x) / 2;
+       }
+-      if (x) {
++      if (y) {
+               qsort(samp, index, sizeof(struct ts_sample), sort_by_y);
+               if (index & 1)
+                       *y = samp[middle].y;
+@@ -193,10 +203,40 @@
+ }
++static void get_sample (struct tsdev *ts, calibration *cal,
++                      int index, int x, int y, char *name)
++{
++      static int last_x = -1, last_y;
++
++      if (last_x != -1) {
++#define NR_STEPS 10
++              int dx = ((x - last_x) << 16) / NR_STEPS;
++              int dy = ((y - last_y) << 16) / NR_STEPS;
++              int i;
++              last_x <<= 16;
++              last_y <<= 16;
++              for (i = 0; i < NR_STEPS; i++) {
++                      put_cross (last_x >> 16, last_y >> 16, 2 | XORMODE);
++                      usleep (1000);
++                      put_cross (last_x >> 16, last_y >> 16, 2 | XORMODE);
++                      last_x += dx;
++                      last_y += dy;
++              }
++      }
++
++      put_cross(x, y, 2 | XORMODE);
++      getxy (ts, &cal->x [index], &cal->y [index]);
++      put_cross(x, y, 2 | XORMODE);
++
++      last_x = cal->xfb [index] = x;
++      last_y = cal->yfb [index] = y;
++
++      printf("%s : X = %4d Y = %4d\n", name, cal->x [index], cal->y [index]);
++}
++
+ int main()
+ {
+       struct tsdev *ts;
+-      int fd;
+       calibration cal;
+       int cal_fd;
+       char cal_buffer[256];
+@@ -231,96 +271,46 @@
+               close_framebuffer();
+               exit(1);
+       }
+-      close_framebuffer();
+-      if (open_framebuffer()) {
+-              close_framebuffer();
+-              exit(1);
+-      }
+-      setcolors(0x48ff48,0x880000);
++      for (i = 0; i < NR_COLORS; i++)
++              setcolor (i, palette [i]);
+-      put_string(xres/2,yres/4,"TSLIB calibration utility",1);
+-      put_string(xres/2,yres/4 + 20,"Touch crosshair to calibrate",1);
++      put_string_center (xres / 2, yres / 4,
++                         "TSLIB calibration utility", 1);
++      put_string_center (xres / 2, yres / 4 + 20,
++                         "Touch crosshair to calibrate", 2);
+-      printf("xres = %d, yres = %d\n",xres,yres);
++      printf("xres = %d, yres = %d\n", xres, yres);
+ // Read a touchscreen event to clear the buffer
+       //getxy(ts, 0, 0);
+-// Now paint a crosshair on the upper left and start taking calibration
+-// data
+-      put_cross(50,50,1);
+-      getxy(ts, &cal.x[0], &cal.y[0]);
+-      put_cross(50,50,0);
+-
+-      cal.xfb[0] = 50;
+-      cal.yfb[0] = 50;
+-
+-      printf("Top left : X = %4d Y = %4d\n", cal.x[0], cal.y[0]);
+-
+-      put_cross(xres - 50, 50, 1);
+-      getxy(ts, &cal.x[1], &cal.y[1]);
+-      put_cross(xres - 50, 50, 0);
+-
+-      cal.xfb[1] = xres-50;
+-      cal.yfb[1] = 50;
+-
+-      printf("Top right: X = %4d Y = %4d\n", cal.x[1], cal.y[1]);
+-
+-      put_cross(xres - 50, yres - 50, 1);
+-      getxy(ts, &cal.x[2], &cal.y[2]);
+-      put_cross(xres - 50, yres - 50, 0);
+-
+-      cal.xfb[2] = xres-50;
+-      cal.yfb[2] = yres-50;
+-
+-      printf("Bot right: X = %4d Y = %4d\n", cal.x[2], cal.y[2]);
+-
+-      put_cross(50, yres - 50, 1);
+-      getxy(ts, &cal.x[3], &cal.y[3]);
+-      put_cross(50, yres - 50, 0);
+-
+-      cal.xfb[3] = 50;
+-      cal.yfb[3] = yres-50;
+-
+-      printf("Bot left : X = %4d Y = %4d\n", cal.x[3], cal.y[3]);
+-
+-      put_cross(xres/2, yres/2, 1);
+-      getxy(ts, &cal.x[4], &cal.y[4]);
+-      put_cross(xres/2, yres/2, 0);
+-
+-      cal.xfb[4] = xres/2;
+-      cal.yfb[4] = yres/2;
+-
+-      printf("Middle: X = %4d Y = %4d\n", cal.x[4], cal.y[4]);
++      get_sample (ts, &cal, 0, 50,        50,        "Top left");
++      get_sample (ts, &cal, 1, xres - 50, 50,        "Top right");
++      get_sample (ts, &cal, 2, xres - 50, yres - 50, "Bot right");
++      get_sample (ts, &cal, 3, 50,        yres - 50, "Bot left");
++      get_sample (ts, &cal, 4, xres / 2,  yres / 2,  "Center");
+-      if(perform_calibration(&cal)) {
+-              printf("Calibration constants: ");
+-              for(i=0;i<7;i++) printf("%d ",cal.a[i]);
++      if (perform_calibration (&cal)) {
++              printf ("Calibration constants: ");
++              for (i = 0; i < 7; i++) printf("%d ", cal.a [i]);
+               printf("\n");
+-              if( (calfile = getenv("TSLIB_CALIBFILE")) != NULL) {
+-                      cal_fd = open(calfile,O_CREAT|O_RDWR);
++              if ((calfile = getenv("TSLIB_CALIBFILE")) != NULL) {
++                      cal_fd = open (calfile, O_CREAT | O_RDWR);
+               } else {
+-                      cal_fd = open("/etc/pointercal",O_CREAT|O_RDWR);
++                      cal_fd = open ("/etc/pointercal", O_CREAT | O_RDWR);
+               }
+-              sprintf(cal_buffer,"%d %d %d %d %d %d %d",cal.a[1],cal.a[2],cal.a[0],cal.a[4],cal.a[5],cal.a[3],cal.a[6]);
+-              write(cal_fd,cal_buffer,strlen(cal_buffer)+1);
+-              close(cal_fd);  
++              sprintf (cal_buffer,"%d %d %d %d %d %d %d",
++                       cal.a[1], cal.a[2], cal.a[0],
++                       cal.a[4], cal.a[5], cal.a[3], cal.a[6]);
++              write (cal_fd, cal_buffer, strlen (cal_buffer) + 1);
++              close (cal_fd);
++                i = 0;
+       } else {
+               printf("Calibration failed.\n");
++              i = -1;
+       }
+-//    while (1) {
+-//            struct ts_sample samp;
+-//
+-//            if (ts_read_raw(ts, &samp, 1) < 0) {
+-//                    perror("ts_read");
+-//                    exit(1);
+-//            }
+-//
+-//            printf("%ld.%06ld: %6d %6d %6d\n", samp.tv.tv_sec, samp.tv.tv_usec,
+-//                    samp.x, samp.y, samp.pressure);
+-//    }
+       close_framebuffer();
+-
++      return i;
+ }
+--- tslib/tests/ts_print.c~tslib
++++ tslib/tests/ts_print.c
+@@ -23,7 +23,6 @@
+ int main()
+ {
+       struct tsdev *ts;
+-      int x, y;
+       char *tsdevice=NULL;
+         if( (tsdevice = getenv("TSLIB_TSDEVICE")) != NULL ) {
+--- tslib/tests/ts_print_raw.c~tslib
++++ tslib/tests/ts_print_raw.c
+@@ -23,7 +23,6 @@
+ int main()
+ {
+       struct tsdev *ts;
+-      int x, y;
+       char *tsdevice=NULL;
+         if( (tsdevice = getenv("TSLIB_TSDEVICE")) != NULL ) {
+--- tslib/tests/ts_test.c~tslib
++++ tslib/tests/ts_test.c
+@@ -14,18 +14,39 @@
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <string.h>
+ #include <signal.h>
+ #include <sys/fcntl.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/time.h>
+-#include <linux/fb.h>
+-#include <linux/kd.h>
+-#include <linux/vt.h>
+ #include "tslib.h"
+ #include "fbutils.h"
++static int palette [] =
++{
++      0x000000, 0xffe080, 0xffffff, 0xe0c0a0, 0x304050, 0x80b8c0
++};
++#define NR_COLORS (sizeof (palette) / sizeof (palette [0]))
++
++struct ts_button {
++      int x, y, w, h;
++      char *text;
++      int flags;
++#define BUTTON_ACTIVE 0x00000001
++};
++
++/* [inactive] border fill text [active] border fill text */
++static int button_palette [6] =
++{
++      1, 4, 2,
++      1, 5, 0
++};
++
++#define NR_BUTTONS 2
++static struct ts_button buttons [NR_BUTTONS];
++
+ static void sig(int sig)
+ {
+       close_framebuffer();
+@@ -35,10 +56,61 @@
+       exit(1);
+ }
++static void button_draw (struct ts_button *button)
++{
++      int s = (button->flags & BUTTON_ACTIVE) ? 3 : 0;
++      rect (button->x, button->y, button->x + button->w - 1,
++            button->y + button->h - 1, button_palette [s]);
++      fillrect (button->x + 1, button->y + 1,
++                button->x + button->w - 2,
++                button->y + button->h - 2, button_palette [s + 1]);
++      put_string_center (button->x + button->w / 2,
++                         button->y + button->h / 2,
++                         button->text, button_palette [s + 2]);
++}
++
++static int button_handle (struct ts_button *button, struct ts_sample *samp)
++{
++      int inside = (samp->x >= button->x) && (samp->y >= button->y) &&
++              (samp->x < button->x + button->w) &&
++              (samp->y < button->y + button->h);
++
++      if (samp->pressure > 0) {
++              if (inside) {
++                      if (!(button->flags & BUTTON_ACTIVE)) {
++                              button->flags |= BUTTON_ACTIVE;
++                              button_draw (button);
++                      }
++              } else if (button->flags & BUTTON_ACTIVE) {
++                      button->flags &= ~BUTTON_ACTIVE;
++                      button_draw (button);
++              }
++      } else if (button->flags & BUTTON_ACTIVE) {
++              button->flags &= ~BUTTON_ACTIVE;
++              button_draw (button);
++                return 1;
++      }
++
++        return 0;
++}
++
++static void refresh_screen ()
++{
++      int i;
++
++      fillrect (0, 0, xres - 1, yres - 1, 0);
++      put_string_center (xres/2, yres/4,   "TSLIB test program", 1);
++      put_string_center (xres/2, yres/4+20,"Touch screen to move crosshair", 2);
++
++      for (i = 0; i < NR_BUTTONS; i++)
++              button_draw (&buttons [i]);
++}
++
+ int main()
+ {
+       struct tsdev *ts;
+-      int x, y;
++      int i, x, y;
++      int mode = 0;
+       char *tsdevice=NULL;
+@@ -46,9 +118,9 @@
+       signal(SIGINT, sig);
+       signal(SIGTERM, sig);
+-        if( (tsdevice = getenv("TSLIB_TSDEVICE")) != NULL ) {
+-                ts = ts_open(tsdevice,0);
+-        } else {
++      if ((tsdevice = getenv("TSLIB_TSDEVICE")) != NULL) {
++              ts = ts_open(tsdevice,0);
++      } else {
+ #ifdef USE_INPUT_API
+                 ts = ts_open("/dev/input/event0", 0);
+ #else
+@@ -70,28 +142,37 @@
+               close_framebuffer();
+               exit(1);
+       }
+-      close_framebuffer();
+-      if (open_framebuffer()) {
+-              close_framebuffer();
+-              exit(1);
+-      }
+       x = xres/2;
+       y = yres/2;
+-      setcolors(0x48ff48,0x880000);
++      for (i = 0; i < NR_COLORS; i++)
++              setcolor (i, palette [i]);
+-      put_string(xres/2,yres/4,"TSLIB test program",1);
+-      put_string(xres/2,yres/4+20,"Touch screen to move crosshair",1);
++      /* Initialize buttons */
++      memset (&buttons, 0, sizeof (buttons));
++      buttons [0].w = buttons [1].w = xres / 4;
++      buttons [0].h = buttons [1].h = 20;
++      buttons [0].x = xres / 4 - buttons [0].w / 2;
++      buttons [1].x = (3 * xres) / 4 - buttons [0].w / 2;
++      buttons [0].y = buttons [1].y = 10;
++      buttons [0].text = "Drag";
++      buttons [1].text = "Draw";
+-      put_cross(x,y,1);
++      refresh_screen ();
+       while (1) {
+               struct ts_sample samp;
+               int ret;
++              /* Show the cross */
++              put_cross(x, y, 2 | XORMODE);
++
+               ret = ts_read(ts, &samp, 1);
++              /* Hide it */
++              put_cross(x, y, 2 | XORMODE);
++
+               if (ret < 0) {
+                       perror("ts_read");
+                       close_framebuffer();
+@@ -101,14 +182,30 @@
+               if (ret != 1)
+                       continue;
++              for (i = 0; i < NR_BUTTONS; i++)
++                      if (button_handle (&buttons [i], &samp))
++                              switch (i) {
++                              case 0:
++                                      mode = 0;
++                                      refresh_screen ();
++                                      break;
++                              case 1:
++                                      mode = 1;
++                                      refresh_screen ();
++                                      break;
++                              }
++
+               printf("%ld.%06ld: %6d %6d %6d\n", samp.tv.tv_sec, samp.tv.tv_usec,
+                       samp.x, samp.y, samp.pressure);
+               if (samp.pressure > 0) {
+-                      put_cross(x, y, 0);
++                      if (mode == 0x80000001)
++                              line (x, y, samp.x, samp.y, 2);
+                       x = samp.x;
+                       y = samp.y;
+-                      put_cross(x, y, 1);
+-              }
++                      mode |= 0x80000000;
++              } else
++                      mode &= ~0x80000000;
+       }
++      close_framebuffer();
+ }