diff -urN gpm-orig/src/Makefile.in gpm/src/Makefile.in
--- gpm-orig/src/Makefile.in	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/Makefile.in	2003-11-03 16:41:14.000000000 -0500
@@ -12,12 +12,14 @@
 include $(top_builddir)/Makefile.include
 
 # Main portion: regular build rules
-MICESRC = mice.c protocol/ps2.c protocol/serial-support.c protocol/serial.c \
-          protocol/tablet.c protocol/touchscreen.c protocol/twiddler.c \
-          protocol/synaptics.c @JOYDEV_SRCS@ @EVDEV_SRCS@
+PROTOSRC = protocol/ps2.c protocol/serial-support.c protocol/serial.c \
+           protocol/tablet.c protocol/touchscreen.c protocol/twiddler.c \
+           protocol/synaptics.c @JOYDEV_SRCS@ @EVDEV_SRCS@
+
+PROTOOBJ = $(PROTOSRC:.c=.o)
 
 GSRC = main.c gpm.c gpn.c special.c startup.c console.c \
-       selection.c client.c optparser.c $(MICESRC)
+       selection.c client.c optparser.c mice.c readtmo.c
 
 GOBJ = $(GSRC:.c=.o) report.o
 
@@ -72,7 +74,7 @@
 # Do it all!
 all:	gpm lib/@SHLIB@ lib/libgpm.a $(PROG)
 
-gpm:	$(GOBJ)
+gpm:	$(GOBJ) protocol/libproto.a
 
 # construct dependings of sourcefiles and link sourcefiles
 $(DEPFILE) dep: prog/gpm-root.c
@@ -128,8 +130,8 @@
 # cleaning up section
 
 clean:
-	rm -f gpm lib/libgpm.a lib/libgpm.so lib/libgpm.so.@abi_full@ $(RDEPS)
-	rm -f core *~ $(GOBJ) $(LOBJ) $(POBJ) $(PICS) gpm-root.c $(DEPFILE)
+	rm -f gpm protocol/libproto.a lib/libgpm.a lib/libgpm.so lib/libgpm.so.@abi_full@ $(RDEPS)
+	rm -f core *~ $(GOBJ) $(PROTOOBJ) $(LOBJ) $(POBJ) $(PICS) gpm-root.c $(DEPFILE)
 	rm -f $(PROG) $(POBJ) prog/gpm-root.c
 
 distclean: clean
@@ -146,10 +148,15 @@
 	$(CC) -I. @CPPFLAGS@ $(CPPFLAGS) @CFLAGS@ $(CFLAGS) -c -o $@.o $<
 	$(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $@.o @LIBS@ $(LIBS) lib/libgpm.a
 
-prog/mouse-test:	$(MICESRC:.c=.o) console.o optparser.o
+prog/mouse-test:	console.o optparser.o mice.o rdttmo.o protocol/libproto.a
 
 $(PROG):	lib/libgpm.so lib/@SHLIB@ lib/libgpm.a
 
+# Subdirectory protocol/
+protocol/libproto.a:	$(PROTOOBJ)
+	$(AR) rc protocol/libproto.a $(PROTOOBJ)
+	$(RANLIB) protocol/libproto.a
+
 # Subdirectory lib/
 lib/libgpm.a:	$(LOBJ)
 	$(AR) rc lib/libgpm.a $(LOBJ)
diff -urN gpm-orig/src/gpm.c gpm/src/gpm.c
--- gpm-orig/src/gpm.c	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/gpm.c	2003-11-03 15:02:02.000000000 -0500
@@ -39,6 +39,7 @@
 #include "headers/console.h"
 #include "headers/selection.h"
 #include "headers/client.h"
+#include "headers/readtmo.h"
 
 #ifndef max
 #define max(a,b) ((a)>(b) ? (a) : (b))
@@ -251,18 +252,6 @@
    }
 }
 
-static int more_data_waiting(int fd)
-{
-   static struct timeval timeout = {0, 0};
-   fd_set fdSet;
-
-   FD_ZERO(&fdSet);
-   FD_SET(fd, &fdSet);
-   select(fd + 1, &fdSet, NULL_SET, NULL_SET, &timeout/* zero */);
-
-   return FD_ISSET(fd, &fdSet);
-}
-
 static int multiplex_buttons(struct micetab *mouse, int new_buttons)
 {
    static int left_btn_clicks, mid_btn_clicks, right_btn_clicks;
@@ -371,7 +360,7 @@
          event->wdx += nEvent.wdx;
          event->wdy += nEvent.wdy;
          
-      } while (i++ < opt->cluster && more_data_waiting(mouse->dev.fd));
+      } while (i++ < opt->cluster && wait_fd_data(mouse->dev.fd, 0));
    } /* if(eventFlag) */
 
    /*....................................... update the button number */
Files gpm-orig/src/gpm.exe and gpm/src/gpm.exe differ
diff -urN gpm-orig/src/headers/gpmInt.h gpm/src/headers/gpmInt.h
--- gpm-orig/src/headers/gpmInt.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/gpmInt.h	2003-10-24 12:07:38.000000000 -0500
@@ -69,7 +69,7 @@
 #define GPM_SYS_CONSOLE      "/dev/console"
 
 #define GET_TIME(tv)       (gettimeofday(&tv, (struct timezone *)NULL))
-#define DIF_TIME(t1, t2)   ((t2.tv_sec -t1.tv_sec)*1000 + (t2.tv_usec - t1.tv_usec)/1000)
+#define DIF_TIME(t1, t2)   ((t2.tv_sec - t1.tv_sec)*1000 + (t2.tv_usec - t1.tv_usec)/1000)
 
 /*....................................... Structures */
 
@@ -121,7 +121,7 @@
    protocol_setup    *setup;
    protocol_init     *init;
    protocol_cleanup  *cleanup;
-   protovol_destroy  *destroy;
+   protocol_destroy  *destroy;
    
    unsigned short    flags;
    unsigned char     proto[4];
@@ -199,4 +199,23 @@
 #define MAGIC_P(code) 
 #endif
 
+#ifndef O_NDELAY
+#define O_NDELAY 1
+#endif
+#ifndef TIOCLINUX
+#define TIOCLINUX 1
+#endif
+#ifndef TIOCSTI
+#define TIOCSTI 1
+#endif
+#ifndef SA_NOMASK
+#define SA_NOMASK 2
+#endif
+
+#include <sys/termios.h>
+#include <asm/ioctl.h>
+
+#define GPM_DEVFS_CONSOLE    "/dev/vc/0"
+#define GPM_OLD_CONSOLE      "/dev/tty0"
+
 #endif /* _GPMINT_INCLUDED */
diff -urN gpm-orig/src/headers/message.h gpm/src/headers/message.h
--- gpm-orig/src/headers/message.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/message.h	2003-10-22 15:57:26.000000000 -0500
@@ -185,7 +185,7 @@
 #define GPM_MESS_IMPS2_SETUP_FAIL   "imps2: PS/2 mouse failed setup, continuing..."
 #define GPM_MESS_IMPS2_BAD_ID       "imps2: Auto-detected unknown mouse type %d, assuming standard PS/2"
 #define GPM_MESS_GUNZE_WRONG_BAUD   "%s: %s: wrong baud rate, using 19200"
-#define GPM_MESS_GUNZE_CALIBRATE    "%s: gunze: calibration data absent or invalid,using defaults"
+#define GPM_MESS_GUNZE_CALIBRATE    "%s: gunze: calibration data absent or invalid, using defaults"
 #define GPM_MESS_TOO_MANY_SPECIAL   "%s: too many special functions (max is %i)"
 #define GPM_MESS_SYNTAX_1           "%s: %s :%i: Syntax error"
 #define GPM_MESS_UNKNOWN_MOD_1      "%s: %s :%i: Unknown modifier \"%s\""
diff -urN gpm-orig/src/headers/protocol/evdev.h gpm/src/headers/protocol/evdev.h
--- gpm-orig/src/headers/protocol/evdev.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/evdev.h	2003-10-22 17:36:30.000000000 -0500
@@ -23,7 +23,7 @@
 
 #include "headers/gpmInt.h"
 
-extern protocol_init       I_evdev;
+extern protocol_setup      S_evdev;
 extern protocol_handler    M_evdev;
 
 #endif /* __GPM_EVDEV_H_ */
diff -urN gpm-orig/src/headers/protocol/joystick.h gpm/src/headers/protocol/joystick.h
--- gpm-orig/src/headers/protocol/joystick.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/joystick.h	2003-10-22 16:03:10.000000000 -0500
@@ -23,6 +23,7 @@
 
 #include "headers/gpmInt.h"
 
+extern protocol_setup      S_joystick;
 extern protocol_handler    M_joystick;
 
 #endif /* __GPM_EVDEV_H_ */
diff -urN gpm-orig/src/headers/protocol/ps2.h gpm/src/headers/protocol/ps2.h
--- gpm-orig/src/headers/protocol/ps2.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/ps2.h	2003-10-24 11:04:12.000000000 -0500
@@ -23,8 +23,6 @@
 
 #include "headers/gpmInt.h"
 
-int get_glidepoint_tap_option(char *proto, char *opttext);
-
 extern protocol_init       I_ps2;
 extern protocol_handler    M_ps2;
 extern repeat_handler      R_ps2;
diff -urN gpm-orig/src/headers/protocol/serial.h gpm/src/headers/protocol/serial.h
--- gpm-orig/src/headers/protocol/serial.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/serial.h	2003-10-22 18:37:04.000000000 -0500
@@ -23,8 +23,10 @@
 
 #include "headers/gpmInt.h"
 
+extern protocol_setup      S_serial;
 extern protocol_init       I_serial;
 
+extern protocol_setup      S_ms;
 extern protocol_init       I_ms;
 extern protocol_handler    M_ms;
 extern protocol_handler    M_bare;
@@ -40,15 +42,20 @@
 
 extern protocol_handler    M_mm;
 
+extern protocol_setup      S_logi;
 extern protocol_init       I_logi;
 extern protocol_init       I_logimsc;
 
+extern protocol_setup      S_mman;
 extern protocol_init       I_mman;
 extern protocol_handler    M_mman;
 
+extern protocol_setup      S_vsxxx_aa;
 extern protocol_init       I_vsxxx_aa;
 
+extern protocol_setup      S_pnp;
 extern protocol_init       I_pnp;
-extern protocol_init       I_empty;
+
+extern protocol_setup      S_empty;
 
 #endif /* __GPM_SERIAL_H_ */
diff -urN gpm-orig/src/headers/protocol/synaptics.h gpm/src/headers/protocol/synaptics.h
--- gpm-orig/src/headers/protocol/synaptics.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/synaptics.h	2003-10-23 14:27:44.000000000 -0500
@@ -56,6 +56,7 @@
 #ifndef _SYNAPTICS_H_
 #define _SYNAPTICS_H_
 
+extern protocol_setup   S_synaptics_serial;
 extern protocol_init    I_synaptics_serial;
 extern protocol_handler M_synaptics_serial;
 
diff -urN gpm-orig/src/headers/protocol/tablet.h gpm/src/headers/protocol/tablet.h
--- gpm-orig/src/headers/protocol/tablet.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/tablet.h	2003-10-23 10:46:30.000000000 -0500
@@ -23,21 +23,26 @@
 
 #include "headers/gpmInt.h"
 
+extern protocol_setup      S_summa;
 extern protocol_init       I_summa;
 extern protocol_handler    M_summa;
 extern repeat_handler      R_summa;
 
+extern protocol_setup      S_geni;
 extern protocol_init       I_geni;
 extern protocol_handler    M_geni;
 
+extern protocol_setup      S_wacom;
 extern protocol_init       I_wacom;
 extern protocol_handler    M_wacom;
 
+extern protocol_setup      S_calus;
 extern protocol_init       I_calus;
 extern protocol_handler    M_calus;
 
 extern protocol_handler    M_ncr;
 
+extern protocol_setup      S_wp;
 extern protocol_init       I_wp;
 extern protocol_handler    M_wp;
 
diff -urN gpm-orig/src/headers/protocol/touchscreen.h gpm/src/headers/protocol/touchscreen.h
--- gpm-orig/src/headers/protocol/touchscreen.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/touchscreen.h	2003-10-23 10:36:54.000000000 -0500
@@ -23,9 +23,11 @@
 
 #include "headers/gpmInt.h"
 
+extern protocol_setup      S_mtouch;
 extern protocol_init       I_mtouch;
 extern protocol_handler    M_mtouch;
 
+extern protocol_setup      S_gunze;
 extern protocol_init       I_gunze;
 extern protocol_handler    M_gunze;
 
diff -urN gpm-orig/src/headers/protocol/twiddler.h gpm/src/headers/protocol/twiddler.h
--- gpm-orig/src/headers/protocol/twiddler.h	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/headers/protocol/twiddler.h	2003-10-22 16:22:36.000000000 -0500
@@ -53,6 +53,7 @@
 #define TW_SYSTEM_FILE SYSCONFDIR "/gpm-twiddler.conf"
 #define TW_CUSTOM_FILE SYSCONFDIR "/gpm-twiddler.user"
 
+extern protocol_setup   S_twiddler;
 extern protocol_init    I_twiddler;
 extern protocol_handler M_twiddler;
 
diff -urN gpm-orig/src/headers/readtmo.h gpm/src/headers/readtmo.h
--- gpm-orig/src/headers/readtmo.h	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/headers/readtmo.h	2003-11-03 14:48:10.000000000 -0500
@@ -0,0 +1,27 @@
+/*
+ * readtmo.h
+ *
+ * Copyright (C) 2003  Dmitry Torokhov <dtor@mail.ru>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ ********/
+
+#ifndef __GPM_READTMO_H_
+#define __GPM_READTMO_H_
+
+extern int wait_fd_data(int fd, unsigned int tmo);
+extern ssize_t read_tmo(int fd, void *data, size_t count, unsigned int tmo);
+
+#endif /* __GPM_READTMO_H_ */
diff -urN gpm-orig/src/mice.c gpm/src/mice.c
--- gpm-orig/src/mice.c	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/mice.c	2003-10-23 14:28:46.000000000 -0500
@@ -109,49 +109,49 @@
 
    {"mman", "The \"MouseMan\" and similar devices (3/4 bytes per packet).",
            "Mouseman", 
-           M_mman, NULL, I_mman, NULL, NULL, 
+           M_mman, S_mman, I_mman, NULL, NULL, 
            CS7 | STD_FLG, 
            {0x40, 0x40, 0x40, 0x00}, 3, 1, 1, 0},
 
    {"ms",   "The original ms protocol, with a middle-button extension.",
            "", 
-           M_ms, NULL, I_ms, NULL, NULL, 
+           M_ms, S_ms, I_ms, NULL, NULL, 
            CS7 | STD_FLG, 
            {0x40, 0x40, 0x40, 0x00}, 3, 1, 0, 0},
 
    {"acecad",  "Acecad tablet absolute mode(Sumagrapics MM-Series mode)",
            "", 
-           M_summa, NULL, I_summa, NULL, NULL, 
+           M_summa, S_summa, I_summa, NULL, NULL, 
            STD_FLG, 
            {0x80, 0x80, 0x00, 0x00}, 7, 1, 0, 1}, 
 
    {"bare", "Unadorned ms protocol. Needed with some 2-buttons mice.",
            "Microsoft", 
-           M_ms, NULL, I_ms, NULL, NULL, 
+           M_ms, S_ms, I_ms, NULL, NULL, 
            CS7 | STD_FLG,
            {0x40, 0x40, 0x40, 0x00}, 3, 1, 0, 0},
 
    {"bm",   "Micro$oft busmice and compatible devices.",
            "BusMouse", 
-           M_bm, NULL, I_empty, NULL, NULL, 
+           M_bm, S_empty, NULL, NULL, NULL, 
            STD_FLG, 
            {0xf8, 0x80, 0x00, 0x00}, 3, 3, 0, 0},
 
    {"brw",  "Fellowes Browser - 4 buttons (and a wheel) (dual protocol?)",
            "", 
-           M_brw, NULL, I_pnp, NULL, NULL,
+           M_brw, S_pnp, I_pnp, NULL, NULL,
            CS7 | STD_FLG, 
            {0xc0, 0x40, 0xc0, 0x00}, 4, 1, 0, 0},
 
    {"cal", "Calcomp UltraSlate",
            "", 
-           M_calus, NULL, I_calus, NULL, NULL,
+           M_calus, S_calus, I_calus, NULL, NULL,
            CS8 | CSTOPB | STD_FLG, {0x80, 0x80, 0x80, 0x00}, 6, 6, 0, 1},
 
 #ifdef HAVE_LINUX_INPUT_H
    {"evdev", "Linux Event Device",
             "", 
-            M_evdev, NULL, I_evdev, NULL, NULL, 
+            M_evdev, S_evdev, NULL, NULL, NULL, 
             STD_FLG, 
             {0x00, 0x00, 0x00, 0x00} , 16, 16, 0},
 #endif /* HAVE_LINUX_INPUT_H */
@@ -159,74 +159,74 @@
 #ifdef HAVE_LINUX_JOYSTICK_H
    {"js",   "Joystick mouse emulation",
            "Joystick", 
-           M_joystick, NULL, I_empty, NULL, NULL,
+           M_joystick, S_empty, NULL, NULL, NULL,
            0,
            {0xFC, 0x00, 0x00, 0x00}, 12, 12, 0, 0},
 #endif
 
    {"genitizer", "\"Genitizer\" tablet, in relative mode.",
            "", 
-           M_geni, NULL, I_geni, NULL, NULL,
+           M_geni, S_geni, I_geni, NULL, NULL,
            CS8 | PARENB | PARODD,
            {0x80, 0x80, 0x00, 0x00}, 3, 1, 0, 0},
 
    {"gunze",  "Gunze touch-screens (only button-1 events, by now)",
            "", 
-           M_gunze, NULL, I_gunze, NULL, NULL,
+           M_gunze, S_gunze, I_gunze, NULL, NULL,
            STD_FLG,
            {0xF9, 0x50, 0xF0, 0x30}, 11, 1, 0, 1}, 
 
    {"logi", "Used in some Logitech devices (only serial).",
            "Logitech", 
-           M_mm, NULL, I_logi, NULL, NULL,
+           M_mm, S_logi, I_logi, NULL, NULL,
            CS8 | CSTOPB | STD_FLG,
            {0xe0, 0x80, 0x80, 0x00}, 3, 3, 0, 0},
 
    {"logim",  "Turn logitech into Mouse-Systems-Compatible.",
            "", 
-           M_msc, NULL, I_logimsc, NULL, NULL,
+           M_msc, S_serial, I_logimsc, NULL, NULL,
            CS8 | CSTOPB | STD_FLG,
            {0xf8, 0x80, 0x00, 0x00}, 5, 1, 0, 0},
 
    {"mm",   "MM series. Probably an old protocol...",
            "MMSeries", 
-           M_mm, NULL, I_serial, NULL, NULL,
+           M_mm, S_serial, I_serial, NULL, NULL,
            CS8 | PARENB|PARODD | STD_FLG,
            {0xe0, 0x80, 0x80, 0x00}, 3, 1, 0, 0},
 
    {"ms3", "Microsoft Intellimouse (serial) - 3 buttons, wheel unused",
            "", 
-           M_ms3, NULL, I_pnp, NULL, NULL,
+           M_ms3, S_pnp, I_pnp, NULL, NULL,
            CS7 | STD_FLG,
            {0xc0, 0x40, 0xc0, 0x00}, 4, 1, 0, 0},
 
    {"ms+", "Like 'ms', but allows dragging with the middle button.",
            "", 
-           M_ms, NULL, I_ms, NULL, NULL,
+           M_ms, S_ms, I_ms, NULL, NULL,
            CS7 | STD_FLG,
            {0x40, 0x40, 0x40, 0x00}, 3, 1, 0, 0},
 
    {"ms+lr", "'ms+', but you can reset m by pressing lr (see man page).",
            "", 
-           M_ms, NULL, I_ms, NULL, NULL,
+           M_ms, S_ms, I_ms, NULL, NULL,
            CS7 | STD_FLG,
            {0x40, 0x40, 0x40, 0x00}, 3, 1, 0, 0},
 
    {"msc",  "Mouse-Systems-Compatible (5bytes). Most 3-button mice.",
            "MouseSystems",
-           M_msc, NULL, I_serial, NULL, NULL,
+           M_msc, S_serial, I_serial, NULL, NULL,
            CS8 | CSTOPB | STD_FLG,
            {0xf8, 0x80, 0x00, 0x00}, 5, 1, 0, 0},
 
    {"mtouch",  "MicroTouch touch-screens (only button-1 events, by now)",
            "", 
-           M_mtouch, NULL, I_mtouch, NULL, NULL,
+           M_mtouch, S_mtouch, I_mtouch, NULL, NULL,
            STD_FLG,
            {0x80, 0x80, 0x80, 0x00}, 5, 1, 0, 1}, 
 
    {"ncr",  "Ncr3125pen, found on some laptops",
            "", 
-           M_ncr, NULL, NULL, NULL, NULL,
+           M_ncr, S_empty, NULL, NULL, NULL,
            STD_FLG,
            {0x08, 0x08, 0x00, 0x00}, 7, 7, 0, 1},
 
@@ -238,7 +238,7 @@
 
    {"pnp",  "Plug and pray. New mice may not run with '-t ms'.",
            "", 
-           M_bare, NULL, I_pnp, NULL, NULL,
+           M_bare, S_pnp, I_pnp, NULL, NULL,
            CS7 | STD_FLG,
            {0x40, 0x40, 0x40, 0x00}, 3, 1, 0, 0},
 
@@ -250,19 +250,19 @@
 
    {"sun",  "Same as Microsoft busmice, but on serial line.",
            "", 
-           M_bm, NULL, I_serial, NULL, NULL,
+           M_bm, S_serial, I_serial, NULL, NULL,
            CS8 | CSTOPB | STD_FLG,
            {0xf8, 0x80, 0x00, 0x00}, 3, 1, 0, 0},
 
    {"summa",  "Summagraphics or Genius tablet absolute mode(MM-Series)",
            "", 
-           M_summa, NULL, I_summa, NULL, NULL,
+           M_summa, S_summa, I_summa, NULL, NULL,
            STD_FLG,
            {0x80, 0x80, 0x00, 0x00}, 5, 1, 0, 1},
 
    {"syn", "The \"Synaptics\" serial TouchPad.",
            "synaptics", 
-           M_synaptics_serial, NULL, I_synaptics_serial, NULL, NULL,
+           M_synaptics_serial, S_synaptics_serial, I_synaptics_serial, NULL, NULL,
            CS7 | STD_FLG,
            {0x40, 0x40, 0x40, 0x00}, 6, 6, 1, 0},
 
@@ -272,27 +272,27 @@
            STD_FLG,
            {0x80, 0x80, 0x00, 0x00}, 6, 1, 1, 0},
 
-   {"twid", "Twidddler keyboard",
+   {"twid", "Twiddler keyboard",
            "twiddler", 
-           M_twiddler, NULL, I_twiddler, NULL, NULL,
+           M_twiddler, S_twiddler, I_twiddler, NULL, NULL,
            CS8 | STD_FLG,
            {0x80, 0x00, 0x80, 0x80}, 5, 1, 0, 0},
 
    {"vsxxxaa", "The DEC VSXXX-AA/GA serial mouse on DEC workstations.",
            "",    
-           M_mm, NULL, I_vsxxx_aa, NULL, NULL,
+           M_mm, S_vsxxx_aa, I_vsxxx_aa, NULL, NULL,
            CS8 | PARENB | PARODD | STD_FLG,
            {0xe0, 0x80, 0x80, 0x00}, 3, 1, 0, 0},
 
    {"wacom","Wacom Protocol IV Tablets: Pen+Mouse, relative+absolute mode",
            "", 
-           M_wacom, NULL, I_wacom, NULL, NULL,
+           M_wacom, S_wacom, I_wacom, NULL, NULL,
            STD_FLG,
            {0x80, 0x80, 0x80, 0x00}, 7, 1, 0, 0},
 
    {"wp",   "Genius WizardPad tablet",
            "wizardpad", 
-           M_wp, NULL, I_wp, NULL, NULL,
+           M_wp, S_wp, I_wp, NULL, NULL,
            STD_FLG,
            {0xFA, 0x42, 0x00, 0x00}, 10, 1, 0, 1},
 
diff -urN gpm-orig/src/protocol/evdev.c gpm/src/protocol/evdev.c
--- gpm-orig/src/protocol/evdev.c	2003-10-21 15:38:40.000000000 -0500
+++ gpm/src/protocol/evdev.c	2003-10-22 17:35:36.000000000 -0500
@@ -737,107 +737,105 @@
    return 0;
 }
 
-int I_evdev(struct micedev *dev, struct miceopt *opts, Gpm_Type *type)
+int S_evdev(struct micedev *dev, struct miceopt *opts, Gpm_Type *type)
 {
    struct input_id id;
    struct evdev_capabilities caps;
    struct event_device *evdev;
 
-   if (!dev->private) {          /* called first time, not re-init */
-      if (!(dev->private = evdev = malloc(sizeof(*evdev))))
-         gpm_report(GPM_PR_OOPS, "Can't allocate memory for event device");
+   if (!(dev->private = evdev = malloc(sizeof(*evdev))))
+      gpm_report(GPM_PR_OOPS, "Can't allocate memory for event device");
 
-      memset(evdev, 0, sizeof(*evdev));
+   memset(evdev, 0, sizeof(*evdev));
 
-      if (evdev_get_id(dev->fd, &id))
-         goto init_fail;
-
-      if (evdev_get_capabilities(dev->fd, &caps))
-         goto init_fail;
-      
-      evdev->type = evdev_guess_type(&id, &caps);
-      
-      /* load default values - suitable for my synaptics ;P */
-      evdev->left_edge = 1900;
-      evdev->right_edge = 5300;
-      evdev->top_edge = 2000;
-      evdev->bottom_edge = 3900;
-      evdev->tap_time = 180;
-      evdev->tap_move = 220;
-      evdev->touch_high = 30;
-      evdev->touch_low = 25;
+   if (evdev_get_id(dev->fd, &id))
+      goto init_fail;
 
-      if (evdev->type == EVDEV_ABSOLUTE && evdev_get_limits(dev->fd, evdev, &caps) < 0) 
-         goto init_fail;
-     
-      if (evdev_apply_options(evdev, opts->text) < 0)
+   if (evdev_get_capabilities(dev->fd, &caps))
+      goto init_fail;
+   
+   evdev->type = evdev_guess_type(&id, &caps);
+   
+   /* load default values - suitable for my synaptics ;P */
+   evdev->left_edge = 1900;
+   evdev->right_edge = 5300;
+   evdev->top_edge = 2000;
+   evdev->bottom_edge = 3900;
+   evdev->tap_time = 180;
+   evdev->tap_move = 220;
+   evdev->touch_high = 30;
+   evdev->touch_low = 25;
+
+   if (evdev->type == EVDEV_ABSOLUTE && evdev_get_limits(dev->fd, evdev, &caps) < 0) 
+      goto init_fail;
+  
+   if (evdev_apply_options(evdev, opts->text) < 0)
+      goto init_fail;
+
+   if (!test_bit(EV_SYNC, caps.evbits)) {
+      evdev->dont_sync = 1;
+      if (evdev->type == EVDEV_TOUCHPAD || evdev->type == EVDEV_SYNAPTICS) {
+         gpm_report(GPM_PR_ERR, 
+                    "evdev: The running kernel lacks EV_SYNC support which is required for touchpad/synaptics mode"); 
          goto init_fail;
-
-      if (!test_bit(EV_SYNC, caps.evbits)) {
-         evdev->dont_sync = 1;
-         if (evdev->type == EVDEV_TOUCHPAD || evdev->type == EVDEV_SYNAPTICS) {
-            gpm_report(GPM_PR_ERR, 
-                       "evdev: The running kernel lacks EV_SYNC support which is required for touchpad/synaptics mode"); 
+      }
+   }
+   
+   switch (evdev->type) {
+      case EVDEV_RELATIVE:
+         gpm_report(GPM_PR_INFO, "evdev: selected Relative mode");
+         if (!test_bit(EV_REL, caps.evbits))
+            gpm_report(GPM_PR_WARN, "evdev: selected relative mode but device does not report any relative events");
+         break;
+         
+      case EVDEV_ABSOLUTE:
+         gpm_report(GPM_PR_INFO, "evdev: selected Absolute mode");
+         if (evdev->right_edge <= evdev->left_edge) {
+            gpm_report(GPM_PR_ERR, "evdev: right edge value should be gerater than left");
             goto init_fail;
          }
-      }
-      
-      switch (evdev->type) {
-         case EVDEV_RELATIVE:
-            gpm_report(GPM_PR_INFO, "evdev: selected Relative mode");
-            if (!test_bit(EV_REL, caps.evbits))
-               gpm_report(GPM_PR_WARN, "evdev: selected relative mode but device does not report any relative events");
-            break;
-            
-         case EVDEV_ABSOLUTE:
-            gpm_report(GPM_PR_INFO, "evdev: selected Absolute mode");
-            if (evdev->right_edge <= evdev->left_edge) {
-               gpm_report(GPM_PR_ERR, "evdev: right edge value should be gerater than left");
-               goto init_fail;
-            }
-            if (evdev->bottom_edge <= evdev->top_edge) {
-               gpm_report(GPM_PR_ERR, "evdev: bottom edge value should be gerater than top");
-               goto init_fail;
-            }
-            if (!test_bit(EV_ABS, caps.evbits))
-               gpm_report(GPM_PR_WARN, "evdev: selected absolute mode but device does not report any absolute events");
-            opts->absolute = 1;
-            break;
-
-         case EVDEV_TOUCHPAD:
-            gpm_report(GPM_PR_INFO, "evdev: selected Touchpad mode");
-            if (!test_bit(EV_ABS, caps.evbits))
-               gpm_report(GPM_PR_WARN, "evdev: selected touchpad mode but device does not report any absolute events");
-            if (test_bit(ABS_PRESSURE, caps.absbits))
-               evdev->detect_touch = smart_tp_detect_touch;
-            else if (test_bit(BTN_TOUCH, caps.keybits))
-               evdev->detect_touch = dumb_tp_detect_touch;
-            else
-               gpm_report(GPM_PR_WARN, "evdev: selected touchpad mode but device does not report pressure not touch events");
+         if (evdev->bottom_edge <= evdev->top_edge) {
+            gpm_report(GPM_PR_ERR, "evdev: bottom edge value should be gerater than top");
+            goto init_fail;
+         }
+         if (!test_bit(EV_ABS, caps.evbits))
+            gpm_report(GPM_PR_WARN, "evdev: selected absolute mode but device does not report any absolute events");
+         opts->absolute = 1;
+         break;
+
+      case EVDEV_TOUCHPAD:
+         gpm_report(GPM_PR_INFO, "evdev: selected Touchpad mode");
+         if (!test_bit(EV_ABS, caps.evbits))
+            gpm_report(GPM_PR_WARN, "evdev: selected touchpad mode but device does not report any absolute events");
+         if (test_bit(ABS_PRESSURE, caps.absbits))
+            evdev->detect_touch = smart_tp_detect_touch;
+         else if (test_bit(BTN_TOUCH, caps.keybits))
+            evdev->detect_touch = dumb_tp_detect_touch;
+         else
+            gpm_report(GPM_PR_WARN, "evdev: selected touchpad mode but device does not report pressure not touch events");
+         evdev->update_finger_count = tp_update_finger_count;
+         break;
+
+      case EVDEV_SYNAPTICS:
+         gpm_report(GPM_PR_INFO, "evdev: selected Synaptics mode");
+         if (!is_synaptics(&id))
+            gpm_report(GPM_PR_WARN, "evdev: idevice isn't identified as Synaptics");
+         if (!test_bit(EV_ABS, caps.evbits))
+            gpm_report(GPM_PR_WARN, "evdev: selected synaptics mode but device does not report any absolute events");
+         if (!test_bit(ABS_PRESSURE, caps.absbits))
+            gpm_report(GPM_PR_WARN, "evdev: selected synaptics mode but device does not report pressure");
+         if (test_bit(EV_MSC, caps.evbits) && test_bit(MSC_GESTURE, caps.mscbits)) {
+            /* this is compatibility mode with pre 2.6-test6 kernels */
+            evdev->update_finger_count = syn_update_finger_count;
+            evdev->y_inverted = 1;
+         } else { 
             evdev->update_finger_count = tp_update_finger_count;
-            break;
-
-         case EVDEV_SYNAPTICS:
-            gpm_report(GPM_PR_INFO, "evdev: selected Synaptics mode");
-            if (!is_synaptics(&id))
-               gpm_report(GPM_PR_WARN, "evdev: idevice isn't identified as Synaptics");
-            if (!test_bit(EV_ABS, caps.evbits))
-               gpm_report(GPM_PR_WARN, "evdev: selected synaptics mode but device does not report any absolute events");
-            if (!test_bit(ABS_PRESSURE, caps.absbits))
-               gpm_report(GPM_PR_WARN, "evdev: selected synaptics mode but device does not report pressure");
-            if (test_bit(EV_MSC, caps.evbits) && test_bit(MSC_GESTURE, caps.mscbits)) {
-               /* this is compatibility mode with pre 2.6-test6 kernels */
-               evdev->update_finger_count = syn_update_finger_count;
-               evdev->y_inverted = 1;
-            } else { 
-               evdev->update_finger_count = tp_update_finger_count;
-            }
-            evdev->detect_touch = syn_detect_touch;
-            break;
+         }
+         evdev->detect_touch = syn_detect_touch;
+         break;
 
-         default:
-            break;
-      }
+      default:
+         break;
    }
    
    return 0;
diff -urN gpm-orig/src/protocol/joystick.c gpm/src/protocol/joystick.c
--- gpm-orig/src/protocol/joystick.c	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/protocol/joystick.c	2003-10-23 10:52:46.000000000 -0500
@@ -5,6 +5,7 @@
  * Copyright (C) 1994-2000   Alessandro Rubini <rubini@linux.it>
  * Copyright (C) 1998,1999   Ian Zimmerman <itz@rahul.net>
  * Copyright (C) 2001,2002   Nico Schottelius <nicos@pcsystems.de>
+ * Copyright (C) 2003        Dmitry Torokhov <dtor@mail.ru>
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -32,39 +33,64 @@
 #include <linux/joystick.h>
 
 #include "headers/gpmInt.h"
+#include "headers/message.h"
+#include "headers/optparser.h"
 #include "headers/protocol/joystick.h"
 
 /* Joystick mouse emulation (David Given) */
+struct joystick_state {
+   int centerx;
+   int centery;
+   int oldbuttons;
+   int count;
+};
+
+int S_joystick(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   dev->private = malloc(sizeof(struct joystick_state));
+   
+   if (!dev->private)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+
+   memset(dev->private, 0, sizeof(struct joystick_state));
+
+   if (check_no_options(type->name, opt->text, ',') != 0) {
+      free(dev->private);
+      dev->private = NULL;
+      return -1;
+   }
+ 
+   return 0;
+}
+
 int M_joystick(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    struct JS_DATA_TYPE *jdata = (void*)data;
-   static int centerx = 0;
-   static int centery = 0;
-   static int oldbuttons = 0;
-   static int count = 0;
+   struct joystick_state *joy_state = dev->private;
    int dx;
    int dy;
 
-   count++;
-   if (count < 200) {
-      state->buttons = oldbuttons;
+   if (++joy_state->count < 200) {
+      state->buttons = joy_state->oldbuttons;
       state->dx = 0;
       state->dy = 0;
       return 0;
    }
-   count = 0;
 
-   if (centerx == 0) {
-      centerx = jdata->x;
-      centery = jdata->y;
+   joy_state->count = 0;
+
+   if (joy_state->centerx == 0) {
+      joy_state->centerx = jdata->x;
+      joy_state->centery = jdata->y;
    }
 
    state->buttons = ((jdata->buttons & 1) * GPM_B_LEFT) |
                     ((jdata->buttons & 2) * GPM_B_RIGHT);
-   oldbuttons     = state->buttons;
+   joy_state->oldbuttons = state->buttons;
 
-   dx             = (jdata->x - centerx) >> 6;
-   dy             = (jdata->y - centery) >> 6;
+   dx = (jdata->x - joy_state->centerx) >> 6;
+   dy = (jdata->y - joy_state->centery) >> 6;
 
    if (dx > 0) state->dx =   dx * dx;
    else        state->dx = -(dx * dx);
@@ -82,8 +108,3 @@
    return 0;
 }
 
-/* indent: use three spaces. no tab. not two or four. three */
-
-/* Local Variables: */
-/* c-indent-level: 3 */
-/* End: */
diff -urN gpm-orig/src/protocol/ps2.c gpm/src/protocol/ps2.c
--- gpm-orig/src/protocol/ps2.c	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/protocol/ps2.c	2003-10-24 12:15:14.000000000 -0500
@@ -50,36 +50,20 @@
 #define GPM_AUX_RESET         0xFF  /* Reset aux device */
 #define GPM_AUX_ACK           0xFA  /* Command byte ACK. */
 
+enum ps2_type {
+   PS2_BARE,
+   PS2_GENPS,
+   PS2_IMPS,
+   PS2_EXPS
+};
 
 struct ps2_options {
+   enum ps2_type type;
    int   probe_extensions;
    int   glidepoint_tap;
    int   tap_active;
 };
 
-int get_glidepoint_tap_option(char *proto, char *opttext)
-{
-   static int glidepoint_tap;
-   static struct option_helper optioninfo[] = {
-      { "glidepoint_tap", OPT_INT, u: { iptr: &glidepoint_tap } },
-      { "", OPT_END }
-   };
-   int rslt;
-   
-   if ((rslt = parse_options(proto, opttext, ',', optioninfo)) < 0)
-      return -1;
-
-    if (rslt > 0) {
-      if (glidepoint_tap < 1 || glidepoint_tap > 3) {
-         gpm_report(GPM_PR_ERR, "%s: glidepoint_tap only accepts values 1..3", proto);
-         return -1;
-      }
-      return GPM_B_LEFT >> (glidepoint_tap - 1);
-  }
-
-   return 0;
-}
-
 /*
  * Sends the SEND_ID command to the ps2-type mouse.
  * Return one of GPM_AUX_ID_...
@@ -91,12 +75,11 @@
 
    write(fd, &c, 1);
    read(fd, &c, 1);
-   if (c != GPM_AUX_ACK) {
-      return(GPM_AUX_ID_ERROR);
-   }
+   if (c != GPM_AUX_ACK)
+      return GPM_AUX_ID_ERROR;
+   
    read(fd, &id, 1);
-
-   return(id);
+   return id;
 }
 
 /**
@@ -105,7 +88,7 @@
  * 
  * Returns 0 if OK, or >0 if 1 or more errors occurred.
  */
-static int write_to_mouse(int fd, unsigned char *data, size_t len)
+static int write_to_mouse(int fd, unsigned char *data, size_t len, int flush)
 {
    int i;
    int error = 0;
@@ -117,9 +100,39 @@
    }
 
    /* flush any left-over input */
-   usleep (30000);
-   tcflush (fd, TCIFLUSH);
-   return(error);
+   if (flush) {
+      usleep (30000);
+      tcflush (fd, TCIFLUSH);
+   }
+
+   return error;
+}
+
+/**
+ * Checks response of the device, 
+ * waits up to 200ms for data to arrive.
+ * 
+ * Returns 0 if response matches
+ */
+static int check_mouse_response(int fd, unsigned char *data, size_t len)
+{
+   unsigned char response[32];
+   struct timeval start, now;
+   int to_go = len;
+
+   GET_TIME(start);
+   do {
+      to_go -= read(fd, response, to_go);
+      GET_TIME(now);
+      if (DIF_TIME(start, now) > 200)
+         return -1;
+   } while (to_go > 0);
+
+   /* flush any left-over input */
+   usleep(30000);
+   tcflush(fd, TCIFLUSH);
+
+   return memcmp(data, response, len);    
 }
 
 static int ps2_parse_options(struct ps2_options *ps2_opts, char *opttext)
@@ -161,10 +174,10 @@
    int id = GPM_AUX_ID_PS2;
 
    /* Do a basic init in case the mouse is confused */
-   write_to_mouse(fd, basic_init, sizeof (basic_init));
+   write_to_mouse(fd, basic_init, sizeof (basic_init), 1);
 
    /* Now try again and make sure we have a PS/2 mouse */
-   if (write_to_mouse(fd, basic_init, sizeof (basic_init)) != 0) {
+   if (write_to_mouse(fd, basic_init, sizeof (basic_init), 1) != 0) {
       gpm_report(GPM_PR_ERR, "ps2: mouse initialization failed");
       return -1;
    }
@@ -172,7 +185,7 @@
    if (probe_extensions) {
  
       /* Try to switch to IMPS/2 protocol */
-      if (write_to_mouse(fd, imps2_magic, sizeof (imps2_magic)) != 0) {
+      if (write_to_mouse(fd, imps2_magic, sizeof (imps2_magic), 1) != 0) {
          gpm_report(GPM_PR_ERR, "ps2: protocol extension probe failed");
          return -1;
       }
@@ -184,7 +197,7 @@
       
       if (id == GPM_AUX_ID_IMPS2) {
          /* Good... and what about ExPS/2? */
-         if (write_to_mouse(fd, exps2_magic, sizeof (exps2_magic)) != 0) {
+         if (write_to_mouse(fd, exps2_magic, sizeof (exps2_magic), 1) != 0) {
             gpm_report(GPM_PR_ERR, "ps2: protocol extension probe failed");
             return -1;
          } 
@@ -219,22 +232,16 @@
                  "%s: Can't allocate memory for internal data", type->name);
    memset(ps2_opts, 0, sizeof(struct ps2_options));
 
-   if (ps2_parse_options(ps2_opts, opt->text) != 0) {
-      free(ps2_opts);
-      dev->private = NULL;
-      return -1;
-   }
+   if (ps2_parse_options(ps2_opts, opt->text) != 0)
+      goto init_fail;
  
-   if ((id = ps2_probe(dev->fd, ps2_opts->probe_extensions)) == GPM_AUX_ID_ERROR) {
-      free(ps2_opts);
-      dev->private = NULL;
-      return -1;
-   }
+   if ((id = ps2_probe(dev->fd, ps2_opts->probe_extensions)) == GPM_AUX_ID_ERROR)
+      goto init_fail;
 
    dev->packetlen = id == GPM_AUX_ID_PS2 ? 3 : 4;
 
    /* And do the real initialisation */
-   if (write_to_mouse(dev->fd, ps2_init, sizeof (ps2_init)) != 0)
+   if (write_to_mouse(dev->fd, ps2_init, sizeof (ps2_init), 1) != 0)
       gpm_report(GPM_PR_WARN, "ps2: setup sequence failed, continuing");
    
    return 0;
@@ -277,7 +284,7 @@
    dev->packetlen = id == GPM_AUX_ID_PS2 ? 3 : 4;
 
    /* And do the real initialisation */
-   if (write_to_mouse(dev->fd, ps2_init, sizeof (ps2_init)) != 0)
+   if (write_to_mouse(dev->fd, ps2_init, sizeof (ps2_init), 1) != 0)
       gpm_report(GPM_PR_WARN, "ps2: setup sequence failed, continuing");
    
    return 0;
@@ -287,24 +294,28 @@
 {
    struct ps2_options *ps2_opts = dev->private;
 
-   state->dx = state->dy = state->wdx = state->wdy = 0;
-
    state->buttons = ((data[0] & 1) << 2) |  /* left              */
                     ((data[0] & 6) >> 1);   /* middle and right  */
-   
-   if (data[0] == 0 && ps2_opts->glidepoint_tap) // by default this is false
-      state->buttons = ps2_opts->tap_active = ps2_opts->glidepoint_tap;
-   else if (ps2_opts->tap_active) {
-      if (data[0] == 8)
-         ps2_opts->tap_active = 0;
-      state->buttons = ps2_opts->tap_active;
+
+   if (ps2_opts->type == PS2_GENPS) {
+      /* map extra Genius buttons to middle */
+      state->buttons |= !!(data[3]) * GPM_B_MIDDLE;
+   } else {
+      if (data[0] == 0 && ps2_opts->glidepoint_tap) // by default this is false
+         state->buttons = ps2_opts->tap_active = ps2_opts->glidepoint_tap;
+      else if (ps2_opts->tap_active) {
+         if (data[0] == 8)
+            ps2_opts->tap_active = 0;
+         state->buttons = ps2_opts->tap_active;
+      }
    }
 
    /* Standard movement.. */
-   state->dx = (data[0] & 0x10) ? data[1] - 256 : data[1];
-   state->dy = (data[0] & 0x20) ? -(data[2] - 256) : -data[2];
+   state->dx = data[1] ?  ((data[0] & 0x10) ? data[1] - 256 : data[1]) : 0;
+   state->dy = data[2] ? -((data[0] & 0x20) ? data[2] - 256 : data[2]) : 0;
   
-   if (dev->packetlen == 4) { 
+   state->wdx = state->wdy = 0;
+   if (ps2_opts->type >= PS2_IMPS) { 
       /* The wheels.. */
       switch (data[3] & 0x0f) {
          case 0x0e: state->wdx = +1; break;
@@ -396,7 +407,7 @@
 
    if (!check_no_options(type->name, opt->text, ',')) return -1;
 
-   if (write_to_mouse(dev->fd, magic, sizeof(magic)) != 0) {
+   if (write_to_mouse(dev->fd, magic, sizeof(magic), 0) != 0) {
       gpm_report(GPM_PR_ERR, "netmouse: initialization failed");
       return -1;
    }
@@ -413,8 +424,3 @@
    return 0;
 }
 
-/* indent: use three spaces. no tab. not two or four. three */
-
-/* Local Variables: */
-/* c-indent-level: 3 */
-/* End: */
diff -urN gpm-orig/src/protocol/serial.c gpm/src/protocol/serial.c
--- gpm-orig/src/protocol/serial.c	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/protocol/serial.c	2003-10-31 10:39:56.000000000 -0500
@@ -43,26 +43,31 @@
    int            baud;
 };
 
+int S_serial(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct sermouse_options *sermouse_opts;
+
+   dev->private = sermouse_opts = malloc(sizeof(struct sermouse_options));
+   if (!sermouse_opts)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+   
+   /* accept "-o baud=xxx,{dtr|rts|both}" */
+   if (parse_generic_serial_options(type->name, opt->text, 
+                                    &sermouse_opts->baud, &sermouse_opts->lines) < 0) {
+      dev->private = NULL;
+      free(sermouse_opts);
+      return -1;
+   }
+
+   return 0;
+}
+
 int I_serial(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct sermouse_options *sermouse_opts = dev->private;
    int i;
 
-   if (!sermouse_opts) {
-      dev->private = sermouse_opts = malloc(sizeof(struct sermouse_options));
-      if (!sermouse_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-      
-      /* accept "-o baud=xxx,{dtr|rts|both}" */
-      if (parse_generic_serial_options(type->name, opt->text, 
-                                       &sermouse_opts->baud, &sermouse_opts->lines) < 0) {
-         dev->private = NULL;
-         free(sermouse_opts);
-         return -1;
-      }
-   }
-
    set_modem_lines(dev->fd, sermouse_opts->lines);
    flush_pending_input(dev->fd);
 
@@ -135,25 +140,29 @@
    return 0;
 }
 
+int S_ms(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct msmouse_options *msmouse_opts;
+
+   dev->private = msmouse_opts = malloc(sizeof(struct msmouse_options));
+   if (!msmouse_opts)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+
+   if (msmouse_parse_options(type->name, opt->text, msmouse_opts) < 0) {
+      free(msmouse_opts);
+      dev->private = NULL;
+      return -1;
+   }
+
+   return 0;
+}
+
 int I_ms(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct msmouse_options *msmouse_opts = dev->private;
    int i;
 
-   if (!msmouse_opts) {
-      dev->private = msmouse_opts = malloc(sizeof(struct msmouse_options));
-      if (!msmouse_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-
-gpm_report(GPM_PR_ERR, "<%s> <%s>", type->name, opt->text);
-      if (msmouse_parse_options(type->name, opt->text, msmouse_opts) < 0) {
-         free(msmouse_opts);
-         dev->private = NULL;
-         return -1;
-      }
-   }
-
    set_modem_lines(dev->fd, msmouse_opts->lines);
    flush_pending_input(dev->fd);
 
@@ -279,16 +288,16 @@
 /* M_brw is a variant of m$ 'Intellimouse' the middle button is different */
 int M_brw(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
-   state->buttons= ((data[0] & 0x20) >> 3)   /* left */
-      | ((data[3] & 0x20) >> 4)   /* middle */
-      | ((data[0] & 0x10) >> 4);   /* right */
-   state->dx =      (signed char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
-   state->dy =      (signed char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+   state->buttons = ((data[0] & 0x20) >> 3) |  /* left */
+                    ((data[3] & 0x20) >> 4) |  /* middle */
+                    ((data[0] & 0x10) >> 4);   /* right */
+   state->dx = (signed char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+   state->dy = (signed char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
    if ((data[0] & 0xC0) != 0x40 ||
        (data[1] & 0xC0) != 0x00 ||
        (data[2] & 0xC0) != 0x00 ||
        (data[3] & 0xC0) != 0x00) {
-      gpm_report(GPM_PR_DEBUG,GPM_MESS_SKIP_DATAP,data[0],data[1],data[2],data[3]);
+      gpm_report(GPM_PR_DEBUG, GPM_MESS_SKIP_DATAP, data[0], data[1], data[2], data[3]);
       return -1;
    }
    /* wheel (dz) is (data[3] & 0x0f) */
@@ -307,9 +316,9 @@
    return 0;
 }
 
-int I_empty(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+int S_empty(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-    return check_no_options(type->name, opt->text, ',')  == 0;
+    return check_no_options(type->name, opt->text, ',') == 0;
 }
 
 /* ---------------------- Mouse systems ---------------------------------- */
@@ -328,11 +337,11 @@
    int dx, dy;
 
    /* sluggish... */
-   buffer[0]=(state->buttons ^ 0x07) | 0x80;
+   buffer[0] =(state->buttons ^ 0x07) | 0x80;
+   buffer[3] = state->dx - (buffer[1] = state->dx/2); /* Markus */
+   buffer[4] = -state->dy - (buffer[2] = -state->dy/2);
    dx = limit_value(state->dx, -256, 254);
-   buffer[3] =  state->dx - (buffer[1] = state->dx/2); /* Markus */
    dy = limit_value(state->dy, -256, 254);
-   buffer[4] = -state->dy - (buffer[2] = -state->dy/2);
    return write(fd, buffer, 5);
 }
 
@@ -352,6 +361,37 @@
    int   baud;
 };
 
+int S_logi(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct logitech_options *logi_opts;
+   struct stat buf;
+   int busmouse;
+  
+   dev->private = logi_opts = malloc(sizeof(struct logitech_options));
+   if (!logi_opts)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+
+   if (parse_serial_speed(type->name, opt->text, &logi_opts->baud) < 0)
+      goto setup_fail;
+
+   if (fstat(dev->fd, &buf) == -1) {
+      gpm_report(GPM_PR_ERR, "%s: can't fstat the device");
+      goto setup_fail;
+   }
+
+   busmouse = MAJOR(buf.st_rdev) != 4; /* 4 is serial major */
+   /* fix the howmany field, so that serial mice have 1, while busmice have 3 */
+   dev->howmany = busmouse ? 3 : 1;
+
+   return 0;
+
+setup_fail:
+   free(logi_opts);
+   dev->private = NULL;
+   return -1;
+}
+
 int I_logi(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    static struct {
@@ -367,35 +407,10 @@
       { 125, "Q" },
       { 1E9, "N" }, 
    };
-
    
    struct logitech_options *logi_opts = dev->private;
-   struct stat buf;
-   int busmouse;
    int i;
   
-   if (!logi_opts) {
-      dev->private = logi_opts = malloc(sizeof(struct logitech_options));
-      if (!logi_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-      if (parse_serial_speed(type->name, opt->text, &logi_opts->baud) < 0) {
-         free(logi_opts);
-         dev->private = NULL;
-         return -1;
-      }
-
-      if (fstat(dev->fd, &buf) == -1) {
-         gpm_report(GPM_PR_ERR, "%s: can't fstat the device");
-         free(logi_opts);
-         dev->private = NULL;
-         return -1;
-      }
-      busmouse = MAJOR(buf.st_rdev) != 4; /* 4 is serial major */
-      /* fix the howmany field, so that serial mice have 1, while busmice have 3 */
-      dev->howmany = busmouse ? 3 : 1;
-   }
-
    /* change from any available speed to the chosen one */
    for (i = 9600; i >= 1200; i /= 2) 
       serial_setspeed(dev->fd, i, logi_opts->baud, 1, type->flags);
@@ -419,21 +434,6 @@
    struct sermouse_options *logimsc_opts = dev->private;
    int i;
 
-   if (!logimsc_opts) {
-      dev->private = logimsc_opts = malloc(sizeof(struct sermouse_options));
-      if (!logimsc_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-      
-      /* accept "-o baud=xxx,{dtr|rts|both}" */
-      if (parse_generic_serial_options(type->name, opt->text, 
-                                       &logimsc_opts->baud, &logimsc_opts->lines) < 0) {
-         dev->private = NULL;
-         free(logimsc_opts);
-         return -1;
-      }
-   }
-
    set_modem_lines(dev->fd, logimsc_opts->lines);
    flush_pending_input(dev->fd);
    write(dev->fd, "QU", 2);
@@ -492,23 +492,29 @@
    return 0;
 }
 
+int S_mman(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct mman_options *mman_opts;
+
+   dev->private = mman_opts = malloc(sizeof(struct mman_options));
+   if (!mman_opts)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+
+   if (mman_parse_options(opt->text, mman_opts) < 0) {
+      free(mman_opts);
+      dev->private = NULL;
+      return -1;
+   }
+
+   return 0;
+}
+
 int I_mman(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct mman_options *mman_opts = dev->private;
    int i;
 
-   if (!mman_opts) {
-      dev->private = mman_opts = malloc(sizeof(struct mman_options));
-      if (!mman_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-      if (mman_parse_options(opt->text, mman_opts) < 0) {
-         free(mman_opts);
-         dev->private = NULL;
-         return -1;
-      }
-   }
-
    set_modem_lines(dev->fd, mman_opts->lines);
    flush_pending_input(dev->fd);
 
@@ -630,23 +636,29 @@
    unsigned int   lines;
 };
 
-int I_vsxxx_aa(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+int S_vsxxx_aa(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct vsxxx_options *vsxxx_opts = dev->private;
-   int i;
   
-   if (!vsxxx_opts) {
-      dev->private = vsxxx_opts = malloc(sizeof(struct vsxxx_options));
-      if (!vsxxx_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-      if (parse_serial_lines(type->name, opt->text, &vsxxx_opts->lines) < 0) {
-         free(vsxxx_opts);
-         dev->private = NULL;
-         return -1;
-      }
+   dev->private = vsxxx_opts = malloc(sizeof(struct vsxxx_options));
+   if (!vsxxx_opts)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+
+   if (parse_serial_lines(type->name, opt->text, &vsxxx_opts->lines) < 0) {
+      free(vsxxx_opts);
+      dev->private = NULL;
+      return -1;
    }
 
+   return 0;
+}
+
+int I_vsxxx_aa(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct vsxxx_options *vsxxx_opts = dev->private;
+   int i;
+ 
    set_modem_lines(dev->fd, vsxxx_opts->lines);
    flush_pending_input(dev->fd);
 
@@ -665,23 +677,28 @@
    unsigned int   lines;
 };
 
+int S_pnp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct pnp_options *pnp_opts; 
+
+   dev->private = pnp_opts = malloc(sizeof(struct pnp_options));
+   if (!pnp_opts)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+   if (parse_serial_lines(type->name, opt->text, &pnp_opts->lines) < 0) {
+      free(pnp_opts);
+      dev->private = NULL;
+      return -1;
+   }
+
+   return 0;
+}
+
 int I_pnp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct pnp_options *pnp_opts = dev->private; 
    struct termios tty;
 
-   if (!pnp_opts) {
-      dev->private = pnp_opts = malloc(sizeof(struct pnp_options));
-      if (!pnp_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-      if (parse_serial_lines(type->name, opt->text, &pnp_opts->lines) < 0) {
-         free(pnp_opts);
-         dev->private = NULL;
-         return -1;
-      }
-   }
-
    set_modem_lines(dev->fd, pnp_opts->lines);
 
    /*
diff -urN gpm-orig/src/protocol/synaptics.c gpm/src/protocol/synaptics.c
--- gpm-orig/src/protocol/synaptics.c	2003-10-21 15:38:40.000000000 -0500
+++ gpm/src/protocol/synaptics.c	2003-10-23 14:27:00.000000000 -0500
@@ -425,6 +425,7 @@
 					   * Do not turn it on per default.                         */
 
 
+static unsigned int synaptics_lines;   /* what serail port control lines should be used */
 /*
 ** Types for describing actions.  When adding a new action, place it as
 ** the last item. It will break old configurefiles otherwise.
@@ -3152,19 +3153,16 @@
 }
 
 /*
-** I_synaptics_serial
+** S_synaptics_serial
 ** 
-** Initialize the synaptics touchpad.  Read model and identification.
-** Determine the size of the touchpad in "pixels".  Select 6/7/8 byte packets,
-** select 9600 baud, and select high packet rate.
+** Parse command line options.
 */
-int I_synaptics_serial(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+int S_synaptics_serial(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-  static unsigned int lines;
   static struct option_helper optioninfo[] = {
-     { "dtr",  OPT_BOOL, u: { iptr: &lines }, value: TIOCM_DTR },
-     { "rts",  OPT_BOOL, u: { iptr: &lines }, value: TIOCM_RTS },
-     { "both", OPT_BOOL, u: { iptr: &lines }, value: TIOCM_DTR | TIOCM_RTS },
+     { "dtr",  OPT_BOOL, u: { iptr: &synaptics_lines }, value: TIOCM_DTR },
+     { "rts",  OPT_BOOL, u: { iptr: &synaptics_lines }, value: TIOCM_RTS },
+     { "both", OPT_BOOL, u: { iptr: &synaptics_lines }, value: TIOCM_DTR | TIOCM_RTS },
      { "",     OPT_END}
   };
   int lineopts;
@@ -3175,13 +3173,25 @@
   if ((lineopts = count_modem_line_options(optioninfo)) > 1) {
     gpm_report(GPM_PR_ERR, "%s: only one of 'dtr', 'rts' or 'both' options can be set at a time", type->name);
     return -1;
-  } else if (lineopts == 0) {
-    lines = 0;
   } 
+  
+  if (lineopts == 0)
+    synaptics_lines = 0;
 
+  return 0;
+}
+/*
+** I_synaptics_serial
+** 
+** Initialize the synaptics touchpad.  Read model and identification.
+** Determine the size of the touchpad in "pixels".  Select 6/7/8 byte packets,
+** select 9600 baud, and select high packet rate.
+*/
+int I_synaptics_serial(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
   gpm_report(GPM_PR_DEBUG,"Initializing Synaptics Serial TouchPad");
 
-  set_modem_lines(dev->fd, lines);
+  set_modem_lines(dev->fd, synaptics_lines);
   flush_pending_input(dev->fd);
   serial_setspeed(dev->fd, 1200, 1200, 1, type->flags);
 
diff -urN gpm-orig/src/protocol/tablet.c gpm/src/protocol/tablet.c
--- gpm-orig/src/protocol/tablet.c	2003-10-21 15:38:40.000000000 -0500
+++ gpm/src/protocol/tablet.c	2003-10-22 17:09:34.000000000 -0500
@@ -79,28 +79,29 @@
    return select(fd + 1, &readfds, NULL, NULL, &timeout) == 1;
 }
  
+int S_summa(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) 
+{
+   if (!check_no_options(type->name, opt->text, ','))
+      return -1;
+
+   if ((dev->private = malloc(sizeof(struct summa_data))) == NULL)
+      gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
+
+   return 0;
+}
+
 int I_summa(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) 
 {
    struct summa_data *summa = dev->private;
    char data[5];
 
-   if (!summa) {
-      if (!check_no_options(type->name, opt->text, ','))
-         return -1;
-      dev->private = summa = malloc(sizeof(struct summa_data));
-      if (!summa) {
-         gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
-         return -1;
-      }
-      summa->id = -1; /* "don't know" */
-   }
-
    /* Set speed to 9600bps */
    serial_setspeed(dev->fd, 1200, 9600, 1, B9600|CS8|CREAD|CLOCAL|HUPCL|PARENB|PARODD);  
    summa_reset(dev->fd); 
  
    write(dev->fd, SS_PROMPT_MODE, strlen(SS_PROMPT_MODE));
   
+   summa->id = -1; /* "don't know" */
    if (strstr(type->name, "acecad") != NULL) 
       summa->id = 11;
 
@@ -197,22 +198,22 @@
    unsigned int lines;
 };
 
-int M_geni(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
+int S_geni(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-   /* this is a little confusing. If we use the stylus, we
-    * have three buttons (tip, lower, upper), and if
-    * we use the puck we have four buttons. (And the
-    * protocol is a little mangled if several of the buttons
-    * on the puck are pressed simultaneously. 
-    * I don't use the puck, hence I try to decode three buttons
-    * only. tip = left, lower = middle, upper = right
-    */
-   state->buttons = (data[0] & 0x01) << 2 | 
-                    (data[0] & 0x02) |
-                    (data[0] & 0x04) >> 2;
+   struct geni_options *geni_opts = dev->private;
 
-   state->dx = (data[1] & 0x3f) * (data[0] & 0x10 ?  1 : -1);   
-   state->dy = (data[2] & 0x3f) * (data[0] & 0x08 ? -1 :  1);
+   dev->private = geni_opts = malloc(sizeof(struct geni_options));
+   if (!geni_opts)
+      gpm_report(GPM_PR_OOPS,
+                 "%s: Can't allocate memory for internal data", type->name);
+
+   if (parse_serial_lines(type->name, opt->text, &geni_opts->lines) < 0) {
+      free(geni_opts);
+      dev->private = NULL;
+      return -1;
+   }
+
+   gpm_report(GPM_PR_INFO, GPM_MESS_INIT_GENI);
 
    return 0;
 }
@@ -222,19 +223,6 @@
    struct geni_options *geni_opts = dev->private;
    int i;
 
-   if (!geni_opts) {
-      dev->private = geni_opts = malloc(sizeof(struct geni_options));
-      if (!geni_opts)
-         gpm_report(GPM_PR_OOPS,
-                    "%s: Can't allocate memory for internal data", type->name);
-      if (parse_serial_lines(type->name, opt->text, &geni_opts->lines) < 0) {
-         free(geni_opts);
-         dev->private = NULL;
-         return -1;
-      }
-      gpm_report(GPM_PR_INFO, GPM_MESS_INIT_GENI);
-   }
-
    set_modem_lines(dev->fd, geni_opts->lines);
    flush_pending_input(dev->fd);
 
@@ -248,6 +236,26 @@
    return 0;
 }
 
+int M_geni(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
+{
+   /* this is a little confusing. If we use the stylus, we
+    * have three buttons (tip, lower, upper), and if
+    * we use the puck we have four buttons. (And the
+    * protocol is a little mangled if several of the buttons
+    * on the puck are pressed simultaneously. 
+    * I don't use the puck, hence I try to decode three buttons
+    * only. tip = left, lower = middle, upper = right
+    */
+   state->buttons = (data[0] & 0x01) << 2 | 
+                    (data[0] & 0x02) |
+                    (data[0] & 0x04) >> 2;
+
+   state->dx = (data[1] & 0x3f) * (data[0] & 0x10 ?  1 : -1);   
+   state->dy = (data[2] & 0x3f) * (data[0] & 0x08 ? -1 :  1);
+
+   return 0;
+}
+
 
 /* ------------------------------------------------------------------ */
 /* 
@@ -326,7 +334,7 @@
    return select(fd + 1, &readfds, NULL, NULL, &timeout) == 1;
 }
 
-int I_wacom(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+int S_wacom(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    /*
     * We do both modes, relative and absolute, with the same function.
@@ -343,27 +351,31 @@
       { "",          OPT_END } 
    };
 
+   int rslt;
+
+   if ((rslt = parse_options(type->name, opt->text, ',', optioninfo)) < 0)
+      return -1;
+   
+   if (is_option_present(optioninfo, "absolute") && 
+       is_option_present(optioninfo, "relative")) {
+      gpm_report(GPM_PR_ERR, 
+         "%s: can not be in absolute and relative mode at the same time", type->name);
+      return -1;
+   }  
+
+   opt->absolute = rslt ? do_absolute : 0;
+
+   if ((dev->private = malloc(sizeof(struct summa_data))) == NULL)
+      gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
+
+   return 0;
+}
+
+int I_wacom(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
    struct wacom_data *wacom = dev->private; 
    char buffer[50];
-   int i, rslt;
-
-   if (!wacom) {
-      if ((rslt = parse_options(type->name, opt->text, ',', optioninfo)) < 0)
-         return -1;
-      else if (rslt > 1) {
-         gpm_report(GPM_PR_ERR, 
-            "%s: can not be in absolute and relative mode at the same time", type->name);
-         return -1;
-      }  
-      opt->absolute = rslt ? do_absolute : 0;
-
-      dev->private = wacom = malloc(sizeof(struct summa_data));
-      if (!wacom) {
-         gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
-         return -1;
-      }
-      wacom->model = -1; /* "don't know" */
-   }
+   int i;
 
    wacom_reset(dev->fd);
 
@@ -377,6 +389,7 @@
    if (wacom_wait_data(dev->fd))
       read(dev->fd, buffer, sizeof(buffer));
 
+   wacom->model = -1; /* "don't know" */
    /* Search for matching modell */
    for (i = 0; i < sizeof(wacom_models) / sizeof(wacom_models[0]); i++) { 
       if (!strncmp(buffer + 2, wacom_models[i].magic, 2)) {
@@ -502,7 +515,7 @@
    int ox, oy;
 };
 
-int I_calus(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+int S_calus(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    static int do_absolute;
    static int baud;
@@ -513,28 +526,34 @@
    };
 
    struct calus_data *calus = dev->private; 
-   int i, rslt;
+   int rslt;
 
-   if (!calus) {
-      do_absolute = 0;
-      if ((rslt = parse_options(type->name, opt->text, ',', optioninfo)) < 0)
-         return -1;
-
-      if (is_option_present(optioninfo, "absolute") && 
-          is_option_present(optioninfo, "relative")) {
-         gpm_report(GPM_PR_ERR, 
-            "%s: can not be in absolute and relative mode at the same time", type->name);
-         return -1;
-      }
-      opt->absolute = rslt ? do_absolute : 0;
+   do_absolute = 0;
+   if ((rslt = parse_options(type->name, opt->text, ',', optioninfo)) < 0)
+      return -1;
 
-      dev->private = calus = malloc(sizeof(struct summa_data));
-      if (!calus) {
-         gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
-         return -1;
-      }
-      calus->baud = is_option_present(optioninfo, "baud") ? baud : 9600;
+   if (is_option_present(optioninfo, "absolute") && 
+       is_option_present(optioninfo, "relative")) {
+      gpm_report(GPM_PR_ERR, 
+         "%s: can not be in absolute and relative mode at the same time", type->name);
+      return -1;
    }
+   opt->absolute = rslt ? do_absolute : 0;
+
+   dev->private = calus = malloc(sizeof(struct summa_data));
+   if (!calus)
+      gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
+
+   calus->baud = is_option_present(optioninfo, "baud") ? baud : 9600;
+
+   return 0;
+}
+
+
+int I_calus(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct calus_data *calus = dev->private; 
+   int i;
 
    flush_pending_input(dev->fd);
 
@@ -646,6 +665,14 @@
    int   width, height;
 };  
 
+int S_wp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   if ((dev->private = malloc(sizeof(struct wp_data))) == NULL)
+      gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
+
+   return 0;
+}
+
 int I_wp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct wp_data *wp = dev->private;
@@ -679,19 +706,11 @@
    if (count < 2 || tablet_info[0] != 'K' || tablet_info[1] != 'W') 
       return -1;
    
-   if (!wp) {
-      dev->private = wp = malloc(sizeof(struct wp_data));
-      if (!wp) {
-         gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name); 
-         return -1;
-      }
-      wp->height = wp->width = -1;
-   }
-
    /*  Now, we want the width and height of the tablet.  They should be 
      of the form "X###" and "Y###" where ### is the number of units of
      the tablet.  The model I've got is "X130" and "Y095", but I guess
      there might be other ones sometime.  */
+   wp->height = wp->width = -1;
    for (pos = 2; pos < count; pos++) {
       if (tablet_info[pos] == 'X' || tablet_info[pos] == 'Y') {
          if (pos + 3 < count) {
diff -urN gpm-orig/src/protocol/touchscreen.c gpm/src/protocol/touchscreen.c
--- gpm-orig/src/protocol/touchscreen.c	2003-10-21 15:38:40.000000000 -0500
+++ gpm/src/protocol/touchscreen.c	2003-10-22 17:12:30.000000000 -0500
@@ -58,19 +58,20 @@
    struct timeval uptv, tv; /* time of last up, and down events */
 };
 
+int S_mtouch(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   if ((dev->private = malloc(sizeof(struct mtouch_data))) == NULL)
+      gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name);
+
+   return 0;
+}
+
 int I_mtouch(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-   struct termios tty;
    struct mtouch_data *mtouch = dev->private;
+   struct termios tty;
 
-   if (!mtouch) {
-      dev->private = mtouch = malloc(sizeof(struct mtouch_data));
-      if (!mtouch) {
-         gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name);
-         return -1;
-      }
-      mtouch->avgx = mtouch->avgy = -1;
-   }
+   mtouch->avgx = mtouch->avgy = -1;
 
    /* Set speed to 9600bps (copied from I_summa :) */
    tcgetattr(dev->fd, &tty);
@@ -84,7 +85,7 @@
    tcsetattr(dev->fd, TCSAFLUSH, &tty);
 
    /* Turn it to "format tablet" and "mode stream" */
-   write(dev->fd,"\001MS\r\n\001FT\r\n",10);
+   write(dev->fd, "\001MS\r\n\001FT\r\n", 10);
   
    return 0;
 }
@@ -170,8 +171,37 @@
    int debounce;            /* milliseconds: ignore shorter taps */
    int calib[4];            /* x0,y0 x1,y1 (measured at 1/8 and 7/8) */
 };
- 
-int I_gunze(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+
+static void gunze_calibrate(struct gunze_data *gunze)
+{ 
+   FILE *f;
+   char s[80];
+   int i, calib_ok = 0;
+
+   /* retrieve calibration, if not existent, use defaults (uncalib) */
+   if ((f = fopen(GUNZE_CALIBRATION_FILE, "r")) != NULL) {
+      fgets(s, 80, f); /* discard the comment */
+      if (fscanf(f, "%d %d %d %d", 
+                 gunze->calib, gunze->calib + 1, gunze->calib + 2, gunze->calib + 3) == 4)
+         calib_ok = 1;
+      fclose(f);
+
+      /* Hmm... check if the data is sane */
+      for (i = 0; i < 4; i++)
+         if (gunze->calib[i] & ~1023) 
+            calib_ok = 0;
+      if (gunze->calib[0] == gunze->calib[2]) calib_ok = 0;
+      if (gunze->calib[1] == gunze->calib[4]) calib_ok = 0;
+   }
+
+   if (!calib_ok) {
+      gpm_report(GPM_PR_ERR, GPM_MESS_GUNZE_CALIBRATE, option.progname);
+      gunze->calib[0] = gunze->calib[1] = 128; /* 1/8 */
+      gunze->calib[2] = gunze->calib[3] = 896; /* 7/8 */
+   }
+}
+
+int S_gunze(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    static int avg, debounce, baud;
    static struct option_helper optioninfo[] = {
@@ -182,37 +212,40 @@
       {"",         OPT_END}
    };
 
-   struct gunze_data *gunze = dev->private;
-   struct termios tty;
-   FILE *f;
-   char s[80];
-   int i, calibok = 0;
-
+   struct gunze_data *gunze;
   
-   if (!gunze) {
-      dev->private = gunze = malloc(sizeof(struct gunze_data));
-      if (!gunze) {
-         gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name);
-         return -1;
-      }
- 
-      memset(gunze, 0, sizeof(struct gunze_data));
-
-      if (parse_options(type->name, opt->text, ',', optioninfo) < 0) {
-         free(gunze);
-         dev->private = NULL;
-         return -1;
-      }
+   dev->private = gunze = malloc(sizeof(struct gunze_data));
+   if (!gunze)
+      gpm_report(GPM_PR_OOPS, "%s: Can't allocate memory for internal data", type->name);
+
+   memset(gunze, 0, sizeof(struct gunze_data));
+
+   if (parse_options(type->name, opt->text, ',', optioninfo) < 0) {
+      free(gunze);
+      dev->private = NULL;
+      return -1;
+   }
 
-      gunze->avg = is_option_present(optioninfo, "smooth") ? avg : 9;
-      gunze->debounce = is_option_present(optioninfo, "debounce") ? debounce : 100;
-      gunze->baud = is_option_present(optioninfo, "baud") ? baud : 19200;
-      if (gunze->baud != 9600 && gunze->baud != 19200) {
-         gpm_report(GPM_PR_ERR, GPM_MESS_GUNZE_WRONG_BAUD, option.progname, type->name);
-         gunze->baud = 19200;
-      }
+   gunze->avg = is_option_present(optioninfo, "smooth") ? avg : 9;
+   gunze->debounce = is_option_present(optioninfo, "debounce") ? debounce : 100;
+   gunze->baud = is_option_present(optioninfo, "baud") ? baud : 19200;
+   if (gunze->baud != 9600 && gunze->baud != 19200) {
+      gpm_report(GPM_PR_WARN, GPM_MESS_GUNZE_WRONG_BAUD, option.progname, type->name);
+      gunze->baud = 19200;
    }
 
+   gunze_calibrate(gunze);
+
+   /* FIXME: try to find some information about the device */
+   
+   return 0;
+}
+
+int I_gunze(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   struct gunze_data *gunze = dev->private;
+   struct termios tty;
+  
    tcgetattr(dev->fd, &tty);
    tty.c_iflag = IGNBRK | IGNPAR;
    tty.c_oflag = 0;
@@ -223,28 +256,6 @@
    tty.c_cflag = (gunze->baud == 9600 ? B9600 : B19200) |CS8|CREAD|CLOCAL|HUPCL;
    tcsetattr(dev->fd, TCSAFLUSH, &tty);
 
-   /* FIXME: try to find some information about the device */
-
-   /* retrieve calibration, if not existent, use defaults (uncalib) */
-   f = fopen(GUNZE_CALIBRATION_FILE, "r");
-   if (f) {
-      fgets(s, 80, f); /* discard the comment */
-      if (fscanf(f, "%d %d %d %d", 
-                 gunze->calib, gunze->calib + 1, gunze->calib + 2, gunze->calib + 3) == 4)
-         calibok = 1;
-      /* Hmm... check */
-      for (i = 0; i < 4; i++)
-         if (gunze->calib[i] & ~1023) 
-            calibok = 0;
-      if (gunze->calib[0] == gunze->calib[2]) calibok = 0;
-      if (gunze->calib[1] == gunze->calib[4]) calibok = 0;
-      fclose(f);
-   }
-   if (!calibok) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_GUNZE_CALIBRATE, option.progname);
-      gunze->calib[0] = gunze->calib[1] = 128; /* 1/8 */
-      gunze->calib[2] = gunze->calib[3] = 896; /* 7/8 */
-   }
    return 0;
 }
 
diff -urN gpm-orig/src/protocol/twiddler.c gpm/src/protocol/twiddler.c
--- gpm-orig/src/protocol/twiddler.c	2003-10-21 15:38:40.000000000 -0500
+++ gpm/src/protocol/twiddler.c	2003-10-22 16:21:38.000000000 -0500
@@ -60,6 +60,8 @@
 #include "headers/protocol/twiddler.h"
 
 
+static int twiddler_baud;
+
 /* 
  * Each table is made up of 256 entries, as these are the possible chords
  * Then, there is one table for each modifier (two of them are not allowed).
@@ -460,10 +462,6 @@
    char mod[64], chord[64], *value;
    int index, lineno=0, errcount=0;
    char **table;
-   static int initcount=0;
-
-   if (initcount) return 0; /* do it only once */
-   initcount++;
 
    if (!(f = fopen(TW_SYSTEM_FILE,"r"))) {
       gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,TW_SYSTEM_FILE,strerror(errno));
@@ -528,31 +526,38 @@
    return errcount;
 }
 
-int I_twiddler(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+int S_twiddler(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-   static int baud;
    static struct option_helper optioninfo[] = {
-      { "baud", OPT_INT,  u: { iptr: &baud } },
+      { "baud", OPT_INT,  u: { iptr: &twiddler_baud } },
       { "",     OPT_END}
    };
-   int i;
 
    if (parse_options(type->name, opt->text, ',', optioninfo) < 0) 
       return -1;
 
+   if (!is_option_present(optioninfo, "baud"))
+      twiddler_baud = 2400;
+ 
    if (twiddler_key_init() != 0) 
       return -1;
 
+   return 0;
+}
+
+int I_twiddler(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
+{
+   int i;
+
    /*
    * the twiddler is a serial mouse: just drop dtr
    * and run at 2400 (unless specified differently)
    */
    set_modem_lines(dev->fd, TIOCM_DTR); 
    flush_pending_input(dev->fd);
-   if (!is_option_present(optioninfo, "baud"))
-      baud = 2400;
+   
    for (i = 9600; i >= 1200; i /= 2)
-      serial_setspeed(dev->fd, i, baud, 1, type->flags);
+      serial_setspeed(dev->fd, i, twiddler_baud, 1, type->flags);
 
    return 0;
 }
diff -urN gpm-orig/src/readtmo.c gpm/src/readtmo.c
--- gpm-orig/src/readtmo.c	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/readtmo.c	2003-11-03 14:47:42.000000000 -0500
@@ -0,0 +1,54 @@
+/*
+ * readtmo.c
+ *
+ * Copyright (c) 2003        Dmitry Torokhov <dtor@mail.ru>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ ********/
+
+#include <unistd.h>
+#include <sys/time.h>      
+
+#include "headers/readtmo.h"
+
+/*-------------------------------------------------------------------*/
+int wait_fd_data(int fd, unsigned int tmo)
+{
+   struct timeval timeout = { 0, tmo };
+   fd_set fdSet;
+
+   FD_ZERO(&fdSet);
+   FD_SET(fd, &fdSet);
+   return select(fd + 1, &fdSet, NULL, NULL, &timeout) &&
+          FD_ISSET(fd, &fdSet);
+}
+
+/*-------------------------------------------------------------------*/
+ssize_t read_tmo(int fd, void *data, size_t count, unsigned int tmo)
+{
+   ssize_t bytes, len = 0;
+
+   while (wait_fd_data(fd, tmo)) { 
+      if ((bytes = read(fd, data, count - len)) == -1)
+         return -1;
+      data += bytes;
+      len += bytes;
+      if (len >= count)
+         break;
+   }
+
+   return len;
+}
+
diff -urN gpm-orig/src/synaptics.c gpm/src/synaptics.c
--- gpm-orig/src/synaptics.c	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/synaptics.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,3307 +0,0 @@
-/*
- * synaptics.c - support for the synaptics serial and ps2 touchpads
- *
- * Copyright 1999   hdavies@ameritech.net (Henry Davies)
- *                  Geert Van der Plas provided the code to support
- *                        older Synaptics PS/2 touchpads.
- *
- *   Synpatics Passthrough Support Copyright (C) 2002 Linuxcare Inc.
- *   dkennedy@linuxcare.com (David Kennedy)
- * 
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- *
- ********/
-
-/*
-** Design/Goals
-**     I want to use the Synaptics Serial touchpad as a cursor device under
-**     Linux (gpm).  With this device I want to support operations similar
-**     to those supported by the Synaptics WinDOS driver, and some others 
-**     of my own devising.
-**
-** Features:
-**     Corner Clicks
-**         This recognizes taps on the touchpad in the corner(s) and
-**         translates them into specific actions.  Initially I am looking
-**         at actions on the order of alternate button clicks.  Other 
-**         alternatives include drags and whatnot.
-**     Edge Extensions
-**         This recognizes that the finger has moved from the center region
-**         of the touchpad and dragged to the edge area.  At which point
-**         I want to be able to extend the motion by automatically moving 
-**         in the direction of the edge.
-**     Toss n Catch
-**         This recognizes a quick motion of the finger on the touchpad and
-**         uses that to define a velocity vector for the cursor.  A tap
-**         on the touchpad at a later time catches (stops) the cursor.
-**     Tap n Drag
-**         A quick tap of the touchpad followed by finger motion on the 
-**         touchpad initiates what would be a drag with a normal mouse
-**         type device.
-**     Pressure Sensitive Velocity
-**         The Synaptics touchpad indicates the touch pressure of the finger
-**         (really an interface area) this is used to accelerate the cursor
-**         motion.  This can be used in the normal motion, Tap n Drag, or
-**         Edge Extension modes.  In normal motion and Tap n Drag this may 
-**         be awkward due to increased friction caused by the pressure.
-**
-** Parameters:
-**     search below for configuration constants
-*/
-
-
-/* Pebl - pebl@diku.dk 20/12/2001 08:06.
-**
-** I want to have more features :). Every touch pad (ps2 and serial) is now be
-** supported according to STIG and every feature/capability is read.  However
-** there seems to be some very old serial touchpads that have an advanced
-** mode not mentioned in STIG.
-**
-**
-** Further I have added the following
-**
-**  Emulation of scrolling
-**        The window drivers allow using the edge to emulate a wheel
-**        mouse. When putting the finger at the right edge, a movement up or
-**        down translates to wheel movement. Taking the finger to the
-**        top/button edge keeps the wheel turning.  Lift the finger again to
-**        operate normally again. Another option is to do a toss scrolling.
-**
-**  Stick attached to a synaptic touchpad (aka styk)
-**        Some touchpads have a stick "attached", so they share the same port.
-**        In absolute mode the stick protocol is a simple ps2 protocol, except
-**        it is sent in an absolute packet. (In relative mode both uses ps2)
-**        Some sticks send packets when pressed (different from moved), which
-**        will be reported as left button.
-**
-**  4 Way button attached to a touchpad
-**        Likewise some touchpads have a round button giving the choices of
-**        four way to press the button. The packet is nearly identical to the
-**        stick, turn off the stick if you have this button. This is no longer
-**        needed.  The button can act as a mouse or as buttons which can be
-**        changed on the fly. The buttons can be configured just as the
-**        touchpads corners.
-**
-**  Four buttons to work
-**        Some touchpads have 4 buttons. Only 3 was read and the last was set to 
-**        up or down "button". They can be configured just as the
-**        touchpads corners.
-**
-**  Multiple fingers
-**        I have added an option to detect such by looking at pressure levels,
-**        which is not that great. If the pad have the capability to detect it,
-**        this is used instead, but this far from optimal. It does detect two
-**        horizontal parted finger if in same vertical position, otherwise the
-**        detection is bad. This is/was a problem as my wrist lays on the
-**        laptop which gives a 45 deg to horizontal for my fingers. Now I try
-**        to add further detections, which works for me in 95% of the
-**        time. 
-**
-**  Multi finger tap
-**        Using 1,2 or 3 fingers to make a tap translates into left, right or
-**        middle button pressed. I originally thought about doing what is
-**        called a "HOP" where after a quick finger shift the distance of the
-**        hop decides which button is pressed. I dropped it partly because
-**        synaptics did in version 3.2 and because it was harder than I
-**        thought. Multifinger taps can be configured just as the touchpads corners.
-**
-**  Multi finger less sensitive
-**        Adding or removing a finger or just accidently touch the pad with
-**        the palm while using the pad causes the pad to report the average
-**        position between the touched places.  This of cause gives annoying
-**        erratic movements. When adding or removing fingers are detected
-**        the mouse is stop for some small time to avoid this. This is not
-**        perfect as the finger detection is not perfect, but it helps a lot!
-**
-**  Palm detection
-**        Some touchpads tries to detect whether the reported data is from a
-**        palm or similar.  When reading this signal the movement is
-**        stopped. Except the detection does not work very well :(
-**
-**
-**  Enabling/disabling touchpad
-**        A new corner action is to disable the touchpad. It is enabled again
-**        by tapping the same corner. This is useful if I know I am going
-**        to write a lot. The stick still works.
-**
-**  Debugging corner action  
-**        A corner action now allows toggling the debug information. 
-**
-**
-** The structure has changed to handle both serial and ps2 touchpads. Many
-** variable names have changed.                  
-**
-** The documentation referred to is from
-**  "Synaptics TouchPad Interfacing Guide" revision 2.5 
-** or just STIG
-**                                                                                 
-**/
-
-
-/*
-** TODO
-**   - handle other versions of synaptics touchpads (mine is 3.4 firmware)
-**     (this should be close)
-**   - test this with more Synaptics touch pads (laptops and such)
-**   - provide a configuration interface to adjust parameters and
-**     enabled features
-**   - determine appropriate ranges for adjusting parameters
-**
-** TODO (pebl)
-**   - Two pads can not be used at the same time (internal/external)
-**   - Move a lot of the comments to a readme file.
-**   - Allow normal taps in unused corners. 
-**   - Better detection of spontaneous reseting touchpad.
-**   - Implement resend command for serial connection.
-**   - Only start scrolling if mostly vertical movement.
-**   - Disable/enable command for serial touchpad.
-**   - Clean up the mess about extended packets with pressure 0.
-**   - source splitting of normal touchpad functions and synaptic specific and
-**     add other touchpads.
-*/
-
-
-
-/**
-** Notation:
-** A gesture means a motion or action that is not a regular mouse movement.
-** 
-** Wmode is an absolute mode where no gesture is signaled by the touchpad, only
-** supported on newer versions.
-**
-** variables *_enabled are use for enable behaviors that may not supported in
-** the touchpad.
-**
-** Many variables have two counterparts (and some that dont should have): a
-** *_time and *_packet, where the first is in msec and the latter is the same
-** time converted to the number of packets, when using 80 packets per second.
-**
-** Variables:
-** last_* is for last reviewed packet, not last reported/calculated movement/event.
-** was_*  is for last event, not necessary last packet.
-**
-**
-** Data process line:
-**
-** syn_process_ps2_data   ---- syn_translate_serial_data    --                         -----------------------------------------------
-**                                (handles also wmode)       |                         |                            |
-**                                                           |                         |                            V
-**                                                           |- syn_preprocess_report --- syn_process_wmode_report --- syn_process_report
-**                                                           |                          
-** syn_process_serial_data --- syn_translate_ps2_wmode_data --                                                       
-**                          |                                |                          
-**                          |                                |                          
-**                          -- syn_translate_ps2_data     ----                          
-**
-**
-*/
-
-
-#include <math.h>                /* ceil */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-
-#include "headers/gpm.h"
-#include "headers/gpmInt.h"       /* which_mouse */
-#include "headers/synaptics.h"
-#include "headers/message.h"
-
-#define DEBUG                     1
-#undef DEBUG
-
-#ifdef DEBUG
-#  define DEBUG_SYNAPTIC          
-#  define DEBUG_PARAMS            1
-#  define DEBUG_FLUSH             1
-#  define DEBUG_RESET             1
-#  define DEBUG_SENT_DATA         1
-#  define DEBUG_RECEIVED_DATA     1
-#  define DEBUG_TOSS              1
-#  define DEBUG_PALM              1
-#  define DEBUG_STICK             1
-#  define DEBUG_TAPS              1
-#  define DEBUG_MULTI_FINGER      1
-#  define DEBUG_CMD               1
-#  define DEBUG_GETBYTE           1    /* this is VERY verbose */
-#  undef  DEBUG_PUTBYTE           1    /* this is VERY verbose */
-#  define DEBUG_PUTBYTE_ACK       1    /* this is VERY verbose */
-#  define DEBUG_REPORTS           1    /* this is VERY verbose */
-#endif
-
-
-/* The next is UGLY, but I only want debug info from this file */
-/* it's really ugly and you shouldn't use this. Instead use
- * gpm -D | grep filename.c.
- * ifdef DEBUG should not be used anymore! */
-/* pebl: But this require that I boot my machine with gpm -D which I dont. The
-   intention is that when I am doing my normal doing, and the touchpad suddenly
-   behaves strange, I can start debuging without restarting gpm, using a
-   corneraction.
-*/
-
-/* BAD CODE BEGIN 
-#ifdef DEBUG_SYNAPTIC
-#  include <stdarg.h>
-   static int debug_syn_to_stderr = 1;
-
-   static void gpm_report_static(int line, char *file, int stat, char* fmt, ... ) {
-
-     va_list ap;
-     va_start(ap, fmt);
-     if (debug_syn_to_stderr){
-       vfprintf(stderr, fmt, ap);
-       fputs("\n", stderr);
-     }else{
-       gpm_report(line,file,stat,fmt,&ap);
-     }
-     va_end(ap);
-
-   }
-#  define gpm_report gpm_report_static
-#endif
-
-* END BADE CODE */
-
-/* Prototype */
-typedef unsigned char byte;
-
-static void syn_ps2_absolute_mode(int fd);
-static char *syn_model_name (int sensor);
-static void syn_ps2_send_cmd(int fd, int stick, byte cmd); 
-
-
-/* Defines */
-
-#define abs(value)              ((value) < 0 ? -(value) : (value))
-#define check_bits(value,mask)  (((value) & (mask)) == (mask))
-#define sqr(value)              ((value) * (value))
-#define distance(dx,dy)         (sqr(dx) + sqr(dy))
-#define mod4(value)             ((value) % 4)
-#define max(x,y)                ((x)>(y)?(x):(y))
-
-/*
-** Define the edge bit values.
-*/
-#define LEFT_EDGE           0x01
-#define RIGHT_EDGE          0x02
-#define TOP_EDGE            0x04
-#define BOTTOM_EDGE         0x08
-#define UPPER_LEFT_CORNER   (LEFT_EDGE  | TOP_EDGE)
-#define LOWER_LEFT_CORNER   (LEFT_EDGE  | BOTTOM_EDGE)
-#define UPPER_RIGHT_CORNER  (RIGHT_EDGE | TOP_EDGE)
-#define LOWER_RIGHT_CORNER  (RIGHT_EDGE | BOTTOM_EDGE)
-#define is_corner(edges)    (((edges) & (LEFT_EDGE | RIGHT_EDGE)) && \
-			     ((edges) & (TOP_EDGE  | BOTTOM_EDGE)))
-
-/*
-** Define the action button bit values.
-*/
-#define RIGHT_BUTTON        0x01
-#define MIDDLE_BUTTON       0x02
-#define LEFT_BUTTON         0x04
-#define FOURTH_BUTTON       0x08
-#define UP_BUTTON           0x10
-#define DOWN_BUTTON         0x20
-#define ONE_FINGER          0x01
-#define TWO_FINGERS         0x02
-#define THREE_FINGERS       0x04
-#define FOUR_UP_BUTTON      0x01
-#define FOUR_DOWN_BUTTON    0x02
-#define FOUR_LEFT_BUTTON    0x04
-#define FOUR_RIGHT_BUTTON   0x08
-#define STICK_RIGHT_BUTTON  0x01
-#define STICK_MIDDLE_BUTTON 0x02
-#define STICK_LEFT_BUTTON   0x04
-/*
-** Define additional gpm button bit values.
-*/
-#define GPM_B_NOT_SET       (-1)
-
-/*
-** Define the guest and touchpad devices.
-*/
-#define DEVICE_TOUCHPAD     0
-#define DEVICE_STICK        1
-
-
-/****************************************************************************
-**
-** Configuration constants.
-**
-** Those with C at the end are suitable for adjustment by a configuration
-** program.
-****************************************************************************/
-
-static int corner_taps_enabled         = 1;  /* are corner taps enabled C*/
-static int tap_gesture_enabled         = 1;  /* are gestures treaded as taps enabled  C*/
-static int tossing_enabled             = 1;  /* is toss/catch enabled   C*/
-static int does_toss_use_static_speed  = 1;  /* is toss/catch speed     C*/
-                                                /* based on toss dist       */
-static int edge_motion_enabled         = 1;  /* is edge motion enabled  C*/
-static int edge_motion_speed_enabled   = 1;  /* does pressure control   C*/
-                                               /* speed of edge motion     */
-static int pressure_speed_enabled      = 1;  /* does pressure control   C*/
-                                                 /* speed in non edges       */
-static int tap_hold_edge_motion_enabled = 1; /* Enable edge motion while holding a tap  C*/
-
-/* pressure induced speed related configuration constants */
-static int   low_speed_pressure      = 60;                                /*C*/
-static int   speed_up_pressure       = 60;                                /*C*/
-static float speed_pressure_factor   = 0.05;                              /*C*/
-static float standard_speed_factor   = 0.08;                              /*C*/
-
-/* toss/catch related constants */
-static int   min_toss_time           = 100;   /* ms: 0.10 sec */
-static int   max_toss_time           = 300;   /* ms: 0.30 sec */          /*C*/
-static int   prevent_toss_time       = 300;   /* ms: 0.25 sec */          /*C*/
-static int   min_toss_dist           = 2;     /* mm */                    /*C*/
-static int   static_toss_speed       = 70;                                /*C*/
-static float toss_speed_factor       = 0.5;                               /*C*/
-
-/* edge motion related configuration constants */
-static int   x_min_center            = 1632;  /* define left edge           C*/
-static int   x_max_center            = 5312;  /* define right edge          C*/
-static int   y_min_center            = 1408;  /* define bottom edge         C*/
-static int   y_max_center            = 4108;  /* define top edge            C*/
-static int   edge_speed              = 20;    /* default speed at edges     C*/
-
-/* gesture related configuration constants for when wmode is enabled. */
-static int   wmode_enabled	     = 1;     /* is wmode enabled        C */
-static int   drag_lock_enabled	     = 1;     /* is drag locking enabled C */
-static int   finger_threshold	     = 30;    /* pressure before it is a finger C */
-static int   tap_lower_limit	     = 5;     /* a tap last at least this long C */
-static int   tap_upper_limit	     = 200;   /* a tap is at most this long C */
-static int   tap_range		     = 100;   /* mm finger movement limit  C */
-static int   tap_interval	     = 200;   /* a tap reports button press this long C*/
-static int   multiple_tap_delay      = 30;    /* time between reported button pressed C*/
-static int   pads_tap_interval       = 8;     /* if pad sends gestures, what is it's tap_interval. C*/
-
-/* wmode capabilities */
-static int   palm_detect_enabled     = 1;     /* Ignore when palm on pad   C */
-static int   palm_detect_level       = 12;    /* Detecting a palm level (between 0-11) C */
-static int   multi_finger_tap_enabled= 1;     /* No of fingers decides which button is pressed C*/
-static int   multi_finger_stop_enabled = 1;   /* less sensitive mouse with multi finger C*/
-static int   multi_finger_stop_delay = 8;     /* how long to stop after a multifinger detection. C*/
-static int   fake_finger_layer_enabled = 1;   /* add an extra software layer to detect multi fingers C*/
-
-
-/* mixed configurations */
-static int   touchpad_enabled        = 1; /* Disable the touch pad, see corner action turn_on_off. C*/
-static int   stick_enabled           = 1; /* Some machines have a touchpad and a stick on
-                                           * same device port. The stick will be ignored in
-                                           * absolute mode, this option try to recognize
-                                           * it's packets.                                         C*/
-static int   stick_pressure_enabled  = 1; /* A (hard) press on the stick is reported as left click C*/
-static int   four_way_button_enabled = 1; /* Round button giving 4 choices on some touchpads        C*/
-static int   four_way_button_is_mouse= 1; /* Is the button: 4 buttons or does it moves the mouse.  C*/
-static int   scrolling_enabled       = 1; /* Simulate wheel mouse in at the right edge             C*/
-static int   scrolling_edge          = RIGHT_EDGE; /* Which edge is a the scrolling edge           C*/
-static int   scrolling_speed         = 10;/* less is faster, 1 fastest  */
-static float scrolling_button_factor = 0.5; /* How fast should a button/corner tap scroll, higher faster C*/
-static int   auto_scrolling_enabled  = 1; /* Moving to the upper/lower edge keeps scrolling up/downC*/
-static int   auto_scrolling_factor   = 2.0; /* How fast should autoscrolling be                   C*/
-static int   reset_on_error_enabled  = 0; /* If a packet does not conform to any absolute protocol 
-					   * should we reset the touchpad? This is wrong, because we
-					   * should rather find out why it does that in first place.
-					   * Do not turn it on per default.                         */
-
-
-/*
-** Types for describing actions.  When adding a new action, place it as
-** the last item. It will break old configurefiles otherwise.
-*/
-typedef enum {
-  No_Action          = 0,
-  Left_Button_Action,
-  Middle_Button_Action,
-  Right_Button_Action,
-  Fourth_Button_Action,
-  Up_Button_Action,
-  Down_Button_Action,
-  Turn_On_Off_Action,
-  Debug_On_Off_Action,
-  Reset_Touchpad_Action,
-  Toggle_Four_Way_Button_Action,
-  Toggle_Stick_Pressure_Action,
-  Toggle_Scrolling_Action,
-  Left_Double_Click_Action,
-} action_type;
-
-
-typedef struct {
-  int         action_mask;
-  action_type action;
-} touchpad_action_type;
-
-static touchpad_action_type corner_actions [] = {
-  { UPPER_LEFT_CORNER,  No_Action },
-  { LOWER_LEFT_CORNER,  No_Action },
-  { UPPER_RIGHT_CORNER, Middle_Button_Action },
-  { LOWER_RIGHT_CORNER, Right_Button_Action  },
-  { 0,                  No_Action } /* stop flag value */
-};
-
-static touchpad_action_type normal_button_actions [] = {
-  { LEFT_BUTTON,        Left_Button_Action },
-  { MIDDLE_BUTTON,      Middle_Button_Action },
-  { RIGHT_BUTTON,       Right_Button_Action },
-  { FOURTH_BUTTON,      Fourth_Button_Action },
-  { UP_BUTTON,          Up_Button_Action },
-  { DOWN_BUTTON,        Down_Button_Action },
-  { 0,                  No_Action } /* stop flag value */
-};
-
-static touchpad_action_type multi_finger_actions [] = {
-  { ONE_FINGER,         Left_Button_Action },
-  { TWO_FINGERS,        Right_Button_Action },
-  { THREE_FINGERS,      Middle_Button_Action },
-  { 0,                  No_Action } /* stop flag value */
-};
-
-static touchpad_action_type four_button_actions [] = {
-  { FOUR_LEFT_BUTTON,   Middle_Button_Action },
-  { FOUR_RIGHT_BUTTON,  Fourth_Button_Action },
-  { FOUR_UP_BUTTON,     Up_Button_Action },
-  { FOUR_DOWN_BUTTON,   Down_Button_Action },
-  { 0,                  No_Action } /* stop flag value */
-};
-
-static touchpad_action_type stick_actions [] = {
-  { LEFT_BUTTON,        Left_Button_Action },
-  { MIDDLE_BUTTON,      Middle_Button_Action },
-  { RIGHT_BUTTON,       Right_Button_Action },
-  { 0,                  No_Action } /* stop flag value */
-};
-
-
-/*
-** These types are used to read the configuration data from the config file.
-*/
-typedef enum {
-  Integer_Param,
-  Float_Param,
-  Flag_Param,
-  Action_Param
-} param_type_type;
-
-typedef struct {
-  char            *name;
-  param_type_type  p_type;
-  union {
-    void  *gen_p;   /* avoids complaints by the compiler later on */
-    int   *int_p;
-    float *float_p;
-    int   *flag_p;
-    touchpad_action_type *corner_p;
-  } addr;
-} param_data_type;
-
-static param_data_type param_data [] = {
-  /* enabling configuration parameters */
-  { "edge_motion_enabled",        Flag_Param,    {&edge_motion_enabled        }},
-  { "edge_motion_speed_enabled",  Flag_Param,    {&edge_motion_speed_enabled  }},
-  { "corner_taps_enabled",        Flag_Param,    {&corner_taps_enabled        }},
-  { "tap_gesture_enabled",        Flag_Param,    {&tap_gesture_enabled        }},
-  { "pressure_speed_enabled",     Flag_Param,    {&pressure_speed_enabled     }},
-  { "tossing_enabled",            Flag_Param,    {&tossing_enabled            }},
-  { "does_toss_use_static_speed", Flag_Param,    {&does_toss_use_static_speed }},
-  { "tap_hold_edge_motion_enabled",Flag_Param,   {&tap_hold_edge_motion_enabled}},
-  
-  /* pressure induced speed related configuration parameters */		     
-  { "low_pressure",               Integer_Param, {&low_speed_pressure         }},
-  { "speed_up_pressure",          Integer_Param, {&speed_up_pressure          }},
-  { "pressure_factor",            Float_Param,   {&speed_pressure_factor      }},
-  { "standard_speed_factor",      Float_Param,   {&standard_speed_factor      }},
-  /* toss/catch related parameters */		 			     
-  { "min_toss_time",              Integer_Param, {&min_toss_time              }},
-  { "max_toss_time",              Integer_Param, {&max_toss_time              }},
-  { "prevent_toss_time",          Integer_Param, {&prevent_toss_time          }},
-  { "min_toss_dist",              Integer_Param, {&min_toss_dist              }},
-  { "static_toss_speed",          Integer_Param, {&static_toss_speed          }},
-  { "toss_speed_factor",          Float_Param,   {&toss_speed_factor          }},
-  /* edge motion related configuration parameters */			     
-  { "x_min_center",               Integer_Param, {&x_min_center               }},
-  { "x_max_center",               Integer_Param, {&x_max_center               }},
-  { "y_min_center",               Integer_Param, {&y_min_center               }},
-  { "y_max_center",               Integer_Param, {&y_max_center               }},
-  { "edge_speed",                 Integer_Param, {&edge_speed                 }},
-  /* use wmode */				 			     
-  { "wmode_enabled",		  Flag_Param,	 {&wmode_enabled	      }},
-  { "drag_lock_enabled",	  Flag_Param,	 {&drag_lock_enabled	      }},
-  { "finger_threshold",		  Integer_Param, {&finger_threshold	      }},
-  { "tap_lower_limit",		  Integer_Param, {&tap_lower_limit	      }},
-  { "tap_upper_limit",		  Integer_Param, {&tap_upper_limit	      }},
-  { "tap_range",		  Integer_Param, {&tap_range		      }},
-  { "tap_interval",		  Integer_Param, {&tap_interval		      }},
-  { "multiple_tap_delay",	  Integer_Param, {&multiple_tap_delay	      }},
-  { "pads_tap_interval",	  Integer_Param, {&pads_tap_interval	      }},
-  /* Additional wmode parameters */ 
-  { "palm_detect_enabled",	  Flag_Param,	 {&palm_detect_enabled	      }},
-  { "palm_detect_level",	  Integer_Param, {&palm_detect_level	      }},
-  { "multi_finger_tap_enable",    Flag_Param,    {&multi_finger_tap_enabled   }},
-  { "multi_finger_stop_enabled",  Flag_Param,    {&multi_finger_stop_enabled  }},
-  { "multi_finger_stop_delay",    Integer_Param, {&multi_finger_stop_delay    }},
-  { "fake_finger_layer_enabled",  Integer_Param, {&fake_finger_layer_enabled  }},
-  /* Additional options*/
-  { "touchpad_enabled", 	  Flag_Param,    {&touchpad_enabled	      }},
-  { "stick_enabled",	          Flag_Param,    {&stick_enabled	      }},
-  { "stick_pressure_enabled",     Flag_Param,    {&stick_pressure_enabled     }},
-  { "four_way_button_enabled",    Flag_Param,    {&four_way_button_enabled    }},
-  { "four_way_button_is_mouse",   Flag_Param,    {&four_way_button_is_mouse   }},
-  { "scrolling_enabled",	  Flag_Param,    {&scrolling_enabled	      }},
-  { "auto_scrolling_enabled",	  Flag_Param,    {&auto_scrolling_enabled     }},
-  { "scrolling_edge",	          Integer_Param, {&scrolling_edge	      }},
-  { "scrolling_speed",	          Integer_Param, {&scrolling_speed	      }},
-  { "scrolling_button_factor",    Float_Param,   {&scrolling_button_factor    }},
-  { "auto_scrolling_factor",      Float_Param,   {&auto_scrolling_factor      }},
-  /* corner tap actions */			 			     
-  { "upper_left_action",          Action_Param,  {&corner_actions [0]         }},
-  { "lower_left_action",          Action_Param,  {&corner_actions [1]         }},
-  { "upper_right_action",         Action_Param,  {&corner_actions [2]         }},
-  { "lower_right_action",         Action_Param,  {&corner_actions [3]         }},
-  /* no. of fingers tap actions */
-  { "one_finger_tap_action",      Action_Param,  {&multi_finger_actions [0]   }},
-  { "two_fingers_tap_action",     Action_Param,  {&multi_finger_actions [1]   }},
-  { "three_fingers_tap_action",   Action_Param,  {&multi_finger_actions [2]   }},
-  /* normal button actions */
-  { "left_button_action",         Action_Param,  {&normal_button_actions [0]  }},
-  { "middle_button_action",       Action_Param,  {&normal_button_actions [1]  }},
-  { "right_button_action",        Action_Param,  {&normal_button_actions [2]  }},
-  { "fourth_button_action",       Action_Param,  {&normal_button_actions [3]  }},
-  { "up_button_action",           Action_Param,  {&normal_button_actions [4]  }},
-  { "down_button_action",         Action_Param,  {&normal_button_actions [5]  }},
-  /* 4 way button actions */
-  { "four_way_left_button_action", Action_Param,  {&four_button_actions [0]   }},
-  { "four_way_right_button_action",Action_Param,  {&four_button_actions [1]   }},
-  { "four_way_up_button_action",   Action_Param,  {&four_button_actions [2]   }},
-  { "four_way_down_button_action", Action_Param,  {&four_button_actions [3]   }},
-  /* Synaptic Stick (passthrugh,stick) actions */
-  { "stick_left_button_action",    Action_Param,  {&stick_actions [0]         }},
-  { "stick_middle_button_action",  Action_Param,  {&stick_actions [1]         }},
-  { "stick_right_button_action",   Action_Param,  {&stick_actions [2]         }},
-  /* end of list */				 			     
-  { NULL,                         Flag_Param,    {NULL                        }}
-};
-
-
-/*
-** The information returned in the identification packet.
-** STIG page 10
-*/
-typedef struct {
-  int info_model_code;
-  int info_major;
-  int info_minor;
-} info_type;
-
-static info_type ident[2];
-
-/*
-** The information returned in the model ID packet.
-** STIG page 11
-*/
-
-#define INFO_ROT180_BITS      0x800000   /* bit 23    */
-#define INFO_PORTRAIT_BITS    0x400000	 /* bit 22    */
-#define INFO_SENSOR_BITS      0x3F0000	 /* bit 16-21 */
-#define INFO_HARDWARE_BITS    0x00FE00	 /* bit 9-15  */
-#define INFO_NEW_ABS_BITS     0x000080	 /* bit 7     */
-#define INFO_CAP_PEN_BITS     0x000040	 /* bit 6     */
-#define INFO_SIMPLE_CMD_BITS  0x000020	 /* bit 5     */
-#define INFO_GEOMETRY_BITS    0x00000F	 /* bit 0-3   */
-
-
-typedef struct {
-  int info_rot180; 
-  int info_portrait; 
-  int info_sensor; 
-  int info_hardware; 
-  int info_new_abs; 
-  int info_cap_pen; 
-  int info_simple_cmd; 
-  int info_geometry; 
-} model_id_type; 
-
-static model_id_type model[2];
-
-/*
-** The sensor types as of STIG 2.5
-** Page 11. Plus some guessing.
-*/
-static char *model_names [] = {
-  "Unknown",                                /*  0 */
-  "Standard TouchPad (TM41xx134)",
-  "Mini Module (TM41xx156)",
-  "Super Module (TM41xx180)",
-  "Romulan Module",
-  "Apple Module",
-  "Single Chip",
-  "Flexible pad (discontinued)",
-  "Ultra-thin Module (TM41xx220)",
-  "Wide pad Module (TW41xx230)",
-  "TwinPad",                                /* 10 */
-  "StampPad Module (TM41xx240)",
-  "Sub-mini Module (TM41xx140)",
-  "MultiSwitch module (TBD)",
-  "Standard Thin",
-  "Advanced Technology Pad (TM41xx221)",
-  "Ultra-thin Module, connector reversed",
-  "Low Power Module",
-  "Thin Module, ATP",
-  "Snap dome Module, ATP", 
-  "FlexArm Module",                         /* 20 */
-  "TWIII Module (TouchWriter 3)",
-  "TWIII Module (P64)",
-  "Combo Module",
-  "Squish Module",
-  "Thin TTL Serial module",
-  "TWIII Ultra Thin Module",
-  "PS/2 Passthrough", 
-  "4 Button On Board Module",
-  "6 Buttons Off Board Module",             
-  "6 Buttons On Board Module",              /* 30 */
-  "Ultrathin TTL serial Module",
-  "ClearPad Module",
-  "HyperThin Sensor Module",
-  "Pad With Scroll Strip",
-  "UltraThin TTL rounded, serial Module",
-  "Ultrathin ATP Module",
-  "SubMini w/6 buttons",
-  "Standard USB Module",
-  "cPad Dropin Plain USB Module",
-  "cPad",                                   /* 40 */ 
-  "",
-  "",
-  "",
-  "UltraNav",
-};
-
-
-/*
-** Define the information known about a sensor.
-** STIG page 14.
-** Resolution only apply for absolute mode.
-** For older models the default resolution is 85x94.
-*/
-typedef struct {
-  char *model;
-  int   x_per_mm;
-  int   y_per_mm;
-  float width_mm;
-  float height_mm;
-} sensor_info_type;
-
-
-static sensor_info_type sensor_info [] = {
-  { "",            0,   0,  0.0,  0.0 },
-  { "Standard",   85,  94, 47.1, 32.3 },
-  { "Mini",       91, 124, 44.0, 24.5 },
-  { "Super",      57,  58, 70.2, 52.4 },
-  { "",            0,   0,  0.0,  0.0 },
-  { "",            0,   0,  0.0,  0.0 },
-  { "",            0,   0,  0.0,  0.0 },
-  { "",            0,   0,  0.0,  0.0 },
-  { "UltraThin",  85,  94, 47.1, 32.3 },
-  { "Wide",       73,  96, 54.8, 31.7 },
-  { "",            0,   0,  0.0,  0.0 },
-  { "Stamp",     187, 170, 21.4, 17.9 },
-  { "SubMini",   122, 167, 32.8, 18.2 },
-};
-
-static sensor_info_type *sensor[2] = {
-  &sensor_info[0],&sensor_info[0]
-};
-
-/*
-** The information returned in the extended capability packet.
-** STIG page 15
-*/
-
-#define EXT_CAP_EXTENDED     0x8000     /* Bit 15  */
-#define EXT_CAP_STICK        0x0080     /* Bit 8   */
-#define EXT_CAP_PASS_THROUGH 0X0080     /* Bit 8!! */
-#define EXT_CAP_SLEEP        0x0010     /* Bit 4   */
-#define EXT_CAP_FOUR_BUTTON  0x0008     /* Bit 3   */
-#define EXT_CAP_MULTI_FINGER 0X0002     /* Bit 1   */
-#define EXT_CAP_PALM_DETECT  0X0001     /* Bit 0   */
-
-typedef struct {
-  int cap_ext; 
-  int cap_stick;
-  int cap_sleep; 
-  int cap_four_button; 
-  int cap_multi_finger; 
-  int cap_palm_detect; 
-} ext_cap_type;
-
-static ext_cap_type capabilities[2];
-
-/*
-** The information in the mode byte.
-** STIG Page 17
-*/
-#define ABSOLUTE_MODE      0x80      /* Bit 7 set */
-#define RELATIVE_MODE      0x00	     /* Bit       */
-#define HIGH_REPORT_RATE   0x40	     /* Bit 6 set = 80 packages per second */
-#define LOW_REPORT_RATE    0x00	     /* Bit         40 packages per second */
-#define USE_9600_BAUD      0x08	     /* Bit 3 for serial protocol */
-#define USE_1200_BAUD      0x00	     /* Bit   */
-#define PS2_SLEEP          0x08	     /* Bit 3 for ps2 protocol */
-#define PS2_NO_SLEEP       0x00	     /* Bit   (only  button press activates touchpad again)*/
-#define NO_TAPDRAG_GESTURE 0x04      /* Bit 2 for model version >= 4 */
-#define TAPDRAG_GESTURE    0x00      /* Bit   */     
-#define EXTENDED_REPORT    0x02	     /* Bit 1 for serial protocol absolute mode only */
-#define NORMAL_REPORT      0x00	     /* Bit   */
-#define STICK_DISABLE      0x02	     /* Bit 1 for ps2 protocol this disables any stick attached */
-#define STICK_ENABLED      0x00	     /* Bit   */
-#define REPORT_W_ON        0x01	     /* Bit 0 set */
-#define REPORT_W_OFF       0x00      /* Bit   */
-
-
-
-/*
-** The format of the translated data to a report.
-*/
-typedef struct {
-  int left;
-  int middle;
-  int right;
-  int fourth;
-  int up;
-  int down;
-  int x;
-  int y;
-  int pressure;
-  int gesture;
-  int fingers;
-  int fingerwidth;
-  int w;
-} report_type;
-
-static report_type last_report,cur_report;
-
-/*
-** A location record.
-** This is needed to make an average over several packages, 
-** because the reported x,y might not be that accurate.
-*/
-typedef struct {
-  int x;
-  int y;
-} location_type;
-
-
-
-/*
-** Parameters for controlling the touchpad.
-*/
-/* touchpad information */
-static int res_x;
-static int res_y;
-static int x_per_mm;
-static int y_per_mm;
-
-
-/* status information */
-static int           packet_num = 0;
-static int           was_edges = 0;
-static int           was_non_edge = 0;
-static location_type last_locs [4];
-static Gpm_Event     last_state;
-static int           tap_lower_limit_packet;    
-static int           tap_upper_limit_packet;
-static int           last_corner_action = GPM_B_NOT_SET;
-static int           last_finger_action = GPM_B_NOT_SET;
-static int           last_normal_button_actions[6] = 
-  {GPM_B_NOT_SET,GPM_B_NOT_SET,GPM_B_NOT_SET,GPM_B_NOT_SET,GPM_B_NOT_SET,GPM_B_NOT_SET};
-static int           last_stick_button_actions[3]  = 
-  {GPM_B_NOT_SET,GPM_B_NOT_SET,GPM_B_NOT_SET};
-static int           last_4_way_button_actions[4] =
-  {GPM_B_NOT_SET,GPM_B_NOT_SET,GPM_B_NOT_SET,GPM_B_NOT_SET};
-
-/* toss status information */
-static int           is_tossing = 0;
-static int           was_tossing = 0;
-static int           min_toss_dist__2 = 32000;
-static int           max_toss_packets;
-static int           min_toss_packets;
-static int           prevent_toss_packets;
-static int           toss_timer;
-static location_type toss_speed;
-static location_type touch_loc;
-
-/* Multi tap information */
-static int           gesture_delay = 0;
-static int           fake_forget_tap_interval = 0;  /* if hardware sends tap-hold, we need to keep track */
-static int           fake_time_to_forget_tap = 0;   /* not to lose user defined actions in the hold periode. 
-						     * (action like: Multifingers, non-repeating actions etc.*/
-
-/* Multi finger information */
-static int           was_fingers = 0;
-static int           multi_finger_stop_timer = 0;
-static int           multi_finger_pressure  = 0;
-static int           multi_finger_xy = 0;
-
-
-/* Scrolling information */
-static int           is_scrolling = 0;            /* Scrolling using touchpad edge*/
-static int           is_always_scrolling = 0;     /* Only report scrolling, no mouse movement */
-static int           scrolling_speed_timer = 0;
-static int           scrolling_amount_left = 0;   /* Tells how much to scroll up or down */
-
-static int           mouse_fd;      
-
-
-
-/****************************************************************************
-**
-** ROUTINES for processing either type of touchpad.
-**
-****************************************************************************/
-
-/*
-** Dump the report data for debugging.
-**
-** Because the synaptics sends (trivial) data in one second after last touch,
-** which makes reading the debug data harder, only dump the report if it is different 
-** than the previously dumped.
-*/
-#if DEBUG_REPORTS
-static void tp_dump_report_data (report_type report,
-				 int edges,
-				 Gpm_Event* state) 
-{
-  static report_type  last_report_reported;
-  static unsigned int times_report_repeated = 0;
-
-
-  report.left   |= state->buttons & GPM_B_LEFT;
-  report.right  |= state->buttons & GPM_B_RIGHT;
-  report.middle |= state->buttons & GPM_B_MIDDLE;
-
-  if (memcmp(&report,&last_report_reported,sizeof(report_type)) == 0){
-    times_report_repeated++;
-    return;
-  }
-
-  /* Was the last report repeated ? */
-  if(times_report_repeated > 0){
-    gpm_report (GPM_PR_DEBUG,"\rSynps2: Last report reported %d times\n",times_report_repeated); 
-    times_report_repeated = 0;
-  }
-
-  last_report_reported = report;
-
-  gpm_report (GPM_PR_DEBUG,
-	      "\rSynps2: %c%c%c%c%c  %4dx%-4d %3d %2d %d  %c%c%c%c  %c%c    %3d%3d %d    %8d %8d %c",
-	      report.fingers ? 'f' : '-',  
-	      report.gesture ? 'g' : '-',
-	      
-	      report.left    ? 'l' : '-',
-	      report.middle  ? 'm' : '-',  
-	      report.right   ? 'r' : '-',
-	      
-	      report.x, report.y, report.pressure,
-	      report.w,was_fingers, 
-	      
-	      edges & LEFT_EDGE   ? 'l' : '-',
-	      edges & RIGHT_EDGE  ? 'r' : '-',
-	      edges & BOTTOM_EDGE ? 'b' : '-',
-	      edges & TOP_EDGE    ? 't' : '-',
-	      
-	      report.gesture && !report.fingers ? 't' : '-',
-	      report.gesture && report.fingers  ? 'd' : '-',
-	      
-	      state->dx,state->dy,state->buttons,
-
-
-	      multi_finger_pressure,multi_finger_xy,
-	      (multi_finger_pressure>4500 && multi_finger_xy>50000? 'f':' '));
-
-}
-#endif
-
-/* syn_dump_info
-**
-** Print properties for the hardare.
-**
- */
-static void syn_dump_info(int stick)
-{
-
-  gpm_report (GPM_PR_INFO,"Synaptic %s Device:",(stick?"Stick":"Touchpad"));
-    
-  gpm_report (GPM_PR_INFO,"Synaptics Ident:  model_code=%d   Firmware version %d.%d",
-	      ident[stick].info_model_code, ident[stick].info_major, ident[stick].info_minor);
-  gpm_report (GPM_PR_INFO,"Synaptics model:");
-  gpm_report (GPM_PR_INFO,"   rot180:      %s", model[stick].info_rot180 ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   portrait:    %s", model[stick].info_portrait ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   sensor:      %d", model[stick].info_sensor);
-  gpm_report (GPM_PR_INFO,"                %s", syn_model_name (model[stick].info_sensor));
-  gpm_report (GPM_PR_INFO,"                %s", sensor[stick]->model);
-  gpm_report (GPM_PR_INFO,"                %dx%d res/mm",
-	      sensor[stick]->x_per_mm, sensor[stick]->y_per_mm);
-  gpm_report (GPM_PR_INFO,"                %4.1fx%4.1f mm",
-	      sensor[stick]->width_mm, sensor[stick]->height_mm);
-  gpm_report (GPM_PR_INFO,"                %dx%d res", res_x, res_y);
-  gpm_report (GPM_PR_INFO,"   hardware:    %d", model[stick].info_hardware);
-  gpm_report (GPM_PR_INFO,"   newABS:      %s", model[stick].info_new_abs ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   simpleCmd:   %s", model[stick].info_simple_cmd ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   geometry:    %d", model[stick].info_geometry);
-  gpm_report (GPM_PR_INFO,"   extended:    %s", capabilities[stick].cap_ext ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   stick:       %s", capabilities[stick].cap_stick ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   sleep:       %s", capabilities[stick].cap_sleep ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   4 buttons:   %s", capabilities[stick].cap_four_button ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   multifinger: %s", capabilities[stick].cap_multi_finger ? "Yes" : "No");
-  gpm_report (GPM_PR_INFO,"   palmdetect:  %s", capabilities[stick].cap_palm_detect ? "Yes" : "No");
-
-#if DEBUG_TOSS
-  gpm_report (GPM_PR_INFO,"Min Toss Dist^2: %d\n", min_toss_dist__2);
-#endif
-}
-
-
-/* Get model name, STIG page 11 */
-static char *syn_model_name (int sensor) 
-{
-  if (sensor < 0 || 44 < sensor ) {
-    return "Reserved";
-  } else {
-    return model_names [sensor];
-  }
-}
-
-/* convert the model id from bits to values 
-*  STIG page 11 
-*/
-static void syn_extract_model_id_info (int model_int, model_id_type *model) 
-{
-  model->info_rot180     = check_bits (model_int,  INFO_ROT180_BITS);
-  model->info_portrait   = check_bits (model_int,  INFO_PORTRAIT_BITS);
-  model->info_sensor     =            (model_int & INFO_SENSOR_BITS)   >> 16;
-  model->info_hardware   =            (model_int & INFO_HARDWARE_BITS) >> 8;
-  model->info_new_abs    = check_bits (model_int,  INFO_NEW_ABS_BITS);
-  model->info_cap_pen    = check_bits (model_int,  INFO_CAP_PEN_BITS);
-  model->info_simple_cmd = check_bits (model_int,  INFO_SIMPLE_CMD_BITS);
-  model->info_geometry   =            (model_int & INFO_GEOMETRY_BITS);
-}
-
-
-/* Translate the reported data into a record for processing 
- *  STIG page 14*/
-static sensor_info_type *syn_get_sensor_info (int sensor_id) 
-{
-  if (sensor_id < 0 || 12 < sensor_id ) {
-    return &sensor_info [0];
-  } else {
-    return &sensor_info [sensor_id];
-  }
-}
-
-
-
-/* Translate the reported data of extended capabilities STIG page 15.  If the
- extended bit is not set it should be assumed that neither of the other
- capabilities is available.*/
-static void syn_extract_extended_capabilities(int ext_cap_int, ext_cap_type *cap)
-{
-
-# ifdef DEBUG  
-  gpm_report(GPM_PR_INFO,"Synaptics Device Capabilities: %02X",ext_cap_int);
-# endif 
-
-  cap->cap_ext            = check_bits (ext_cap_int, EXT_CAP_EXTENDED);
-
-  if(cap->cap_ext){
-    cap->cap_stick        = check_bits (ext_cap_int, EXT_CAP_STICK);
-    cap->cap_sleep        = check_bits (ext_cap_int, EXT_CAP_SLEEP);
-    cap->cap_four_button  = check_bits (ext_cap_int, EXT_CAP_FOUR_BUTTON);
-    cap->cap_multi_finger = check_bits (ext_cap_int, EXT_CAP_MULTI_FINGER);
-    cap->cap_palm_detect  = check_bits (ext_cap_int, EXT_CAP_PALM_DETECT);
-  }else{
-    cap->cap_stick        = 0;
-    cap->cap_sleep        = 0;
-    cap->cap_four_button  = 0;
-    cap->cap_multi_finger = 0;
-    cap->cap_palm_detect  = 0;
-    /* Wmode is not supported, but this should be turned off after reading the
-       config file.*/
-  }
-}
-
-
-/*
-** Check for edges.
-*/
-static int tp_edges (location_type loc) 
-{
-  int edges = 0;
- 
-  if (loc.x <= x_min_center)
-    edges |= LEFT_EDGE;
-
-  if (loc.x >= x_max_center)
-    edges |= RIGHT_EDGE;
-
-  if (loc.y <= y_min_center)
-    edges |= BOTTOM_EDGE;
-
-  if (loc.y >= y_max_center)
-    edges |= TOP_EDGE;
-
-  return edges;
-}
-
-
-/**
- ** Handle scrolling. The wheel is way too fast to be usefull, so only report
- ** every scrolling_speed. This function is also called when scrolling is done by
- ** buttons, which is why DOWN and UP must be removed in the case of not scrolling.
- */
-
-static void tp_handle_scrolling(Gpm_Event *state)
-{
-  /* Limit the amount of scrolling, so that we do not overrun. */
-  if ( scrolling_amount_left >  256*20 )
-    scrolling_amount_left = 256*20;
-
-  if ( scrolling_amount_left < -256*20 )
-    scrolling_amount_left = -256*20;
-
-  state->buttons &= ~(GPM_B_DOWN | GPM_B_UP);
-  
-  if (scrolling_amount_left > scrolling_speed){
-    scrolling_amount_left -= scrolling_speed;
-    state->buttons |= GPM_B_UP;
-  }else if (scrolling_amount_left < -scrolling_speed){
-    scrolling_amount_left += scrolling_speed;
-    state->buttons |= GPM_B_DOWN;
-  } 
-}
-
-
-/*
-** process_action
-**
-** Do the action and return a button state for a given action list and mask.
-** Actions that should not be repeated should report GPM_B_NOT_SET (when
-** holding down a button).
-*/
-
-static int tp_process_action(touchpad_action_type *action_list, int mask)
-{
-  int i = 0;
-  int status = GPM_B_NOT_SET;
-  static int Left_Double_Click = 0;
-
-  if (mask == 0){
-    gpm_report (GPM_PR_WARN,"Action Mask is 0");
-    return GPM_B_NOT_SET;
-  }
-  
-  while (action_list [i].action_mask) {
-    if (check_bits (mask, action_list [i].action_mask)) {
-      switch (action_list [i].action) {
-      case Left_Button_Action:
-	status = GPM_B_LEFT;
-	break;
-      case Middle_Button_Action:
-	status = GPM_B_MIDDLE;
-	break;
-      case Right_Button_Action:
-	status = GPM_B_RIGHT;
-	break;
-      case Fourth_Button_Action:
-	status = GPM_B_FOURTH;
-	break;
-      case Up_Button_Action:
-	scrolling_amount_left += ceil(scrolling_button_factor * scrolling_speed);
-	status = GPM_B_UP;
-	break;
-      case Down_Button_Action:
-	scrolling_amount_left -= ceil(scrolling_button_factor * scrolling_speed);
-	status = GPM_B_DOWN;
-	break;
-      case Left_Double_Click_Action:
-	Left_Double_Click++;
-	status = GPM_B_LEFT; 
-	if(Left_Double_Click == 2)
-	  status = GPM_B_NONE; 
-	if(Left_Double_Click == 4) {
-	  status = GPM_B_NOT_SET; 
-	  Left_Double_Click = 0;
-	}
-	break;
-      case Turn_On_Off_Action:
-	touchpad_enabled = !touchpad_enabled;
-	status = GPM_B_NOT_SET;
-	break;
-      case Debug_On_Off_Action:
-#       ifdef DEBUG_SYNAPTIC
-	  debug_syn_to_stderr = !debug_syn_to_stderr;
-#       endif
-	status = GPM_B_NOT_SET;
-	break;
-      case Reset_Touchpad_Action:
-	syn_ps2_reset(mouse_fd);
-	syn_ps2_absolute_mode(mouse_fd);
-	status = GPM_B_NOT_SET;
-	break;
-      case Toggle_Four_Way_Button_Action:
-	four_way_button_is_mouse = !four_way_button_is_mouse;
-	status = GPM_B_NOT_SET;
-	break;
-      case Toggle_Stick_Pressure_Action:
-	stick_pressure_enabled = !stick_pressure_enabled;
-	status = GPM_B_NOT_SET;
-	break;
-      case Toggle_Scrolling_Action:
-	is_always_scrolling = !is_always_scrolling;
-	status = GPM_B_NOT_SET;
-	break;
-      case No_Action:
-	status = GPM_B_NOT_SET;
-	break;
-      default:
-	gpm_report (GPM_PR_WARN,"Default Action: Action no. %X not defined",
-		    action_list [i].action); 
-	status = GPM_B_NOT_SET;
-	break;
-      }
-
-      return status;
-    }
-    
-    i++;
-  }
-  
-  return status;
-}
-
-
-/*
-** tp_process_corner_taps. 
-**
-** last_*_action is an easy way of remember which taps/buttons should call/repeat
-** the action when the tap/button is held pressed. It could just as well  have
-** been one variable where each bit held the repeater info for all the
-** tap/buttons, but that will mean more code.
-**
-** The reason for not actually reusing last_*_action, instead of
-** calculating it again, is that some actions like scrolling have "side effects".
-** This may be perceived as a design fault.
-**
-** tp_process_corner_taps and tp_process_button_press are more complicated than
-** to what is obvious. This is because 1) in a corner tap-and-hold the hold
-** could take place at non edge. 2) A normal tap-and-hold can be moved to a
-** corner.
-*/
-static void tp_process_corner_taps (Gpm_Event *state, report_type *report) 
-{
-  static int edges_at_cornertap_time;
-
-  if (report->gesture && 
-      ((is_corner (was_edges) && !last_report.gesture) || 
-       (last_corner_action != GPM_B_NOT_SET))) {
-
-    if(!last_report.gesture && last_corner_action == GPM_B_NOT_SET)
-      edges_at_cornertap_time = was_edges;
-
-    last_corner_action = tp_process_action(corner_actions,edges_at_cornertap_time);
-
-    if (last_corner_action != GPM_B_NOT_SET)
-      state->buttons |= last_corner_action;
-  } 
-}
-
-/* tp_process_button_press
-**
-** Handles finger taps. Same way as tp_process_corner_taps.
-**
-** Should only calculate a tap if 
-** 1) There is a gesture (tap)
-** 2) The tap did not start at a corner with a corneraction
-** 3) If it is calculated before it should have returned a repeating action.
-*/
-static void tp_process_finger_taps (Gpm_Event *state, report_type *report) 
-{
-
-
-  if (report->gesture && last_corner_action == GPM_B_NOT_SET &&
-      !(corner_taps_enabled && is_corner (was_edges) && !last_report.gesture) &&
-      !(last_report.gesture && last_finger_action == GPM_B_NOT_SET) ){
-
-    if( ( multi_finger_tap_enabled && (was_fingers == 0 || was_fingers == 1)) ||
- 	(!multi_finger_tap_enabled && was_fingers > 0))
-      last_finger_action = tp_process_action(multi_finger_actions, ONE_FINGER);
-    
-    if (multi_finger_tap_enabled && was_fingers == 2)
-      last_finger_action = tp_process_action(multi_finger_actions, TWO_FINGERS);
-    
-    if (multi_finger_tap_enabled && was_fingers == 3)
-      last_finger_action = tp_process_action(multi_finger_actions, THREE_FINGERS);
-    
-    if (last_finger_action != GPM_B_NOT_SET) 
-      state->buttons |= last_finger_action;
-  }
-}
-
-/*
-** tp_process_do_repeating_action
-**
-** The function test whether a feature's action should be repeated/called.  The
-** action should be called if the feature is there and if it was there last
-** time, then it should be a repeating action.
-*/
-
-static inline void 
-tp_process_repeating_action(Gpm_Event *state, int feature, int last_feature, int *last_action, 
-			    touchpad_action_type *action_list,int feature_mask)
-{
-  if (feature) {
-    if (!(last_feature && *last_action == GPM_B_NOT_SET)) {
-      *last_action = tp_process_action(action_list, feature_mask);
-      if (*last_action != GPM_B_NOT_SET)
-	state->buttons |= *last_action;
-    }
-  } else {
-      *last_action = GPM_B_NOT_SET;
-  }
-}
-
-/*
-** tp_process_do_repeating_actions
-**
-** Call tp_process_do_repeating_action foreach possible action (right now only buttons.)
-*/
-
-static inline void 
-tp_process_repeating_actions(Gpm_Event *state, int features, int last_features, int last_actions[], 
-			     touchpad_action_type *action_list)
-{
-  int feature_no, feature_mask;
-
-  for(feature_no = 0; feature_no < 8; feature_no++) {
-    feature_mask = (1<<feature_no);
-    tp_process_repeating_action(state, features & feature_mask, last_features & feature_mask,
-				&last_actions[feature_no], action_list, feature_mask);
-  }
-}
-
-/* tp_process_button_press
-**
-** Handles normal button presse explicitly because of the report
-** layout (instead of using tp_process_do_repeating_actions).
-*/
-static void tp_process_button_press (Gpm_Event *state, report_type *report) 
-{
-
-  tp_process_repeating_action(state, report->left, last_report.left,
-			      &last_normal_button_actions[0], normal_button_actions, LEFT_BUTTON);
-
-  tp_process_repeating_action(state, report->right, last_report.right,
-			      &last_normal_button_actions[1], normal_button_actions, RIGHT_BUTTON);
-
-  tp_process_repeating_action(state, report->middle, last_report.middle,
-			      &last_normal_button_actions[2], normal_button_actions, MIDDLE_BUTTON);
-
-  tp_process_repeating_action(state, report->fourth, last_report.fourth,
-			      &last_normal_button_actions[3], normal_button_actions, FOURTH_BUTTON);
-
-  tp_process_repeating_action(state, report->up, last_report.up,
-			      &last_normal_button_actions[4], normal_button_actions, UP_BUTTON);
-
-  tp_process_repeating_action(state, report->down, last_report.down,
-			      &last_normal_button_actions[5], normal_button_actions, DOWN_BUTTON);
-}
-
-
-/*
-** syn_process_wmode_report
-**
-** Translate synaptics specific values.
-*/
-
-
-static void syn_process_wmode_report( report_type *report )
-{
-  /* STIG page 9: Values of w, vary from pad to pad. It is not precise when pressure is small < 25.
-   * 4-7  finger of normal width
-   * 8-14 very wide finger or palm
-   * 15   maximum reportable width     
-   */
-  report->fingerwidth = max(0,report->w - 4);
-
-  /* Check whether there is one finger on the pad */
-  report->fingers  = (report->pressure > finger_threshold);
-  
-  /* use w values. w = 0: 2 fingers, w = 1: 3 fingers, (if there is pressure) */
-  if (capabilities[0].cap_multi_finger){      
-    if (report->pressure != 0 && (report->w == 0 || report->w == 1)){
-      report->fingers = 2+report->w;
-    }
-  }
-}
-
-
-
-/*
-** syn_ps2_process_extended_packets
-**
-** The internal synaptics ps2 touchpads can have extra devices attached (stick,
-** 4 way button) to them, and they reports there state as special embedded
-** packets. These attached devices are handled here.
-**
-** The function returns 1 if it does not make sense to continue normal touchpad
-** processing, 0 otherwise.
-**            
-** I dont think that the external touchpads (serial) can have the same devices
-** attached.  This code should be moved to ps2 specific part, but it is easy to
-** have it here.
-*/
-
-static int syn_ps2_process_extended_packets( unsigned char *data, 
-					     report_type *report,
-					     Gpm_Event *state)
-{
-  static int last_stick_buttons = GPM_B_NONE;
-  static int last_4_way_buttons = GPM_B_NONE;
-  int tmp_buttons = GPM_B_NONE;
-
-  /* Sanity check of data. */
-  if ((report->pressure == 0 && (report->x != 0 || report->y != 0)) ||
-      report->w == 3 ) {
-
-     /* Something is wrong, should we assume it is an extended packet?  It
-     *  cannot be processed further than here as the pressure is 0, which would
-     *  break things, if the user uses it simultaneously with the touchpad. 
-     */
-    /* Allow some simultaneously usage: tap-hold on touchpad, with extended movement.
-     * Do not do buttons, as they are not always correctly defined yet. */
-    if (last_report.gesture) {
-      report->gesture = 1;
-      if(tap_gesture_enabled) tp_process_finger_taps (state, report);
-      if(corner_taps_enabled) tp_process_corner_taps (state, report);
-    }
-
-    /* Stick invariant bits (I hope). See absolute packets */
-    /* Stick pressed: The stick do only generates one packet, so double tap is
-     * a problem; squeezing in a non-clicked state. It is probably not a real
-     * problem, as it is hard not to move the stick a little between pressing,
-     * thereby returning a non-clicked state between the packets. Maybe
-     * press-lock mechanism is useful. Forget it, the styk supports it! */
-    if((data[0] & 0xFC) == 0x84 && 
-       (data[1] & 0xC8) == 0x08 &&
-       (data[3] & 0xFC) == 0xC4){
-
-      tp_process_button_press (state,report);
-
-      if (stick_enabled) {
-	state->dx=  ((data[1] & 0x10) ? data[4]-256 : data[4]);
-	state->dy= -((data[1] & 0x20) ? data[5]-256 : data[5]);
-      }
-
-      if (stick_pressure_enabled) {
-  	tmp_buttons  = ((data[1] & 0x01) ? STICK_LEFT_BUTTON   : 0);
-  	tmp_buttons |= ((data[1] & 0x04) ? STICK_MIDDLE_BUTTON : 0);
-  	tmp_buttons |= ((data[1] & 0x02) ? STICK_RIGHT_BUTTON  : 0);
-	tp_process_repeating_actions(state,tmp_buttons,last_stick_buttons,
-				     &last_stick_button_actions[0],stick_actions);
-      } 
-
-      last_stick_buttons = tmp_buttons;
-            
-#     ifdef DEBUG_STICK      
-      gpm_report (GPM_PR_DEBUG,"StickData? %02x %02x %02x %02x %02x %02x :dx:%d dy:%d b:%d",
-		  data[0],data[1],data[2],data[3],data[4],data[5],
-		  state->dx,state->dy,state->buttons);
-#     endif
-      return 1;
-    }
-
-    /* 4 way button invariant bits (I hope). I dont know the official name. */
-    if((data[0] & 0xFC) == 0x80 &&
-       (data[1] & 0xFF) == 0x00 &&
-       (data[3] & 0xFC) == 0xC0 &&
-       report->x < 4 && report->y < 4 ){
-
-      if(four_way_button_enabled){
-
-	report->fourth = !report->fourth;   /* Note that this is reversed. */
-	tp_process_button_press (state,report);
-
-	if (four_way_button_is_mouse){
-	  /* Report motion */
-	  if (report->x & 1) /* UP */
-	    state->dy = -1;
-	  if (report->y & 1) /* DOWN */
-	    state->dy = 1;
-	  if (report->x & 2) /* LEFT */
-	    state->dx = -1;
-	  if (report->y & 2) /* RIGHT */
-	    state->dx = 1;
-	}else{ 
-	  /* Report buttons */
-	  tmp_buttons  = ((report->x & 1) ? FOUR_UP_BUTTON   : 0); /* UP */
-	  tmp_buttons |= ((report->y & 1) ? FOUR_DOWN_BUTTON : 0); /* DOWN */
-	  tmp_buttons |= ((report->x & 2) ? FOUR_LEFT_BUTTON : 0); /* LEFT */
-	  tmp_buttons |= ((report->y & 2) ? FOUR_RIGHT_BUTTON: 0); /* RIGHT */
-	  tp_process_repeating_actions(state,tmp_buttons,last_4_way_buttons,
-				       &last_4_way_button_actions[0],four_button_actions);	  
-	}
-      }
-
-      last_4_way_buttons = tmp_buttons;
-
-      if ( scrolling_amount_left != 0 ){
-	tp_handle_scrolling(state);
-      }
-
-      return 1;
-    } 
-
-    /* This is unknown packet. */
-    gpm_report (GPM_PR_ERR,"\rSynps2: Pressure is 0, but x or y is not 0. "
-		           "Data: %02X %02X %02X %02X %02X %02X",
-		data [0],data [1],data [2],data [3],data [4],data [5]);
-    return 1;
-  }
-
-  /* Multiplexing with the stick (guest) device. */
-  state->buttons |= last_4_way_buttons | last_stick_buttons;
-
-  return 0;
-}
-
-/**
-** Preprocess the report even before doing wmode stuff.
-** Is always called directly after the conversion to check the data received.
-** return 0 if it is reasonable, 1 if there is something wrong.
-**
-** Checks for correct data package, palm on the pad, number of fingers.
-**            
-*/
-
-static int tp_find_fingers ( report_type *report,
-			     Gpm_Event *state)
-{
-
-  static int fake_extra_finger;
-  static int was_fake_pressure;
-
-  /* Check whether there is a palm on the pad */
-  if (palm_detect_enabled &&  
-      report->fingers && (report->fingerwidth >= palm_detect_level)){
-#   ifdef DEBUG_PALM
-    gpm_report (GPM_PR_DEBUG,"\rTouchpad: palm detected. finger width: %d",report->fingerwidth); 
-#   endif
-    /* BUG should not return 1, as this drops packets. Return a repeated report ? */
-    /*       last_locs [mod4 (packet_num - 1)].x = report->x; */
-    /*       last_locs [mod4 (packet_num - 1)].y = report->y; */
-    /*     or */
-    /*       report->pressure = 0; */
-    return 1;
-  }
-
-
-  /* Extra check for vertical multi fingers which my pad is very bad to detect.
-  ** Only check for extra fingers if no of fingers has not changed.  Faking
-  ** fingers may go wrong so sanity check needed.  This is not an attempt to
-  ** know the number of fingers all the time, as this is not needed. 
-  */
-  if (fake_finger_layer_enabled){
-    
-    if (report->fingers > 1){
-      fake_extra_finger = 0;
-    }
-        
-    if(report->fingers == 0){
-      fake_extra_finger = 0;
-#     ifdef DEBUG_REPORTS
-        multi_finger_pressure  = 0;
-        multi_finger_xy = 0;
-#     endif
-    }else
-      if (report->fingers + fake_extra_finger == last_report.fingers) {
-
-	multi_finger_pressure = sqr(report->pressure) - sqr(last_report.pressure);
-	multi_finger_xy = (sqr(last_locs [mod4 (packet_num - 1)].x - report->x) +
-			   sqr(last_locs [mod4 (packet_num - 1)].y - report->y) );
-
-	/* Check for a second finger. If the move is larger than tap range,
-	* then it is not a tap, and adding the finger does not change reported        
-	* buttons, but it will still stop the moving if
-	* multi_finger_stop_enabled is on. These tests are complete base on my
-	* imagination and experience, so any better idea are welcome. */
-	if(report->fingers == 1 && 
-	   multi_finger_pressure > 4500 && multi_finger_xy > 2*sqr((double)tap_range)){
-	    fake_extra_finger = 1;
-	    was_fake_pressure =  report->pressure;
-
-	}/* Check for third finger. */
-	else if(last_report.pressure  > 180  && (report->fingers + fake_extra_finger) == 2 &&
-		 multi_finger_pressure > 4500 && multi_finger_xy > 2*sqr((double)tap_range)){
-	  fake_extra_finger = 2;
-	  was_fake_pressure = report->pressure;
-
-	} else if ( (fake_extra_finger > 0) &&
-		    (was_fake_pressure - report->pressure > 20)){
-	  fake_extra_finger --;
-
-	} else if(multi_finger_pressure < -5000 && multi_finger_xy > 2*sqr((double)tap_range)){
-	  /* Probably missed a placed multi finger, as this is one removed! */
-	  last_report.fingers ++;
-	}
-      }
-    
-    report->fingers += fake_extra_finger;
-    
-  }
-
-
-  /* Check whether to reduce sensibility when adding or removing fingers */
-  if (multi_finger_stop_enabled){
-
-    /* Is a finger added or removed since last packet? */
-    if( (report->fingers     > 1 && report->fingers > last_report.fingers) ||
-	(last_report.fingers > 1 && report->fingers < last_report.fingers) ){
-
-      /* Updating the timer right after another added/removed finger,
-       * would make the undo moving become redo, so dont.*/
-      if(multi_finger_stop_timer != multi_finger_stop_delay - 1)
-	multi_finger_stop_timer  = multi_finger_stop_delay;
-
-#     ifdef DEBUG_MULTI_FINGER
-      gpm_report (GPM_PR_DEBUG,"%s multi finger %d %d %d",
-		  report->fingers > last_report.fingers ? "Add":"Remove",
-		  last_report.fingers,report->fingers,fake_extra_finger);
-#     endif
-      
-    } /* Should be tested last, because of undo moving when removing fingers. */
-    else if(report->fingers == 0){
-	multi_finger_stop_timer = 0;
-    }
-
-    /* Stop moving the mouse after a finger adding/removing. */
-    if( multi_finger_stop_timer > 0){
-      last_locs [mod4 (packet_num - 1)].x = report->x;
-      last_locs [mod4 (packet_num - 1)].y = report->y;
-      last_locs [mod4 (packet_num - 2)].x = report->x;
-      last_locs [mod4 (packet_num - 2)].y = report->y;
-
-      /* Undo the previous move (before detecting of the adding/removing). */
-      if (multi_finger_stop_timer == multi_finger_stop_delay){
-	last_locs [mod4 (packet_num - 2)].x += last_state.dx * 2 / standard_speed_factor;
-	last_locs [mod4 (packet_num - 2)].y -= last_state.dy * 2 / standard_speed_factor;	
-      }
-
-      multi_finger_stop_timer --;
-    }
-  }
-
-  /* If wmode is not used, we do not know all the informations to reset the
-   * was_fingers variable or stop waiting for a tap-hold, so set a timer to
-   * reset the variables when we believe it is time.  pads_tap_interval is
-   * optimal when set to the touchpads tap_interval.
-   */
-
-  if(fake_forget_tap_interval){
-    if (report->fingers || report->gesture)
-      fake_time_to_forget_tap = pads_tap_interval;
-
-    if(fake_time_to_forget_tap > 0)
-      fake_time_to_forget_tap --;
-    else
-      was_fingers = 0;
-  }
-
-
-  was_fingers = max(was_fingers,report->fingers);
-
-  return 0;
-}
-
-
-/** 
-** tp_find_gestures
-** Process the report from a wmode enabled device.  No gesture calculation is
-** done by the device in wmode, so the find tap and drag hold and tap hold gestures.
-**
-** Tap mechanism: High when touched. (=: assigned, -: decreased, +: increased)
-**
-**                         _________________________  
-**                         | tap_lower/upper_limit |tap_interval|  
-**         -----------------                       -----------------
-** 
-** stroke_x/y         :    =                         
-** finger_on_pad_timer: 0000123        +++++++++++++0000000000000000
-** time_to_forget_tap : 0000000        000000000000=---------3210000
-** gesture_delay      : 0000000  ...   00000000000000000000000000000
-** drag_locked        : 0000000        00000000000000000000000000000
-** gesture            : 0000000        00000000000011111111111110000
-**
-** Note:
-**  0) When gesture is high a button is reported pressed (usually left button).
-**  1) finger_on_pad_timer is increased at most to 1 larger than tap_upper_limit,
-**     but then it is not a tap any longer.
-**  2) If tap_interval is larger than 1s (80 packets) then time_to_forget_tap never reaches 0,
-**     before the touchpads stop sending packets, so gesture is reported until touched again.  
-**
-**
-** Tap hold mechanism: High when touched. (=: assigned, -: decreased, +: increased)
-**
-**                                       tap_interval
-**                         ________________  v ___   ___
-**                         |tap_l/u_limit |    |not tap|
-**         -----------------              ------       --------    
-** 
-** stroke_x/y         :    =                   =      
-** finger_on_pad_timer: 0000123+       +++00000123++  +++0000
-** time_to_forget_tap : 00000000       000=----11111  1110000
-** gesture_delay      : 00000000 ...   0000000000000  0000000
-** drag_locked        : 00000000       0000000000000  0000000
-** gesture            : 00000000       0001111111111  1110000
-**
-** Note:
-**  0) time_to_forget_tap is set to 1 when touching the pad 2 time, so the gesture is stop when released. 
-**     (two fast taps would be a problem).
-**
-**
-** Two consecutive taps mechanism: High when touched. (=: assigned, -: decreased, +: increased)
-**
-**                                       tap_interval  multiple_tap_delay
-**                         ________________  v _______________  v   |
-**                         |tap_l/u_limit |    |tap_l/u_limit|  
-**         -----------------              ------             --------    
-** 
-** stroke_x/y         :    =                   =      
-** finger_on_pad_timer: 0000123+       +++00000123++       ++00000000000000000
-** time_to_forget_tap : 00000000       000=----11111       11=---------32100000
-** gesture_delay      : 00000000 ...   0000000000000 ...   00=----3210000000000
-** drag_locked        : 00000000       0000000000000       00000000000000000000
-** gesture            : 00000000       0001111111111       11000000001111100000
-**
-** Note:
-**  0) There is no gesture if gesture_delay is non zero.
-**  1) multiple_tap_delay (gesture_delay) should be less than tap_interval (time_to_forget_tap),
-**     or else no second tap is reported.
-**  2) Three fast taps (shorter than multiple_tap_delay) would reset gesture_delay the second time 
-**     and only report 2 taps (the first and last). (likewise with more fast taps). BUG ?
-**
-**
-** Drag lock mechanism: High when touched. (=: assigned, -: decreased, +: increased)
-** MISSING
-*/
-
-
-static void tp_find_gestures (report_type *report) 
-{
-  static int finger_on_pad_timer = 0;
-  static int time_to_forget_tap = 0;
-  static int stroke_x;
-  static int stroke_y;
-  static int drag_locked = 0;
-
-
-  if (report->fingers > 0) {
-	    
-    /* finger down for the first time */
-    if (finger_on_pad_timer == 0) { 
-      stroke_x = report->x;
-      stroke_y = report->y;
-    }
-    
-    /* don't want timer to overflow */
-    if (finger_on_pad_timer < (tap_upper_limit_packet)) 
-      finger_on_pad_timer ++; 
-    
-    /* dragging and consecutive tap gestures is to end with finger up 
-     *  forget fast that there was a tap if this is not a part of a tap.*/
-    if (time_to_forget_tap > 0) 
-      time_to_forget_tap = 1;
-    
-  } else { /* interesting things happen when finger is up */
-      
-    /* tap determination: Was the finger long enough on the pad and not too
-     * long, while staying at the same place.
-     */
-    if ((finger_on_pad_timer > (tap_lower_limit_packet)) &&  /* minimum finger down time */
-	(finger_on_pad_timer < (tap_upper_limit_packet)) &&  /* maximum finger down time */
-	((distance((double)(stroke_x - last_report.x),  /* maximum range for finger to drift while down */
-		   (double)(stroke_y - last_report.y))
-	 < sqr((double)tap_range)) ||
-	 (multi_finger_tap_enabled && was_fingers > 1))) {
-      
-      /* not a consecutive tap? */
-      if (time_to_forget_tap == 0) 
-	gesture_delay = 0; /* right -> don't delay gesture */
-      else { /* a consecutive tap! */
-	gesture_delay = multiple_tap_delay * 80 / 1000; /* delay gesture to create multiple click */
-      }
-      
-      /* is drag locked */
-      if (drag_locked) {
-	drag_locked = 0; /* unlock it and don't gesture. */
-	time_to_forget_tap = 0;
-      } else 
-	time_to_forget_tap = tap_interval * 80 / 1000; /* setup gesture time to count down */
-      
-    } else { /* It was not a tap */
-      
-      /* a drag to lock?  If user did a tap and quickly hold the finger longer than a tap.
-       */
-      if (drag_lock_enabled && 
-	  (time_to_forget_tap > 0) && (finger_on_pad_timer >= (tap_upper_limit_packet)))
-	drag_locked = 1;
-      
-      if (time_to_forget_tap  > 0) time_to_forget_tap --;
-      if (time_to_forget_tap == 0) was_fingers=0;
-      if (gesture_delay > 0) gesture_delay --;
-      
-    }
-    
-#   ifdef DEBUG_TAPS
-    if (finger_on_pad_timer)
-      gpm_report (GPM_PR_DEBUG,"A tap? %d < %d < %d && (%d)^2 + (%d)^2 < %d",
-		  tap_lower_limit_packet,finger_on_pad_timer,tap_upper_limit_packet,
-		  stroke_x-last_report.x,stroke_y-last_report.y,tap_range*tap_range);
-#   endif
-
-    finger_on_pad_timer = 0;
-    
-  }
-  
-  report->gesture  = ((time_to_forget_tap > 0) && (gesture_delay == 0)) || drag_locked;
-}
-
-
-/*
-** tp_process_report
-**
-** Process the touchpad report. Do tossing mechanism, edge mechanism (edge
-** extension, corner taps), speed pressure.
-**
-** Tossing mechanism: High when touched.  (=: assigned, -: decreased)
-**                                                                         (Pause)
-**                 ________________________        _____         ______ prevent_toss ___
-**                 | min/max_toss_packets |  < 1s  |      ....        |      ...     |  
-** -----------------                      ----------                  -----       ----  
-** 
-** is_tossing : 000000000000000000000000001111111111000000000000000000000000000000000000 
-** was_tossing: 000000000000000000000000000000000001111111111111111111111111111111100000
-** toss_timer :    =======================         ====================---- ... 321000==  
-**                           
-** Note 
-** 0) When is_tossing is high a motion is reported/calculated.
-** 1) if prevent_toss delay is 0 then toss to toss is allowed without pause.
-** 2) if the pause is to short (< prevent_toss), the timers start over!
-** 3) The 1 second limit is due to the touchpad only sends packets one second after a release.
-** 
-**
-*/
-static void tp_process_report (Gpm_Event *state,
-			       report_type *report) 
-{
-  location_type loc;
-  int           edges;
-  float         pressure_speed_factor;
-  float         edge_speed_factor;
-  int           edge_motion_on;
-  float         dx, dy;
-
-  /* extract location and edges */
-  loc.x = report->x;
-  loc.y = report->y;
-  edges = tp_edges (loc);
-
-
-  if (report->fingers > 0) {
-
-    if (tossing_enabled) {
-      /* this is the cue to stop tossing, if we are tossing so
-         Force a touch free pause before a new tossing is allowed (prevent toss time) */
-      was_tossing = (was_tossing || is_tossing);
-      toss_timer  = prevent_toss_packets;
-      is_tossing  = 0;
-      
-      /* if we start tossing then this is from where */
-      if (last_report.fingers == 0) {
-	touch_loc = loc;
-      }
-    }
-
-    /* Save the edge state, so we can detect a movement from non edge to edge. */
-    if (!edges)
-      was_non_edge = 1;
-
-    /* Need enough packets to perform smoothing on dy and dx
-    *  but it should work with only 2, so why is 4 required? */
-    if (packet_num > 3) {
-
-      /* Is this start of scrolling? */
-      if (scrolling_enabled && !is_scrolling)
-	is_scrolling  = ((edges & scrolling_edge)  && /* Note: only one &! */
-			 !was_non_edge         && /* Must start at edge */
-			 !last_report.gesture  && /* No consecutive tap */
-			 (!corner_taps_enabled || /* Corner disabled or */
-			  !is_corner (edges)));   /* no corner          */
-
-
-      /* 
-      ** 1) if edge motion is enabled, only activate if we moved into the edge or
-      ** if not using the corners taps.  Dont activate right away after a gesture
-      ** from a corner tap. 2) No harm is done if activated when scrolling (as
-      ** long as the scrolling edge is vertical). 3)If user is tap holding (then
-      ** he cannot lift the finger and hit the touchpad boarder).
-      */
-
-      edge_motion_on  = (edges && edge_motion_enabled &&
-			  (was_non_edge         || 
-			   !corner_taps_enabled ||
-			  (!is_corner(edges) && !last_report.gesture)));
-      edge_motion_on |= (edges && auto_scrolling_enabled && is_scrolling);
-      edge_motion_on |= (edges && tap_hold_edge_motion_enabled && last_report.gesture && 
-			 was_non_edge);
-
-
-      /* compute the speed factor based on pressure */
-      pressure_speed_factor = standard_speed_factor;
-
-      if (report->pressure > speed_up_pressure) {
-	pressure_speed_factor *= 1.0 + ((report->pressure - speed_up_pressure) *
-			       speed_pressure_factor);
-      }
-
-      /* use the edge speed factor if edge_motion_speed is enabled */
-      edge_speed_factor = (edge_motion_speed_enabled ?
-			   pressure_speed_factor :
-			   standard_speed_factor);
-      
-      pressure_speed_factor = (pressure_speed_enabled ?
-			       pressure_speed_factor :
-			       standard_speed_factor);
-      
-      if ( auto_scrolling_enabled && is_scrolling ){
-	edge_speed_factor *= 1.0 + auto_scrolling_factor; 
-      }
-
-
-      /* Calculate dx and dy depending on whether we are at an edge */
-
-      if (edge_motion_on && (edges & TOP_EDGE))
-	 state->dy = -edge_speed * edge_speed_factor;
-      else if (edge_motion_on && (edges & BOTTOM_EDGE))
-	 state->dy = edge_speed * edge_speed_factor;
-      else
-	 state->dy = (pressure_speed_factor *
-		      (((last_locs [mod4 (packet_num - 1)].y +
-			 last_locs [mod4 (packet_num - 2)].y) / 2) - 
-		       ((loc.y +
-			 last_locs [mod4 (packet_num - 1)].y) / 2)));
-      
-      if (edge_motion_on && (edges & LEFT_EDGE))
-	 state->dx = -edge_speed * edge_speed_factor;
-      else if (edge_motion_on && (edges & RIGHT_EDGE))
-	 state->dx = edge_speed * edge_speed_factor;
-      else
-	 state->dx = (pressure_speed_factor *
-		      (((loc.x +
-			 last_locs [mod4 (packet_num - 1)].x) / 2) - 
-		       ((last_locs [mod4 (packet_num - 1)].x +
-			 last_locs [mod4 (packet_num - 2)].x) / 2)));
-    } /* If (packet_num > 3)*/
-
-    last_locs [mod4 (packet_num)] = loc;
-    was_edges = edges;
-    packet_num++;
-  } else {
-    /* No finger on the pad */
-    /* Start the tossing action if enabled */
-    if (tossing_enabled && was_fingers == 1 &&
-	!was_tossing    &&
-	!is_scrolling   &&
-	(packet_num > min_toss_packets) &&
-	(packet_num < max_toss_packets)) {
-
-      dx =    last_locs [mod4 (packet_num - 1)].x - touch_loc.x;
-      dy = - (last_locs [mod4 (packet_num - 1)].y - touch_loc.y);
-
-#if DEBUG_TOSS
-      gpm_report (GPM_PR_INFO,"dx: %2.1f  dy: %2.1f  tdist^2: %2.1f",
-		  dx, dy, distance (dx, dy));
-#endif
-
-      if (distance (dx, dy) > min_toss_dist__2) {
-	is_tossing = 1;
-
-	/* determine the toss speed */
-	if (does_toss_use_static_speed) {
-	  toss_speed.x = (static_toss_speed * standard_speed_factor *
-			  dx / (abs (dx) + abs (dy)));
-	  toss_speed.y = (static_toss_speed * standard_speed_factor *
-			  dy / (abs (dx) + abs (dy)));
-	} else {
-	  toss_speed.x = dx * standard_speed_factor * toss_speed_factor;
-	  toss_speed.y = dy * standard_speed_factor * toss_speed_factor;
-	}
-
-#if DEBUG_TOSS
-	gpm_report (GPM_PR_INFO,"tossx: %d  tossy: %d", toss_speed.x, toss_speed.y);
-#endif
-      }
-    }
-
-    /* no fingers therefore: no edge, and restart packet count */
-    was_non_edge = 0;
-    is_scrolling = 0;
-    scrolling_speed_timer = 0;
-    packet_num = 0;
-  }
-
-
-  /* if we are tossing then apply the toss speed */
-  if (tossing_enabled && is_tossing) {
-    state->dx = toss_speed.x;
-    state->dy = toss_speed.y;
-    }
-
-
-  /* if we are scrolling then stop moving and report wheel amount.  The reason
-  ** for having this above buttons actions is buttons can then move the
-  ** mouse while scrolling. 
-  */
-  if ((scrolling_enabled && is_scrolling) ||
-      is_always_scrolling){
-    scrolling_amount_left -= state->dy;
-    state->dx = 0;
-    state->dy = 0;
-  }
-
-
-  /* check for (corner)buttons if we didn't just complete a toss or is scrolling */
-  if (!is_tossing && !was_tossing && !is_scrolling) {
-    /*
-    ** If there is no gesture then there are no buttons, but dont clear if we
-    ** are about to make a double tap.  Otherwise compute new buttons.
-    */
-    if (!report->gesture && 
-	!report->left && !report->right && !report->middle && !report->fourth ) {
-      if (!gesture_delay && !fake_time_to_forget_tap) {
-	last_corner_action = GPM_B_NOT_SET;
-	last_finger_action = GPM_B_NOT_SET;
-      }
-      state->buttons = GPM_B_NONE;
-    } else {
-      tp_process_button_press (state, report);
-      if(tap_gesture_enabled) tp_process_finger_taps (state, report);
-      if(corner_taps_enabled) tp_process_corner_taps (state, report);
-    }
-  }
-
-  /* Is there any amount of scrolling left?  Should be checked after corner actions. */
-  if (scrolling_amount_left != 0){
-    tp_handle_scrolling(state);
-  }
-
-
-  was_tossing  = was_tossing && toss_timer;
-  if (was_tossing)
-    toss_timer--;
-
-
-  /* remember the last state of the finger for toss processing */
-  last_report   = *report;
-  last_state    = *state;
-
-  /* Dont do anything if the pad is not enabled, but after corner actions are
-   * done so it can be turn on again. */
-  if (!touchpad_enabled){
-    state->buttons = GPM_B_NONE;
-    state->dx      = 0;
-    state->dy      = 0;
-  }
-
-#if DEBUG_REPORTS
-  tp_dump_report_data (*report, edges, state);
-#endif
-
-}
-
-
-/*
-** syn_read_config_file
-**
-** Read the configuration data from the global config file
-** SYSCONFDIR "/gpm-syn.conf".
-*/
-void tp_read_config_file (char* config_filename) 
-{
-  char line [80];
-  char *token;
-  char *end_ptr;
-  int  param, tmp_read_int_param;
-  FILE *config;
-  char full_filename[100];
-  int  status;
-  float tmp_read_float_param;
-
-  status = snprintf(full_filename,100,SYSCONFDIR "/%s",config_filename);
-  if (status < 0) {
-    gpm_report (GPM_PR_WARN,"Too long path for configure file: %s", config_filename); 
-    return;
-  }
-
-
-  if ( !(config = fopen (full_filename, "r")) ) {
-    gpm_report (GPM_PR_WARN,"Failed to open configfile: %s", full_filename);    
-  }else{
-    while (fgets (line, 80, config)) {
-      if (line [0] == '[') {
-	if ( (token = strtok (line, "[] \t")) ) {
-	  param = 0;
-
-	  /* which param is it */
-	  while (param_data [param].name &&
-		 strcasecmp (token, param_data [param].name) != 0) {
-	    param++;
-	  }
-
-	  /* was a param found? */
-	  if (!param_data [param].name) {
-	    gpm_report (GPM_PR_WARN,"Unknown parameter %s", token);
-	  } else {
-	    token = strtok (NULL, "[] \t");
-
-	    switch (param_data [param].p_type) {
-	    case Integer_Param:
-	      tmp_read_int_param = strtol (token, &end_ptr, 0);
-	      if (end_ptr != token)
-		*(param_data [param].addr.int_p) = tmp_read_int_param;
-	      else
-		gpm_report (GPM_PR_WARN,"Integer value (%s) for parameter %s is invalid",
-			    token, param_data [param].name);
-#             if DEBUG_PARAMS
-	      gpm_report (GPM_PR_INFO,"Param %s set to %d",
-			  param_data [param].name,
-			  *(param_data [param].addr.int_p));
-#             endif
-	      break;
-
-	    case Float_Param:
-	      tmp_read_float_param = strtod (token, &end_ptr);
-	      if (end_ptr != token)
-		*(param_data [param].addr.float_p) = tmp_read_float_param;
-	      else
-		gpm_report (GPM_PR_WARN,"Float value (%s) for parameter %s is invalid",
-			    token, param_data [param].name);
-#             if DEBUG_PARAMS
-	      gpm_report (GPM_PR_INFO,"Param %s set to %3.3f",
-			  param_data [param].name,
-			  *(param_data [param].addr.float_p));
-#             endif
-	      break;
-
-	    case Flag_Param:
-	      if (index ("YyTt1", token [0])) {
-		*(param_data [param].addr.flag_p) = 1;
-	      } else if (index ("NnFf0", token [0])) {
-		*(param_data [param].addr.flag_p) = 0;
-	      } else {
-		gpm_report (GPM_PR_WARN,"Flag value (%s) for parameter %s is invalid",
-			    token, param_data [param].name);
-	      }
-#             if DEBUG_PARAMS
-	      gpm_report (GPM_PR_INFO,"Param %s set to %s",
-			  param_data [param].name,
-			  (*(param_data [param].addr.flag_p) ?
-			   "True" : "False"));
-#             endif
-	      break;
-
-	    case Action_Param:
-	      tmp_read_int_param = strtol (token, &end_ptr, 0);
-	      if (end_ptr != token)
-		param_data [param].addr.corner_p->action = tmp_read_int_param;
-	      else
-		gpm_report (GPM_PR_WARN,"Action value (%s) for parameter %s is invalid",
-			    token, param_data [param].name);
-#             if DEBUG_PARAMS
-	      gpm_report (GPM_PR_INFO,"Param %s set to %d",
-			  param_data [param].name,
-			  param_data [param].addr.corner_p->action);
-#             endif
-	      break;
-
-	    default: ;
-	    }
-	  }
-	}
-      }
-    }
-
-    fclose (config);
-  }
-}
-
-
-/*
-** syn_process_touchpad_config
-**
-** Extract important information and report (as desired) to the user.
-*/
-static void syn_process_config (info_type ident,
-				model_id_type model) 
-{
-  sensor[0] = syn_get_sensor_info (model.info_sensor);
-  gpm_report (GPM_PR_INFO, "     Firmware version %d.%d\n",
-	      ident.info_major, ident.info_minor);
-
-  tp_read_config_file ("gpm-syn.conf");
-
-  
-  /* Limit the options depending on the touchpad capabilities. This should be
-     done after reading the configure file so they may be turned off on purpose
-     and can'nt be turned on if not supported. */
-  if(!capabilities[0].cap_ext){
-    wmode_enabled         = 0;
-  }
-
-  if(!wmode_enabled || !capabilities[0].cap_palm_detect){
-    palm_detect_enabled   = 0;
-  }
-
-  if(!wmode_enabled || !capabilities[0].cap_stick){
-    stick_enabled          = 0;
-    stick_pressure_enabled = 0;
-  }
-  
-  /* fake_forget_tap_interval must be set if the hardware does the gesture. */
-  if(!wmode_enabled)
-    fake_forget_tap_interval = 1;
-
-  /* Save important information */
-  x_per_mm = sensor[0]->x_per_mm;
-  y_per_mm = sensor[0]->y_per_mm;
-  res_x = (int) (x_per_mm * sensor[0]->width_mm);
-  res_y = (int) (y_per_mm * sensor[0]->height_mm);
-
-  /* convert the tap times to packets (80 pkts/sec and 1000 ms/sec) */
-  tap_lower_limit_packet = tap_lower_limit * 80 / 1000;
-  tap_upper_limit_packet = tap_upper_limit * 80 / 1000;
-
-  /* Convert the toss dist to touchpad resolution from mm */
-  min_toss_dist__2 = sqr (min_toss_dist * (x_per_mm + y_per_mm) / 2);
-
-  /* convert the toss times to packets (80 pkts/sec and 1000 ms/sec) */
-  max_toss_packets     = max_toss_time * 80 / 1000;
-  min_toss_packets     = min_toss_time * 80 / 1000;
-  prevent_toss_packets = prevent_toss_time * 80 / 1000;
-
-}
-
-
-/****************************************************************************
-**
-** ROUTINES for interfacing to a SERIAL touchpad
-**
-****************************************************************************/
-
-
-
-
-static unsigned char tp_hextoint (unsigned char byte1,
-				  unsigned char byte2) 
-{
-  unsigned char bytes [3];
-  int result;
-
-  bytes [0] = byte1;
-  bytes [1] = byte2;
-  bytes [2] = '\0';
-  sscanf (bytes, "%x", &result);
-  return result;
-}
-
-static void tp_serial_flush_input (int fd) 
-{
-  struct timeval tv;
-  fd_set rfds;
-  unsigned char junk;
-  
-  FD_ZERO(&rfds);
-  FD_SET (fd, &rfds);
-  tv.tv_sec = 0;
-  tv.tv_usec = 0;
-  usleep (50000);
-
-  while (select (fd+1, &rfds, NULL, NULL, &tv) == 1) {
-#if DEBUG_FLUSH
-    gpm_report (GPM_PR_INFO,"Serial tossing");
-    fflush (stdout);
-#endif
-    read (fd, &junk, 1);
-#if DEBUG_FLUSH
-    gpm_report (GPM_PR_INFO," %c", junk);
-#endif
-    FD_ZERO(&rfds);
-    FD_SET (fd, &rfds);
-    tv.tv_sec = 0;
-    tv.tv_usec = 0;
-  }
-}
-
-static void tp_serial_read (int fd,
-			    unsigned char *bytes,
-			    size_t count) 
-{
-  struct timeval tv;
-  fd_set rfds;
-  int num_read = 0;
-  int read_count;
-
-  FD_ZERO (&rfds);
-  FD_SET (fd, &rfds);
-  tv.tv_sec = 1;
-  tv.tv_usec = 0;
-
-  while ((select (fd+1, &rfds, NULL, NULL, &tv) == 1) &&
-	 (num_read < count)) {
-    read_count = read (fd, &bytes [num_read], count - num_read);
-    num_read += read_count;
-
-    FD_ZERO (&rfds);
-    FD_SET (fd, &rfds);
-  }
-
-  for (; num_read < count; num_read++) {
-     bytes [num_read] = '\0';
-  }
-}
-
-/* Write a string of commands */
-static void tp_serial_send_cmd(int fd,
-			       unsigned char *cmd) 
-{
-  unsigned char junk [15];
-
-  tp_serial_flush_input (fd);
-  write (fd, cmd, strlen (cmd));
-  tp_serial_read (fd, junk, strlen (cmd));
-#if DEBUG_FLUSH
-  junk [strlen (cmd)] = '\0';
-  gpm_report (GPM_PR_DEBUG,"serial tossing: %s", junk);
-#endif
-}
-
-/* write 'mode' to a serial touchpad, STIG 58 */
-static void syn_serial_set_mode (int fd,
-				 unsigned char mode) 
-{
-  unsigned char bytes [15];
-
-  sprintf (bytes, "%%C3B%02X5555", mode);
-#if DEBUG_SENT_DATA
-  gpm_report (GPM_PR_DEBUG,"modes: %s", bytes);
-#endif
-  tp_serial_send_cmd (fd, bytes);
-}
-
-/* read the identification from the serial touchpad, STIG 57*/
-static void syn_serial_read_ident (int fd,
-				   info_type *info) 
-{
-  unsigned char bytes [5];
-
-  tp_serial_send_cmd (fd, "%A");
-  tp_serial_read (fd, bytes, 4);
-
-#if DEBUG_SENT_DATA
-  bytes [4] = '\0';
-  gpm_report (GPM_PR_INFO,"Serial ident: %s", bytes);
-#endif
-
-  if ( bytes [0] == 'S' && bytes [0] == 'T'){
-    /* reformat the data
-     * The out commented is wrong according to STIG page 57.*/
-    /* info->info_model_code = (bytes [2] & 0x07) >> 3; */
-    info->info_model_code = bytes [2] >> 3;
-    info->info_major      = (bytes [2] & 0x07);
-    info->info_minor      = bytes [3];
-  }else{
-    gpm_report (GPM_PR_ERR,"PS/2 serial device doesn't appear to be a synaptics touchpad\n");
-    info->info_model_code = 0;
-    info->info_minor      = 0;
-    info->info_major      = 0;
-  }
-}
-
-
-
-/* read the model_id from the serial touchpad (in ps/2 format) */
-static void syn_serial_read_model_id (int fd,
-				      model_id_type *model) 
-{
-  unsigned char bytes [7];
-  int model_int;
-
-  /* 
-   * for older touchpads this command is not supported and no response will
-   * come.  We should do non blocking input here to handle that case 
-   * and return byte2 as 0x47 ... later.
-   *
-   * pebl: It is easier just to check version number less than 3.2, STIG page 60.
-   */
-  if ( (ident[0].info_major >= 4) ||
-       (ident[0].info_major == 3 && ident[0].info_minor >= 2)){
-    tp_serial_send_cmd (fd, "%D");
-    tp_serial_read (fd, bytes, 6);
-
-    /* reformat the data */
-    model_int = ((tp_hextoint (bytes [0], bytes [1]) << 16) |
-		 (tp_hextoint (bytes [2], bytes [3]) << 8) |
-		 (tp_hextoint (bytes [4], bytes [5])));
-    
-#   if DEBUG_SENT_DATA
-      bytes [6] = '\0';
-      gpm_report (GPM_PR_DEBUG,"Serial model id: %s", bytes);
-#   endif
-
-  }else{
-    model_int = 0;
-  }
-
-  syn_extract_model_id_info (model_int, model);
-}
-
-
-/* read the mode bytes and capabilities from the serial touchpad, STIG 57 */
-static void syn_serial_read_cap (int fd,
-				 ext_cap_type *cap) 
-{
-  unsigned char bytes [8];
-  int cap_int = 0;
-
-  tp_serial_send_cmd (fd, "%B");
-  tp_serial_read (fd, bytes, 8);
-
-#if DEBUG_SENT_DATA
-  bytes [7] = '\0';
-  gpm_report (GPM_PR_DEBUG,"Serial capabilites: %s", bytes);
-#endif
-
-  if (ident[0].info_major >= 4){
-    if (bytes [0] == '3' && bytes [0] == 'B'){
-      cap_int = ((tp_hextoint (bytes [4], bytes [5]) << 8) |
-		 (tp_hextoint (bytes [6], bytes [7])));
-    }else{
-      gpm_report (GPM_PR_ERR,"PS/2 serial device doesn't appear to be a synaptics touchpad\n");
-    }    
-  }
-
-  syn_extract_extended_capabilities(cap_int,cap);
-}
-
-
-
-/*------------------------------------------------------------------------*/
-/*   PS/2 Utility functions.                                              */
-/*      Adapted from tpconfig.c by C. Scott Ananian                       */
-/*------------------------------------------------------------------------*/
-
-/* PS2 Synaptics is using LSB, STIG page 29. 
-**
-** After power on or reset the touchpads are set to these defaults:
-** 100 samples per second
-** Resolution is 4 counts per mm
-** Scaling 1:1
-** Stream mode is selected
-** Data reporting is disabled
-** Absolute mode is disabled
-*/
-
-
-/* Normal ps2 commands, Command set is on STIG page 33  */
-#define PS2_RESET         0xFF      /* Reset */
-#define PS2_RESEND        0xFE      /* Resend command */
-#define PS2_SET_DEFAULT   0xF6      /* Set default */
-#define PS2_DISABLE_DATA  0xF5      /* Stop sending motion data packets */
-#define PS2_ENABLE_DATA   0xF4      /* Start sending motion data packets */
-#define PS2_SAMPLE_RATE   0xF3      /* Set sample rate to value in a following byte */
-#define PS2_READ_DEVICE   0xF2      /* Read device type (ack and idcode) */
-#define PS2_REMOTE_MODE   0xF0      /* Set touchpad in remote mode */
-#define PS2_WRAP_MODE     0xEE      /* Enter wrap mode */
-#define PS2_END_WRAP_MODE 0xEE      /* Leave wrap mode */
-#define PS2_READ_DATA     0xEB      /* Read move data (in remote mode)*/
-#define PS2_STREAM_MODE   0xEA      /* Enter stream mode (device sends move data) */
-#define PS2_STATUS_REQ    0xE9      /* Ask for status request */
-#define PS2_RESOLUTION    0xE8      /* Set resolution to next transmitted byte */
-#define PS2_SCALE_12      0xE7      /* Set scale to 1:2 */
-#define PS2_SCALE_11      0xE6      /* Set scale to 1:1 */
-
-
-/* Normal ps2 responce */
-#define PS2_ERROR         0xFC      /* Error, after a reset,resend or disconnect*/
-#define PS2_ACK           0xFA      /* Command acknowledge */
-#define PS2_READY         0xAA      /* Send after a calibration or ERROR */
-#define PS2_MOUSE_IDCODE  0x00      /* Identification code (meaning mouse) sent after a PS2_READY */
-
-
-/* Additional synaptic commands*/
-#define PS2_SYN_CMD       0xE8      /* Four of these each with an following byte encodes a command*/
-#define PS2_SYN_INERT     0xE6      /* This ps2 command is ignored by synaptics */
-#define PS2_SYN_SET_MODE1 0x0A      /* Set the mode byte 1 instead of sample rate (used after a sample rate cmd) */
-#define PS2_SYN_SET_MODE2 0x14      /* Set the mode byte 2 instead of sample rate (used after a sample rate cmd).
-				     * All other sample rate gives undefined behavior (used to address 4 byte mode)*/
-#define PS2_SYN_SET_STICK 0x28      /* Send byte to stick */
-#define PS2_SYN_STATUS_OK 0x47      /* Special synaptics Status report is recognized */
-
-
-/* These are the commands that can be given (encoded) by PS_SYN_CMD */
-#define PS2_SYN_CMD_IDENTIFY     0x00 /* Identify Touchpad */
-#define PS2_SYN_CMD_MODES        0x01 /* Read Touchpad Modes */
-#define PS2_SYN_CMD_CAPABILITIES 0x02 /* Read capabilities */
-#define PS2_SYN_CMD_MODEL_ID     0x03 /* Read model id */
-#define PS2_SYN_CMD_SERIAL_NO_P  0x06 /* Read serial number prefix */
-#define PS2_SYN_CMD_SERIAL_NO_S  0x07 /* Read serial number suffix */
-#define PS2_SYN_CMD_RESOLUTIONS  0x08 /* Read resolutions */
-
-
-
-
-/* read a byte from the ps/2 port */
-static byte tp_ps2_getbyte(int fd) 
-{
-  byte b;
-
-# ifdef DEBUG_GETBYTE
-  gpm_report(GPM_PR_DEBUG,"Getting byte");
-# endif
-
-  read(fd, &b, 1);
-
-# ifdef DEBUG_GETBYTE
-  gpm_report(GPM_PR_DEBUG,"Got %X",b);
-# endif
-
-  return b;
-}
-
-
-/* write a byte to the ps/2 port, handling resend.*/
-static byte tp_ps2_putbyte(int fd,
-			   byte b) 
-{
-  byte ack;
-
-# ifdef DEBUG_PUTBYTE
-  gpm_report(GPM_PR_DEBUG,"Send real byte %X",b);
-# endif
-
-  write(fd, &b, 1);
-  read(fd, &ack, 1);
-
-  if (ack == PS2_RESEND) {
-    write(fd, &b, 1);
-    read(fd, &ack, 1);
-  }
-
-# ifdef DEBUG_PUTBYTE_ACK
-  gpm_report(GPM_PR_DEBUG,"Responce %X to byte %X",ack,b);
-# endif
-
-  return ack;
-}
-
-
-/* Read a byte from the touchpad or use the Synaptics extended ps/2 syntax to
- * read a byte from the stick device. The variable stick is used to indicate
- * whether it is the touchpad or stick device that is meant.
- */
-static byte syn_ps2_getbyte(int fd, int stick) 
-{
-  byte response[6];
-
-  if (!stick) {
-    response[1]=tp_ps2_getbyte(fd);
-  } else {
-    response[0]=tp_ps2_getbyte(fd);
-    response[1]=tp_ps2_getbyte(fd);
-    response[2]=tp_ps2_getbyte(fd);
-    response[3]=tp_ps2_getbyte(fd);
-    response[4]=tp_ps2_getbyte(fd);
-    response[5]=tp_ps2_getbyte(fd);
-    
-    /* Do some sanity checking */
-    if((response[0] & 0xFC) != 0x84) {
-      gpm_report (GPM_PR_ERR,"Byte 0 of stick device responce is not valid");
-      return -1;
-    }
-    if((response[3] & 0xCC) != 0xC4) {
-      gpm_report (GPM_PR_ERR,"Byte 3 of stick device responce is not valid");
-      return -1;
-    }
-  }
-
-  return response[1];
-}
-
-
-/* write byte to the touchpad or use the Synaptics extended ps/2 syntax to write
- * a byte to the stick device. The variable stick is used to indicate
- * whether it is the touchpad or stick device that is meant.  */
-static void syn_ps2_putbyte(int fd,
-			    int stick,
-			    byte b) 
-{
-  byte ack;
-
-# ifdef DEBUG_PUTBYTE
-  gpm_report(GPM_PR_DEBUG,"Send byte %X to %s",b,(stick?"Stick":"Touchpad"));
-# endif
-
-  if (!stick) {
-    ack = tp_ps2_putbyte(fd,b);
-  } else {
-    syn_ps2_send_cmd(fd, DEVICE_TOUCHPAD, b);
-    ack = tp_ps2_putbyte(fd, PS2_SAMPLE_RATE);
-    if (ack != PS2_ACK)
-      gpm_report (GPM_PR_ERR,"Invalid ACK to stick putbytet sample rate");
-    ack = tp_ps2_putbyte(fd, PS2_SYN_SET_STICK);
-    if (ack != PS2_ACK)
-      gpm_report (GPM_PR_ERR,"Invalid ACK to stick putbytet set stick");
-    ack = syn_ps2_getbyte(fd,DEVICE_STICK);
-  }
-
-  if (ack != PS2_ACK)
-    gpm_report (GPM_PR_ERR,"Invalid ACK to synps2 %s putbyte %02X, got %02X",
-		(stick?"Stick":"Touchpad"),b,ack);
-}
-
-
-/* use the Synaptics extended ps/2 syntax to write a special command byte 
-* STIG page 36: Send exactly four PS2_SYN_CMD (which is otherwise ignored)
-* and after each a byte with the 2 first bits being the command (LSB). End it with
-* either  PS2_SAMPLE_RATE or PS2_STATUS_REQ. It is hinted to send an inert command
-* first so not having five or more PS2_SYN_CMD by coincident.
-*
-* If data is for the stick device every byte has to be encode by the above method.
-*/
-static void syn_ps2_send_cmd(int fd,
-			     int stick, 
-			     byte cmd)
-{
-  int i;
-
-# ifdef DEBUG_CMD
-  gpm_report(GPM_PR_DEBUG,"Send Command %X to %s",cmd,(stick?"Stick":"Touchpad"));
-# endif
-
-  /* initialize with 'inert' command */
-  tp_ps2_putbyte(fd, PS2_SYN_INERT);
-  for (i=0; i<4; i++) {
-    syn_ps2_putbyte(fd, stick, PS2_SYN_CMD);
-    syn_ps2_putbyte(fd, stick, (cmd>>6)&0x3);
-    cmd<<=2;
-  }
-}
-
-#if 0
-
-/* write 'cmd' to mode byte 1.
- * This function is not used. 
- * Code 0x0A is unknown to me, maybe used in older synaptics?
- *
- * This is used for some old 2 byte control synaptics. The function is not
- * used, and is probably leftover from mixing with Van der Plas code.
- */
-static void syn_ps2_set_mode1(int fd,
-			      int stick, 
-			      byte cmd)
-{
-  syn_ps2_send_cmd(fd, stick, cmd);
-  tp_ps2_putbyte(fd, stick, PS2_SAMPLE_RATE);
-  tp_ps2_putbyte(fd, stick, PS2_SYN_SET_MODE1);
-}
-
-#endif
-
-
-/* write 'cmd' to mode byte 2 
- * See ps2_send_cmd. PS2_SR_SET_MODE stores the touchpad mode encoded in the 
- * four PS2_SYN_CMD commands
- */
-static void syn_ps2_set_mode2(int fd,
-			      int stick,
-			      byte cmd)
-{
-  syn_ps2_send_cmd(fd, stick, cmd);
-  syn_ps2_putbyte (fd, stick, PS2_SAMPLE_RATE);
-  syn_ps2_putbyte (fd, stick, PS2_SYN_SET_MODE2);
-}
-
-
-/* read three byte status ('a','b','c') corresponding to register 'cmd' 
-*  Special status request for synaptics is given after a cmd.
-*  Byte b is PS2_SYN_STATUS_OK to recognize a synaptics
-*/
-static void syn_ps2_status_rqst(int fd,
-				int stick,
-				byte cmd,
-				byte *bytes)
-{
-  gpm_report (GPM_PR_INFO,"Status request for %s, %X", (stick?"stick":"touchpad"),cmd);
-
-  syn_ps2_send_cmd(fd, stick, cmd);
-  syn_ps2_putbyte (fd, stick, PS2_STATUS_REQ);
-  bytes [0]=syn_ps2_getbyte(fd,stick);
-  bytes [1]=syn_ps2_getbyte(fd,stick);
-  bytes [2]=syn_ps2_getbyte(fd,stick);
-
-  gpm_report (GPM_PR_INFO,"Status request %X %X %X", bytes[0], bytes[1], bytes[2]);
-}
-
-
-#if 0
-
-/* read the modes from the touchpad (in ps/2 format) */
-static void syn_ps2_read_modes (int fd, int stick) 
-{
-  unsigned char bytes [3];
-
-  syn_ps2_status_rqst (fd, stick, PS2_SYN_CMD_MODES, bytes);
-# ifdef DEBUG
-  gpm_report (GPM_PR_INFO,"Synaptic PS/2 %s modes: %02X", (stick?"stick":"touchpad"),bytes [2]);
-# endif
-}
-
-#endif
-
-
-/* read the identification from the ps2 touchpad */
-static void syn_ps2_read_ident (int fd,
-				int stick, 
-				info_type *info)
-{
-  byte bytes [3];
-
-  syn_ps2_status_rqst (fd, stick, PS2_SYN_CMD_IDENTIFY, bytes);
-  if (bytes [1] != PS2_SYN_STATUS_OK) {
-    gpm_report (GPM_PR_ERR,"PS/2 device doesn't appear to have synaptics %s identification\n",
-		(stick?"sticks":"touchpads"));
-    info->info_minor      = 0;
-    info->info_model_code = 0;
-    info->info_major      = 0;
-
-  } else {
-    info->info_minor      = bytes [0];
-    info->info_model_code = (bytes [2] >> 4) & 0x0f;
-    info->info_major      = bytes [2] & 0x0f;
-  }
-}
-
-
-/* read the model_id from the ps2 touchpad/stick */
-static void syn_ps2_read_model_id (int fd,
-				   int stick, 
-				   model_id_type *model)
-{
-  unsigned char bytes [3];
-  int model_int;
-
-  syn_ps2_status_rqst (fd, stick, PS2_SYN_CMD_MODEL_ID, bytes);
-  model_int = ((bytes [0] << 16) |
-	       (bytes [1] << 8)  |
-	       (bytes [2]));
-  syn_extract_model_id_info (model_int, model);
-}
-
-
-/* read the extended capability from the ps2 touchpad, STIG page 15 */
-static void syn_ps2_read_cap (int fd,
-			      int stick,
-                              ext_cap_type *cap)
-{
-  unsigned char bytes [3];
-  int ext_cap_int;
-
-  syn_ps2_status_rqst (fd, stick, PS2_SYN_CMD_CAPABILITIES, bytes);
-
-  if (bytes [1] != PS2_SYN_STATUS_OK) {
-    gpm_report (GPM_PR_ERR,"PS/2 device doesn't appear to have synaptics %s capabilities\n",
-		(stick?"stick":"touchpad"));
-    ext_cap_int = 0;
-  }else{
-    ext_cap_int = bytes[0] << 8 | bytes[2];
-  }
-
-  syn_extract_extended_capabilities(ext_cap_int, cap);
-}
-
-
-
-/*
- * ps2_disable_data
- *
- * Disable data reporting (streaming), and flush eventual old packets. As the
- * kernel keeps a queue of received data from the touchpad, the next byte we
- * read could be old data and not the ack to our command or request.  Disable
- * data should always be called before sending commands or request to the
- * touchpad.
- *
- * Note that this is a general ps2 command which should not be in this file,
- * but in mice.c.
- */
-static void tp_ps2_disable_data (int fd) 
-{
-  struct timeval tv;
-  fd_set rfds;
-  unsigned char status;
-  byte cmd = PS2_DISABLE_DATA;
-
-  
-  FD_ZERO(&rfds);
-  FD_SET (fd, &rfds);
-  tv.tv_sec = 0;
-  tv.tv_usec = 0;
-
-  write(fd,&cmd,1);
-
-  usleep (50000);
-  
-  while (select (fd+1, &rfds, NULL, NULL, &tv) == 1) {
-    read (fd, &status, 1);
-#if DEBUG_RESET
-    gpm_report (GPM_PR_INFO,"PS/2 device disable data flush: %02X", status);
-#endif
-    FD_ZERO(&rfds);
-    FD_SET (fd, &rfds);
-    tv.tv_sec = 0;
-    tv.tv_usec = 0;
-  }
-
-  if (status != PS2_ACK)
-    gpm_report (GPM_PR_ERR,"Invalid ACK to disable stream command, got %02X",status);
-}
-
-
-/* 
- * syn_ps2_enable_data
- *
- * Enable data after a disable data command. Should have called the disable data
- * before calling this function.
- */
-
-static void syn_ps2_enable_data(int fd)
-{  
-  if (stick_enabled)
-    syn_ps2_putbyte(fd,DEVICE_STICK,PS2_ENABLE_DATA);
-  syn_ps2_putbyte(fd,DEVICE_TOUCHPAD,PS2_ENABLE_DATA);
-}
-
-
-/* 
- * syn_ps2_send_reset
- *
- * Send reset command and absorb additional READY, IDCODE from the
- * touchpad. Should have called the disable data before calling this function.
- * Synaptics garanties always to return PS2_READY. STIG page 31 and 48.
- */
-
-static void syn_ps2_send_reset(int fd, int stick)
-{
-  byte status,id_code = PS2_MOUSE_IDCODE;
-  byte reset_cmd = PS2_RESET;
-
-  gpm_report(GPM_PR_DEBUG,"Reseting Synaptic PS/2 %s\n",(stick?"Stick":"Touchpad"));
-
-  /* Send reset command without eating the ack. */
-  if(!stick) {
-    write(fd,&reset_cmd,1);
-    status = tp_ps2_getbyte(fd);
-  } else {
-    syn_ps2_putbyte(fd, stick, reset_cmd);
-    status = PS2_ACK;
-  }
-
-  /* Sometimes the touchpad sends additional ready,idcode before ack the reset command.
-   * I dont know why! */
-  while (status == PS2_READY){
-    gpm_report(GPM_PR_INFO,"PS/2 device sending additional READY, ID CODE.\n");
-    id_code = syn_ps2_getbyte(fd,stick);
-    status  = syn_ps2_getbyte(fd,stick);
-  }
-
-  if (status != PS2_ACK || id_code != PS2_MOUSE_IDCODE){
-    gpm_report(GPM_PR_ERR,"Sending reset command to PS/2 Device failed: No ACK, got %02X.\n",status);
-  }
-
-  /* Wait 750 ms to recalibrate. */
-  usleep(750000);
-
-  if ( (status  = syn_ps2_getbyte(fd,stick)) != PS2_READY ){
-    gpm_report(GPM_PR_ERR,"Reseting PS/2 Device failed: No READY, got %02X.\n"
-	                  "Check pc_keyb.c for reconnect smartness.\n",status);
-  }
-  if ( (id_code = syn_ps2_getbyte(fd,stick)) != PS2_MOUSE_IDCODE){
-    gpm_report(GPM_PR_ERR,"Reseting PS/2 Device failed: Wrong ID, got %02X.\n",id_code);
-  }
-
-}
-
-
-/*
-** syn_ps2_absolute_mode
-**
-** Put the touchpad into absolute mode.
-*/
-
-static void syn_ps2_absolute_mode(int fd)
-{
-
-  /* select 6 byte packet, high packet rate, no-sleep */
-  syn_ps2_set_mode2 (fd, DEVICE_TOUCHPAD, 
-		     (ABSOLUTE_MODE    |
-		      HIGH_REPORT_RATE |
-		      PS2_NO_SLEEP     |
-		      (wmode_enabled ? NO_TAPDRAG_GESTURE : TAPDRAG_GESTURE) |
-		      (stick_enabled ? STICK_ENABLED : STICK_DISABLE)        |
-		      (wmode_enabled ? REPORT_W_ON : REPORT_W_OFF)));
-
-}
-
-
-
-/****************************************************************************
-**
-**  TRANSLATE FUNCTIONS the incoming data to an uniform report
-**
-****************************************************************************/
-
-/* SERIAL PACKETS
- * STIG page 63, note 7 bit!
- *
- * byte 0 |    1   | reserved | gesture  | finger |  left   |  middle | right|  
- * byte 1 |    0   |                     x-pos 7-12                          |
- * byte 2 |    0   |                     x-pos 1-6                           |
- * byte 3 |    0   |                     y-pos 7-12                          |
- * byte 4 |    0   |                     y-pos 1-6                           |
- * byte 5 |    0   |                  z pressure 7-2                         |
- * byte 6 |    0   |  down    |   up     |y-pos 0 | x-pos 0 | z pressure 0-1 |  (new_abs set)
- * byte 7 |    0   |      reserved       |       W mode 0-3                  |  (new_abs and wmode set)
- */
-
-
-static void syn_serial_translate_data (unsigned char *data,
-					 report_type *report) 
-{
-  report->gesture     = check_bits (data [0], 0x10);
-  report->fingers     = check_bits (data [0], 0x08);
-  report->left        = check_bits (data [0], 0x04);
-  report->middle      = check_bits (data [0], 0x02);
-  report->right       = check_bits (data [0], 0x01);
-  report->x           = (data [1] << 7) | (data [2] << 1);
-  report->y           = (data [3] << 7) | (data [4] << 1);
-  report->pressure    = data [5] << 2;
-  report->fourth      = 0;
-  report->up          = 0;
-  report->down        = 0;
-  report->w           = 0;
-  report->fingerwidth = 0;
-
-  if (model[0].info_new_abs){
-    report->up        = check_bits (data [6], 0x20);
-    report->down      = check_bits (data [6], 0x40);
-    report->y        |= (data [6] & 0x08) >> 3;
-    report->x        |= (data [6] & 0x04) >> 2;
-    report->pressure |= (data [6] & 0x03);
-
-    if (wmode_enabled){
-      report->w         = (data [7] & 0x0F);
-    }
-  }
-}
-
-
-/* PS2 PACKETS 
- *
- * Handle error packets. It may be garbage or not, as the synaptics pad keeps sending data 1
- * sec after last touch.
- */
-
-static void syn_ps2_translate_error(unsigned char *data,
-				    report_type *report)
-{
-  gpm_report(GPM_PR_WARN,"Unrecognized Synaptic PS/2 Touchpad packet: %02X %02X %02X %02X %02X %02X",
-	     data [0],data [1],data [2],data [3],data [4],data [5]);
-
-  if (reset_on_error_enabled) {
-    syn_ps2_reset(mouse_fd);
-    syn_ps2_absolute_mode(mouse_fd);
-  }
-  
-  report->left        = 0;
-  report->middle      = 0;
-  report->right       = 0;
-  report->fourth      = 0;
-  report->up          = 0;
-  report->down        = 0;
-  report->x           = 0;
-  report->y           = 0;
-  report->pressure    = 0;
-  report->gesture     = 0;
-  report->fingers     = 0;
-  report->fingerwidth = 0;
-  report->w           = 0;
-  
-}
-
-
-/*
- * STIG page 42
- * wmode = 0, newer version. Gesture, right and left are repeated.
- *
- * byte 0 |     1   |    0   |  Finger  | Reserved |    0   | Gesture |  Right  | Left |  
- * byte 1 |         y-pos 11-8                     |         x-pos  11-8               |
- * byte 2 |                           z pressure 0-7                                   |
- * byte 3 |     1   |    1   | y-pos 12 | x-pos 12 |    0   | Gesture |  Right  | Left |
- * byte 4 |                                 x - pos 0-7                                |
- * byte 5 |                                 y - pos 0-7                                |
- *
- * STIG page 43
- * wmode = 0, old version <  3.2.
- * Second is a second gesture!?
- *
- * byte 0 |     1   |    1   |  z-pres 6-7         | Second | Gesture |  Right  | Left |  
- * byte 1 |  finger |    0   |     0    |                    x-pos  12-8               |
- * byte 2 |                           x-pos  0-7                                       |
- * byte 3 |     1   |    0   |               z-pressure 0-5                            |
- * byte 4 |Reserved |    0   |    0     |              y - pos 8-12                    |
- * byte 5 |                                 y - pos 0-7                                |
- * 
- */
-
-/* Translate the reported data into a record for processing */
-static void syn_ps2_translate_data (unsigned char *data,
-				    report_type *report) 
-{
-  
-  /* Check that this is indeed an absolute 6 byte new version packet*/
-  if (((data [0] & 0xc8) == 0x80) &&              /* Check static in byte 0 */
-      ((data [3] & 0xc8) == 0xc0) &&              /* Check static in byte 3 */
-      ((data [0] & 0x0F) == (data [3] & 0x0F))) { /* check repeated data */
-    report->left        = check_bits (data [0], 0x01);
-    report->middle      = 0;
-    report->right       = check_bits (data [0], 0x02);
-    report->fourth      = 0;
-    report->up          = 0;
-    report->down        = 0;
-    report->x           = (((data [1] & 0x0F) << 8) |
-			   ((data [3] & 0x10) << 8) |
-			   ((data [4])));
-    report->y           = (((data [1] & 0xF0) << 4) |
-			   ((data [3] & 0x20) << 7) |
-			   ((data [5])));
-    report->pressure    = data [2];
-    report->gesture     = check_bits (data [0], 0x04);
-    report->fingers     = check_bits (data [0], 0x20);
-    report->fingerwidth = 0;
-    report->w           = 0;
-    
-  } /*th Old style packet maybe */
-  else if (((data [0] & 0xC0) == 0xC0) && /* Static in byte 0*/
-	   ((data [1] & 0x60) == 0x00) && /* Static in byte 1*/
-	   ((data [3] & 0xC0) == 0x80) && /* Static in byte 3*/
-	   ((data [4] & 0x60) == 0x00)) { /* Static in byte 4*/
-    report->left        = check_bits (data [0], 0x01);
-    report->middle      = 0;
-    report->right       = check_bits (data [0], 0x02);
-    report->fourth      = 0;
-    report->up          = 0;
-    report->down        = 0;
-    report->x           = (((data [1] & 0x1F) << 8) |
-			   ((data [2])));
-    report->y           = (((data [4] & 0x1f) << 8) |
-			   ((data [5])));
-    report->pressure    = (((data [0] & 0x30) << 2 ) |
-			   ((data [3] & 0x3f)));
-    report->gesture     = check_bits (data [0], 0x04);
-    report->fingers     = check_bits (data [1], 0x80);
-    report->fingerwidth = 0;
-    report->w           = 0;
-    
-  } else { 
-    syn_ps2_translate_error(data,report);
-  }
-}
-
-
-/* STIG page 42
- * wmode = 1, 
- *
- * byte 0 |     1   |    0   |  W 2-3              |    0   | W 1     |  Right  | Left |  
- * byte 1 |         y-pos 11-8                     |         x-pos  11-8               |
- * byte 2 |                           z pressure 0-7                                   |
- * byte 3 |     1   |    1   | y-pos 12 | x-pos 12 |    0   | W 0     |  R/D    | L/U  |
- * byte 4 |                                 x - pos 0-7                                |
- * byte 5 |                                 y - pos 0-7                                |
- *
- */
-
-static void syn_ps2_translate_wmode_data (unsigned char *data,
-					    report_type *report) 
-{
-  /* Check that it is an absolute packet */
-  if (((data[0] & 0xc8) == 0x80) && ((data[3] & 0xc8) == 0xc0)) {
-
-    report->left        = check_bits (data[0], 0x01);
-    report->middle      = check_bits (data[0] ^ data[3], 0x01);
-    report->right       = check_bits (data[0], 0x02);
-    report->fourth      = check_bits (data[0] ^ data[3], 0x02);
-    report->up          = 0;
-    report->down        = 0;
-    report->x           = (((data[1] & 0x0F) << 8) |
-			   ((data[3] & 0x10) << 8) |
-			   ((data[4])));
-    report->y           = (((data[1] & 0xF0) << 4) |
-			   ((data[3] & 0x20) << 7) |
-			   ((data[5])));
-    report->pressure    = data[2];
-    report->fingers     = 0;
-    report->fingerwidth = 0;
-    report->gesture     = 0;
-    report->w = (((data[3] & 0x04) >> 2) |
-		 ((data[0] & 0x04) >> 1) |
-		 ((data[0] & 0x30) >> 2));
-
-
-  } else { 
-    syn_ps2_translate_error(data,report);
-  }
-}
-
-
-/****************************************************************************
-**
-** INTERFACE ROUTINES
-**
-****************************************************************************/
-
-/*
-** syn_process_serial_data
-**
-** Process the touchpad 6 byte report.
-*/
-void syn_process_serial_data (int fd, Gpm_Event *state,
-			      unsigned char *data) 
-{
-  /* initialize the state */
-  state->buttons = 0;
-  state->dx      = 0;
-  state->dy      = 0;
-
-  mouse_fd = fd; /* cheat */
-  
-  syn_serial_translate_data (data, &cur_report);
-  if (wmode_enabled){
-    syn_process_wmode_report(&cur_report);
-  }    
-  if (tp_find_fingers(&cur_report,state)) return;
-  if (wmode_enabled){
-    tp_find_gestures(&cur_report);    
-  }    
-
-  tp_process_report (state, &cur_report);
-}
-
-
-/*
-** syn_serial_reset
-**
-** Reset the touchpad to relative mode.  This cannot be called directly as a
-** command should be sent in 1200 baud, not 9600.
-*/
-
-void syn_serial_reset(int fd)
-{
-  gpm_report (GPM_PR_INFO,"Reseting Synaptic Serial Touchpad.");
-
-  syn_serial_set_mode (fd, (RELATIVE_MODE    |
-			    HIGH_REPORT_RATE |
-			    USE_9600_BAUD    |
-			    NORMAL_REPORT    |
-			    REPORT_W_OFF));
-
-}
-
-/*
-** syn_serial_init
-** 
-** Initialize the synaptics touchpad.  Read model and identification.
-** Determine the size of the touchpad in "pixels".  Select 6/7/8 byte packets,
-** select 9600 baud, and select high packet rate.
-*/
-int syn_serial_init (int fd) 
-{
-  int return_packetlength;
-
-  gpm_report(GPM_PR_DEBUG,"Initializing Synaptics Serial TouchPad");
-
-  syn_serial_read_ident (fd, &ident[0]);
-  syn_serial_read_model_id (fd, &model[0]);
-  syn_serial_read_cap(fd, &capabilities[0]);
-
-  syn_process_config (ident[0], model[0]);
-
-  syn_dump_info(0);
-
-  /* Change the protocol to use either 6,7 or 8 bytes, STIG 63 */
-  if (model[0].info_new_abs){
-    if (wmode_enabled){
-      return_packetlength = 8;
-    }else{
-      return_packetlength = 7;
-    }
-  }else{
-    return_packetlength = 6;
-    wmode_enabled = 0;
-  }
-
-  syn_serial_set_mode (fd, (ABSOLUTE_MODE    |
-			    HIGH_REPORT_RATE |
-			    USE_9600_BAUD    |
-			    (model[0].info_new_abs ? EXTENDED_REPORT : NORMAL_REPORT) |
-			    (wmode_enabled ? REPORT_W_ON : REPORT_W_OFF)));
-
-  return return_packetlength;
-}
-
-
-/*
-** syn_process_ps2_data
-**
-** Process the touchpad 6 byte report.
-*/
-void syn_process_ps2_data (int fd, Gpm_Event *state,
-			   unsigned char *data) 
-{
-  /*   gpm_report(GPM_PR_DEBUG,"Data %02x %02x %02x %02x %02x %02x",data[0],data[1],data[2],data[3],data[4],data[5]); */
-
-  /* initialize the state */
-  state->buttons = 0;
-  state->dx      = 0;
-  state->dy      = 0;
-
-  mouse_fd = fd; /* cheat */
-
-  if (wmode_enabled) {
-    syn_ps2_translate_wmode_data (data, &cur_report);
-    if (syn_ps2_process_extended_packets(data,&cur_report,state)) return;      
-    syn_process_wmode_report(&cur_report);
-    if (tp_find_fingers(&cur_report,state)) return;
-    tp_find_gestures(&cur_report);
-  }else {
-    syn_ps2_translate_data (data, &cur_report);
-    if (tp_find_fingers(&cur_report,state)) return;
-  }
-
-  tp_process_report (state, &cur_report);
-}
-
-
-/*
-** syn_ps2_reset
-**
-** Reset the touchpad and set to relative mode (ps/2).
-*/
-
-void syn_ps2_reset (int fd)
-{
-  gpm_report (GPM_PR_INFO,"Reseting Synaptic PS/2 Touchpad.");
-
-  /* Stop incoming motion data (of whatever kind absolute/relative). */
-  tp_ps2_disable_data(fd);
-
-  if(stick_enabled)
-    syn_ps2_send_reset(fd,DEVICE_STICK);
-  syn_ps2_send_reset(fd,DEVICE_TOUCHPAD);
-
-  syn_ps2_enable_data(fd);
-}
-
-
-/*
- * syn_ps2_init_stick
- *
- * Initialize the attached device on the synaptics touchpad (usually a stick).
- */
-
-static void syn_ps2_init_stick(int fd)
-{
-  
-  if (!stick_enabled) return;
-
-  gpm_report(GPM_PR_DEBUG,"Initializing Synaptics PS/2 Stick Device");
-
-  /* Reset it, set defaults, streaming */
-  syn_ps2_send_reset(fd,DEVICE_STICK);
-  syn_ps2_putbyte(fd,DEVICE_STICK,PS2_SET_DEFAULT);
-  syn_ps2_putbyte(fd,DEVICE_STICK,PS2_STREAM_MODE);
-
-  /* Unused */
-  /*   syn_ps2_read_ident    (fd, DEVICE_STICK, &ident[1]); */
-  /*   syn_ps2_read_model_id (fd, DEVICE_STICK, &model[1]); */
-  /*   syn_ps2_read_cap      (fd, DEVICE_STICK, &capabilities[1]); */
-
-  /*   syn_dump_info(DEVICE_STICK); */
-}
-
-
-
-/*
-** syn_ps2_init
-** 
-** Initialize the synaptics touchpad.  Read model and identification.
-** Determine the size of the touchpad in "pixels".  Select 6 byte packets,
-** and select high packet rate.
-*/
-void syn_ps2_init (int fd) 
-{
-
-  gpm_report(GPM_PR_DEBUG,"Initializing Synaptics PS/2 TouchPad");
-
-  tp_ps2_disable_data(fd);
-
-  /* Init touchpad */
-  syn_ps2_send_reset(fd,DEVICE_TOUCHPAD);
-
-  syn_ps2_read_ident    (fd, DEVICE_TOUCHPAD, &ident[0]);
-  syn_ps2_read_model_id (fd, DEVICE_TOUCHPAD, &model[0]);
-  syn_ps2_read_cap      (fd, DEVICE_TOUCHPAD, &capabilities[0]);
-
-  syn_process_config (ident[0], model[0]);
-  syn_dump_info(DEVICE_TOUCHPAD);
-
-  syn_ps2_absolute_mode(fd);
-
-  /* Absolut mode must be set before Init Stick device*/
-  syn_ps2_init_stick(fd);
-
-  /* Enable absolut mode and streaming */
-  syn_ps2_enable_data(fd);
-}
diff -urN gpm-orig/src/twiddler.c gpm/src/twiddler.c
--- gpm-orig/src/twiddler.c	2003-10-21 15:38:38.000000000 -0500
+++ gpm/src/twiddler.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,527 +0,0 @@
-/*
- * twiddler.c - support for the twiddler keyboard
- *
- * Copyright 1998   rubini@linux.it (Alessandro Rubini)
- * Changed 04/23/2001 nico@schottelius.org (Nico Schottelius)
- *  --> removed hard wired dev names. Instead used symbolic constants and
- *     generated option.consolename
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- ********/
-
-/* TODO:
-     resolution change (mice.c)
-     switch up/down (mice.c)
-     manage X....
-     modifiers
- */
-
-/* Done:
-      two cfg files
-      mouse buttons
-      unblank
-      special keys...
-      meta keys
-      auto-repeat: double press plus hold...
-      README
-*/
-      
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <linux/vt.h>
-
-#include "headers/gpm.h"
-#include "headers/gpmInt.h"
-#include "headers/message.h"
-#include "headers/console.h"
-#include "headers/twiddler.h"
-
-
-/* 
- * Each table is made up of 256 entries, as these are the possible chords
- * Then, there is one table for each modifier (two of them are not allowed).
- * Each entry is a pointer: a "low" pointer represents a single byte, true
- * pointers represent strings. This is not very clean, but it works well.
- */
-
-char *twiddler_table[7][256];
-
-/* This maps modifiers to tables */
-struct twiddler_map_struct {
-   unsigned long modifiers;
-   char *keyword;
-   char **table;
-} twiddler_map[] = {
-   { TW_MOD_0, "",   twiddler_table[0]},
-   { TW_MOD_S, "Shift", twiddler_table[1]},
-   { TW_MOD_N, "Numeric",  twiddler_table[2]},
-   { TW_MOD_F, "Function", twiddler_table[3]},
-   { TW_MOD_C, "Control",  twiddler_table[4]},
-   { TW_MOD_C, "Ctrl",    twiddler_table[4]},
-   { TW_MOD_A, "Alt",     twiddler_table[5]}, 
-   { TW_MOD_A, "Meta",    twiddler_table[5]}, 
-/* This is different!! */
-   { TW_MOD_C | TW_MOD_S, "Ctrl+Shift",    twiddler_table[6]}, 
-   { TW_MOD_C | TW_MOD_S, "Shift+Ctrl",    twiddler_table[6]}, 
-   { 0,       NULL,      NULL}
-};
-
-/* Convert special keynames to strings */
-struct twiddler_f_struct {
-   char *instring;
-   char *outstring;
-} twiddler_f[] = {
-   {"F1",    "\033[[A" },
-   {"F2",    "\033[[B" },
-   {"F3",    "\033[[C" },
-   {"F4",    "\033[[D" },
-   {"F5",    "\033[[E" },
-   {"F6",    "\033[17~" },
-   {"F7",    "\033[18~" },
-   {"F8",    "\033[19~" },
-   {"F9",    "\033[20~" },
-   {"F10",   "\033[21~" },
-   {"F11",   "\033[23~" },
-   {"F12",   "\033[24~" },
-   {"F13",   "\033[25~" },
-   {"F14",   "\033[26~" },
-   {"F15",   "\033[28~" },
-   {"F16",   "\033[29~" },
-   {"F17",   "\033[31~" },
-   {"F18",   "\033[32~" },
-   {"F19",   "\033[33~" },
-   {"F20",   "\033[34~" },
-   {"Find",   "\033[1~" },
-   {"Insert", "\033[2~" },
-   {"Remove", "\033[3~" },
-   {"Select", "\033[4~" },
-   {"Prior",  "\033[5~" },
-   {"Next",   "\033[6~" },
-   {"Macro",  "\033[M" },
-   {"Pause",  "\033[P" },
-
-   {"Up",    "\033[A" },
-   {"Down",   "\033[B" },
-   {"Left",   "\033[D" },
-   {"Right",  "\033[C" },
-       
-   {NULL, NULL }
-};
-
-/* Convert special keynames to functions */
-struct twiddler_fun_struct {
-   char *name;
-   int (*fun)(char *string);
-};
-
-/*===================================================================*/
-/*              This part deals with pushing keys                  */
-
-/* Function support:
-     if a chord maps to a function, we need two pointers: one to the
-     function and one to its argument. Therefore we must keep an array
-     that keeps both pointers, and the pointer in the table is just
-     an handle to this pair of pointers. The table has a maximum len
-*/
-
-#define TWIDDLER_MAX_ACTIVE_FUNS 128
-
-/* These are the special functions that perform special actions */
-int twiddler_console(char *s)
-{
-   int consolenr = atoi(s); /* atoi never fails :) */
-   int fd;
-   if (consolenr == 0) return 0; /* nothing to do */
-
-   fd=open_console(O_RDONLY);
-   if (fd < 0) return -1;
-   if (ioctl(fd, VT_ACTIVATE, consolenr)<0) {close(fd); return -1;}
-/*if (ioctl(fd, VT_WAITACTIVE, consolenr)<0) {close(fd); return -1;} */
-   close(fd);
-   return 0;
-}
-
-int twiddler_exec(char *s)
-{
-   int pid;
-   
-   switch(pid=fork()) {
-      case -1: return -1;
-      case 0:
-         close(0);
-         close(1);
-         close(2); /* very rude! */
-      
-         open(GPM_NULL_DEV,O_RDONLY);
-         open(console.device, O_WRONLY);
-         dup(1);
-         execl("/bin/sh", "sh", "-c", s, NULL);
-         exit(1); /* shouldn't happen */
-
-   default: /* father: */
-         return(0);
-   }
-}
-
-/* The functions and their name */
-struct twiddler_fun_struct twiddler_functions[] = {
-   { "Console",  twiddler_console },
-   { "Exec",    twiddler_exec },
-   { NULL, NULL}
-};
-
-/* The registered functions */
-struct twiddler_active_fun {
-   int (*fun)(char *s);
-   char *arg;
-   } twiddler_active_funs[TWIDDLER_MAX_ACTIVE_FUNS];
-static int active_fun_nr = 0;
-
-
-int twiddler_do_fun(int i)
-{
-   twiddler_active_funs[i].fun(twiddler_active_funs[i].arg);
-   return 0;
-}
-
-/*
- * Ok, from now on it's normal handling
- */
-
-/* This returns the table to use */
-static inline char **twiddler_get_table(unsigned long message)
-{
-   unsigned long mod = message & TW_ANY_MOD;
-   struct twiddler_map_struct *ptr;
-
-   for (ptr = twiddler_map; ptr->table; ptr++)
-      if (ptr->modifiers == mod) return ptr->table;
-   return NULL;
-}
-
-/* And this uses the item to push keys */
-static inline int twiddler_use_item(char *item)
-{
-   int fd = open_console(O_WRONLY);
-   int i, retval = 0;
-   unsigned char pushthis, unblank=4; /* 4 == TIOCLINUX unblank */
-
- /* a special function */ 
-   /* a single byte */
-   if (((unsigned long)item & 0xff) == (unsigned long)item) {
-      pushthis = (unsigned long)item & 0xff;
-      retval = ioctl(fd,TIOCSTI,&pushthis);
-   } else if(i = (struct twiddler_active_fun *)item - twiddler_active_funs,
-                  i>=0 && i < active_fun_nr)
-      twiddler_do_fun(i);
-   else /* a string */
-      for (; *item!='\0' && retval==0; item++) retval = ioctl(fd,TIOCSTI,item);
-
-   ioctl(fd,TIOCLINUX,&unblank);
-   if (retval)
-   gpm_report(GPM_PR_ERR,GPM_MESS_IOCTL_TIOCSTI, option.progname, strerror(errno));
-   close(fd);
-   return retval;
-}
-
-/* return value is one if auto-repeating, 0 if not */
-int twiddler_key(unsigned long message)
-{
-   char **table = twiddler_get_table(message);
-   char *val;
-  /*
-   * These two are needed to avoid transmitting single keys when typing
-   * chords. When the number of keys being held down decreases, data
-   * is transmitted; but as soon as it increases the cycle is restarted.
-   */
-   static int last_message;
-   static int marked;
-  /*
-   * The time values are needed to implement repetition of keys
-   */
-   static struct timeval tv1, tv2;
-   static int nclick, last_pressed;
-
-   if (!table) return 0;
-   message &= 0xff;
-   val = table[message];
-
-   if ((message < last_message) && !marked) { /* ok, do it */
-      marked++; /* don't retransmit on release */
-      twiddler_use_item(table[last_message]);
-      if (last_pressed != last_message) {
-         nclick=1; GET_TIME(tv1);
-      } /* first click (note: this is release) */
-      last_pressed = last_message;
-   }
-   if (message < last_message) { /* marked: just ignore */
-      last_message = message;
-      return 0;
-   }
-
-  /* building up a chord or repeating */
-
-   if (message != last_pressed) { /* building up */
-      marked=0;
-      last_message = message;
-      return 0;
-   }
-
-  /*  Hmmm... double click */
-   if (message > last_message) {
-      marked = 0; /* but don't use it */
-      GET_TIME(tv2);
-      nclick = 1+ (DIF_TIME(tv1,tv2) < 300); /* if fast, counts as double */
-      last_message = message;
-      if (nclick==1) GET_TIME(tv1); /* maybe the next.. */
-      return 1;
-   }
-
-  /* so, we are repeating... */
-   if (nclick == 2) {
-      GET_TIME(tv1); /* compute delay */
-      if (DIF_TIME(tv2,tv1) > 500) /* held enough */
-         twiddler_use_item(table[message]);
-      return 1;
-   }
-   return 0;
-}
-
-/*===================================================================*/
-/*          This part deals with reading the cfg file(s)           */
-
-/* retrieve the right table according to the modifier string */
-char **twiddler_mod_to_table(char *mod)
-{
-   struct twiddler_map_struct *ptr;
-   int len = strlen(mod);
-   if (len == 0) return twiddler_map->table;
-
-   for (ptr = twiddler_map; ptr->table; ptr = ptr++) {
-      if (!strncasecmp(mod,ptr->keyword,len))
-      return ptr->table;
-   }
-   return NULL;
-}
-
-/* Convert the "M00L"-type string to an integer */
-int twiddler_chord_to_int(char *chord)
-{
-   char *convert = "0LMR"; /* 0123 */
-   char *tmp;
-   int result = 0;
-   int shift = 0;
-
-   if (strlen(chord)!=4) return -1;
-
-   while (*chord) {
-      if (!(tmp = strchr(convert, *chord))) return -1;
-      result |= (tmp-convert)<<shift;
-      chord++;
-      shift += 2;
-   }
-   return result;
-}
-
-/* Convert an escape sequence to a single byte */
-int twiddler_escape_sequence(char *s, int *len)
-{
-   int res = 0;
-   *len=0;
-   if (isdigit(*s)) { /* octal */
-      while (isdigit(*s)) {
-         res *= 8;
-         res += *s-'0';
-         s++;
-         (*len)++;
-         if (*len == 3) return res;
-      }
-      return res;
-   }
-
-   *len=1;
-   switch(*s) {
-      case 'n': return '\n';
-      case 'r': return '\r';
-      case 'e': return '\e';
-      case 't': return '\t';
-      case 'a': return '\a';
-      case 'b': return '\b';
-      default: return *s;
-
-      /* a case statement after default: ???? */
-      case 'x': /* hex */
-         (*len)++; s++;
-         if (isdigit(*s)) res = *s-'0';
-         else res          = tolower(*s)-'a'+10;
-         s++;
-         if (isxdigit(*s)) {
-            (*len)++;
-            res *= 16;
-            if (isdigit(*s)) res += *s-'0';
-            else res          += tolower(*s)-'a'+10;
-         }
-         return res;
-   }
-} 
-
-/*
- * Convert the rest to a string or a byte
- * the special return value "s" signals an error
- */
-char *twiddler_rest_to_value(char *s)
-{
-   char *ptr;
-   static char buf[64];
-   int ibuf = 0, len;
-   struct twiddler_f_struct *sptr;
-   struct twiddler_fun_struct *fptr;
-
-   /* look for the value */
-   ptr = strchr(s,'=');
-   if (!ptr) return s;
-   ptr++;
-   while (isspace(*ptr)) ptr++;
-   if (!*ptr) return s;
-
-   /*
-    * now see what the rest is: accept a single char,
-    * standalone escape sequences or strings (with escape seq.)
-    * Whenever the string is not quoted, try to interpret it
-    */
-   if (*ptr == '"') { /* string... */
-      ptr++;
-      while (*ptr != '"') {
-         if (*ptr == '\\') {
-            ptr++;
-            buf[ibuf++] = twiddler_escape_sequence(ptr, &len);
-            ptr += len;
-         }
-         else
-            buf[ibuf++]=*(ptr++);
-      }
-      buf[ibuf]='\0';
-      return strdup(buf);
-   }
-   if (*ptr == '\\')
-      return (char *)twiddler_escape_sequence(ptr+1, &len /* unused */);
-
-   if (strlen(ptr)==1) return ((char *)((unsigned long)*ptr & 0xFF));
-
-  /* look for special string */
-   for (sptr = twiddler_f; sptr->instring; sptr++)
-      if (!strcmp(ptr,sptr->instring)) return sptr->outstring;
-
-   /* finally, look for special functions */
-   for (fptr = twiddler_functions; fptr->name; fptr++)
-      if (!strncasecmp(fptr->name,ptr,strlen(fptr->name))) {
-         if (active_fun_nr == TWIDDLER_MAX_ACTIVE_FUNS) {
-            gpm_report(GPM_PR_ERR,GPM_MESS_TOO_MANY_SPECIAL, option.progname,
-                            TWIDDLER_MAX_ACTIVE_FUNS);
-            return s;
-         }
-         twiddler_active_funs[active_fun_nr].fun = fptr->fun;
-         twiddler_active_funs[active_fun_nr].arg=strdup(ptr+strlen(fptr->name));
-         return (char *)(twiddler_active_funs + active_fun_nr++);
-      }
-
-   return s; /* error */
-}
-
-int twiddler_key_init(void)
-{
-   FILE *f;
-   char *files[]={TW_SYSTEM_FILE, TW_CUSTOM_FILE, NULL};
-   int fileindex=0;
-   char s[128], buf[64]; /* buf is for the string */
-   char mod[64], chord[64], *value;
-   int index, lineno=0, errcount=0;
-   char **table;
-   static int initcount=0;
-
-   if (initcount) return 0; /* do it only once */
-   initcount++;
-
-   if (!(f = fopen(TW_SYSTEM_FILE,"r"))) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,TW_SYSTEM_FILE,strerror(errno));
-      return -1;
-   }
-
-  /* ok, go on reading all the files in files[]*/
-  while (files[fileindex]) {
-      while (fgets(s,128,f)) {
-         lineno++;
-
-         /* trim newline and blanks, if any */
-         if (s[strlen(s)-1]=='\n') s[strlen(s)-1] = '\0';
-         while (isspace(s[strlen(s)-1])) s[strlen(s)-1] = '\0';
-
-         if (s[0]=='\0' || s[0]=='#') continue; /* ignore comment or empty */
-
-         if (sscanf(s,"%s = %s",chord,buf)==2) /* M00L = anything */
-            mod[0]='\0'; /* no modifiers */
-         else if (sscanf(s, "%s %s = %s", mod, chord, buf)==3) /*Mod M00L =k */;
-         else if (sscanf(s, "%s", buf)!= 0) {
-            gpm_report(GPM_PR_ERR,GPM_MESS_SYNTAX_1,option.progname,TW_SYSTEM_FILE
-                                                   ,lineno);
-	         errcount++;
-	         continue;
-	      }
-
-         /* Ok, here we are: now check the parts */
-         if (!(table = twiddler_mod_to_table(mod))) {
-            gpm_report(GPM_PR_ERR,GPM_MESS_UNKNOWN_MOD_1,option.progname,TW_SYSTEM_FILE
-                                                        ,lineno, mod);
-	         errcount++;
-	         continue;
-	      }
-         if ((index = twiddler_chord_to_int(chord)) <= 0) {
-            gpm_report(GPM_PR_ERR,GPM_MESS_INCORRECT_COORDS,option.progname,
-                                      TW_SYSTEM_FILE,lineno, chord);
-	         errcount++;
-	         continue;
-	      }
-         if ((value = twiddler_rest_to_value(s))==s) {
-	         gpm_report(GPM_PR_ERR,GPM_MESS_INCORRECT_LINE,option.progname,TW_SYSTEM_FILE
-                                                         ,lineno,s);
-	         errcount++;
-	         continue;
-	      }
-
-         if (table[index]) {
-	         gpm_report(GPM_PR_ERR,GPM_MESS_REDEF_COORDS,option.progname,TW_SYSTEM_FILE,
-                                          lineno, mod, mod ? " " : "", chord);
-	      }
-         /* all done */
-         if (value)
-	         table[index]=value;
-         else
-	         table[index]=""; /* the empty string represents the nul byte */
-      }  /* fgets */
-      fclose(f);
-      while (files[++fileindex]) /* next file, optional */
-         if ( (f=fopen(files[fileindex],"r")) ) break;
-   }
-   return errcount;
-}
