Blob Blame History Raw
diff -urN gpm-1.20.1/configure.in gpm/configure.in
--- gpm-1.20.1/configure.in	2002-12-24 17:57:16.000000000 -0500
+++ gpm/configure.in	2003-10-02 01:22:42.000000000 -0500
@@ -61,6 +61,13 @@
 
 AC_CHECK_HEADERS(syslog.h linux/input.h linux/joystick.h ncurses.h ncurses/curses.h curses.h)
 
+EVDEV_SRCS=
+if test ${ac_cv_header_linux_input_h} = yes ; then
+        EVDEV_SRCS=evdev.c ;
+        AC_CHECK_TYPE(struct input_absinfo,AC_DEFINE_UNQUOTED(HAVE_INPUT_ABSINFO, 1, [define if struct input_absinfo defined in linux/input.h]),,[#include <linux/input.h>])
+        AC_CHECK_TYPE(struct input_id,AC_DEFINE_UNQUOTED(HAVE_INPUT_ID, 1, [define if struct input_id defined in linux/input.h]),,[#include <linux/input.h>])
+fi
+
 AC_ARG_WITH(curses,
 [  --without-curses        disable curses support even if curses found])
 
@@ -124,6 +131,7 @@
 AC_SUBST(PICFLAGS)
 AC_SUBST(SOLDFLAGS)
 AC_SUBST(CURSES_OBJS)
+AC_SUBST(EVDEV_SRCS)
 AC_SUBST(SHARED_LIBS)
 AC_SUBST(lispdir)
 
diff -urN gpm-1.20.1/src/client.c gpm/src/client.c
--- gpm-1.20.1/src/client.c	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/client.c	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,319 @@
+/*
+ * client.c - GPM client handling (server side)
+ *
+ * Copyright (C) 1993        Andreq Haylett <ajh@gec-mrc.co.uk>
+ * Copyright (C) 1994-1999   Alessandro Rubini <rubini@linux.it>
+ * Copyright (C) 1998         Ian Zimmerman <itz@rahul.net>
+ * Copyright (c) 2001,2002   Nico Schottelius <nico@schottelius.org>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>        /* strerror(); ?!?  */
+#include <errno.h>
+#include <unistd.h>        /* select(); */
+#include <signal.h>        /* SIGPIPE */
+#include <time.h>          /* time() */
+#include <sys/fcntl.h>     /* O_RDONLY */
+#include <sys/stat.h>      /* mkdir()  */
+#include <sys/time.h>      /* timeval */
+#include <sys/types.h>     /* socket() */
+#include <sys/socket.h>    /* socket() */
+#include <sys/un.h>        /* struct sockaddr_un */
+
+#include "headers/gpmInt.h"
+#include "headers/message.h"
+#include "headers/console.h"
+#include "headers/selection.h"
+#include "headers/client.h"
+
+/* who the f*** runs gpm without glibc? doesn't have dietlibc __socklent_t? */
+#if !defined(__GLIBC__)
+   typedef unsigned int __socklen_t;
+#endif    /* __GLIBC__ */
+
+#ifndef max
+#define max(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+extern int errno;
+
+struct client_info *cinfo[MAX_VC + 1];
+
+/*-------------------------------------------------------------------*
+ * This  was inline, and incurred in a compiler bug (2.7.0)
+ *-------------------------------------------------------------------*/
+static int get_data(int fd, Gpm_Connect *data) 
+{
+   static int len;
+   
+#ifdef GPM_USE_MAGIC
+   while ((len = read(whence, &check, sizeof(int))) == 4 && 
+          check != GPM_MAGIC)
+      gpm_report(GPM_PR_INFO, GPM_MESS_NO_MAGIC);
+
+   if (len == 0) return 0;
+
+   if (check != GPM_MAGIC) {
+      gpm_report(GPM_PR_INFO, GPM_MESS_NOTHING_MORE);
+      return -1;
+   }
+#endif
+
+   len = read(fd, data, sizeof(Gpm_Connect));
+
+   return len ? (len == sizeof(Gpm_Connect) ? 1 : -1) : 0;
+}
+
+/*-------------------------------------------------------------------*/
+int listen_for_clients(void)
+{
+   struct sockaddr_un ctladdr;
+   int fd, len;
+
+   unlink(GPM_NODE_CTL);
+
+   if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 
+      gpm_report(GPM_PR_OOPS, GPM_MESS_SOCKET_PROB);
+   
+   memset(&ctladdr, 0, sizeof(ctladdr));
+   ctladdr.sun_family = AF_UNIX;
+   strcpy(ctladdr.sun_path, GPM_NODE_CTL);
+   len = sizeof(ctladdr.sun_family) + strlen(GPM_NODE_CTL);
+
+   if (bind(fd, (struct sockaddr *)&ctladdr, len) == -1)
+      gpm_report(GPM_PR_OOPS, GPM_MESS_BIND_PROB, ctladdr.sun_path);
+
+   /* needs to be 0777, so all users can _try_ to access gpm */
+   chmod(GPM_NODE_CTL, 0777);
+   listen(fd, 5);          /* Queue up calls */
+
+   return fd;
+}
+
+/*-------------------------------------------------------------------*/
+struct client_info *accept_client_connection(int fd)
+{
+   struct client_info *info;
+   Gpm_Connect *request;
+   int newfd;
+#if !defined(__GLIBC__)
+   int len;
+#else /* __GLIBC__ */
+   size_t len; /* isn't that generally defined in C ???  -- nico */
+#endif /* __GLIBC__ */
+   struct sockaddr_un addr; /* reuse this each time */
+#ifndef SO_PEERCRED
+   struct stat statbuf;
+   time_t staletime;
+#endif
+   uid_t uid;
+
+   /*....................................... Accept */
+   memset(&addr, 0, sizeof(addr));
+   addr.sun_family = AF_UNIX;
+
+   len = sizeof(addr);
+   if ((newfd = accept(fd, (struct sockaddr *)&addr, &len)) < 0) {
+      gpm_report(GPM_PR_ERR, GPM_MESS_ACCEPT_FAILED, strerror(errno));
+      return NULL; 
+   }
+
+   gpm_report(GPM_PR_INFO, GPM_MESS_CONECT_AT, newfd);
+
+   if (!(info = malloc(sizeof(struct client_info))))
+      gpm_report(GPM_PR_OOPS, GPM_MESS_NO_MEM);
+
+   request = &info->data;
+   if (get_data(newfd, request) == -1)
+      goto err;
+
+   if (request->vc > MAX_VC) {
+      gpm_report(GPM_PR_WARN,GPM_MESS_REQUEST_ON, request->vc, MAX_VC);
+      goto err;
+   }
+
+#ifndef SO_PEERCRED
+   if (stat(addr.sun_path, &statbuf) == -1 || !S_ISSOCK(statbuf.st_mode)) {
+      gpm_report(GPM_PR_ERR,GPM_MESS_ADDRES_NSOCKET,addr.sun_path);
+      goto err;
+   }
+
+   unlink(addr.sun_path);   /* delete socket */
+
+   staletime = time(0) - 30;
+   if (statbuf.st_atime < staletime ||
+       statbuf.st_ctime < staletime ||
+       statbuf.st_mtime < staletime) {
+      gpm_report(GPM_PR_ERR, GPM_MESS_SOCKET_OLD);
+      goto err;
+   }
+
+   uid = statbuf.st_uid;      /* owner of socket */
+#else
+   {
+      struct ucred sucred;
+      socklen_t credlen = sizeof(struct ucred);
+
+      if (getsockopt(newfd, SOL_SOCKET, SO_PEERCRED, &sucred, &credlen) == -1) {
+         gpm_report(GPM_PR_ERR,GPM_MESS_GETSOCKOPT, strerror(errno));
+         goto err;
+      }
+      uid = sucred.uid;
+      gpm_report(GPM_PR_DEBUG,GPM_MESS_PEER_SCK_UID, uid);
+   }
+#endif
+
+   if (uid != 0 && !is_console_owner(request->vc, uid)) {
+      gpm_report(GPM_PR_WARN, GPM_MESS_FAILED_CONNECT, uid, request->vc);
+      goto err;
+   }
+
+   /* register the connection information in the right place */
+   info->next = cinfo[request->vc];
+   info->fd = newfd;
+   cinfo[request->vc] = info;
+   gpm_report(GPM_PR_DEBUG, GPM_MESS_LONG_STATUS,
+        request->pid, request->vc, request->eventMask, request->defaultMask,
+        request->minMod, request->maxMod);
+
+   return info;
+
+err:
+   free(info);
+   close(newfd);
+
+   return NULL;
+}
+
+/*-------------------------------------------------------------------*/
+void remove_client(struct client_info *ci, int vc)
+{
+   struct client_info *p, *prev = NULL;
+
+   for (p = cinfo[vc]; p; prev = p, p = p->next) {
+      if (p == ci) {
+         if (!prev)    /* it is on top of the stack */
+            cinfo[vc] = p->next;
+         else 
+            prev->next = p->next;
+         break;
+      }
+   }
+   if (p) free(p);
+}
+
+/*-------------------------------------------------------------------*/
+void notify_clients_resize(void)
+{
+   struct client_info *ci;
+   int i;
+
+   for (i = 0; i < MAX_VC + 1; i++)
+      for (ci = cinfo[i]; ci; ci = ci->next) 
+         kill(ci->data.pid, SIGWINCH);
+}
+
+/*-------------------------------------------------------------------*/
+/* returns 0 if the event has not been processed, and 1 if it has    */
+int do_client(struct client_info *cinfo, Gpm_Event *event)
+{
+   Gpm_Connect *info = &cinfo->data;
+   /* value to return if event is not used */
+   int res = !(info->defaultMask & event->type);
+
+   /* instead of returning 0, scan the stack of clients */
+   if ((info->minMod & event->modifiers) < info->minMod)
+      goto try_next;
+   if ((info->maxMod & event->modifiers) < event->modifiers) 
+      goto try_next;
+
+   /* if not managed, use default mask */
+   if (!(info->eventMask & GPM_BARE_EVENTS(event->type))) {
+      if (res) return res;
+      else goto try_next;
+   }   
+
+   /* WARNING */ /* This can generate a SIGPIPE... I'd better catch it */
+   MAGIC_P((write(cinfo->fd, &magic, sizeof(int))));
+   write(cinfo->fd, event, sizeof(Gpm_Event));
+
+   return info->defaultMask & GPM_HARD ? res : 1; /* HARD forces pass-on */
+
+ try_next:
+   if (cinfo->next != 0) 
+      return do_client(cinfo->next, event); /* try the next */
+
+   return 0; /* no next, not used */
+}
+
+/*-------------------------------------------------------------------*/
+/* returns 0 if client disconnects, -1 - error, 1 -successs */
+int process_client_request(struct client_info *ci, int vc,
+                           int x, int y, int buttons, int clicks,
+                           int three_button_mouse) 
+{
+   int rc;
+   Gpm_Connect conn;
+   static Gpm_Event event;
+
+   gpm_report(GPM_PR_INFO, GPM_MESS_CON_REQUEST, ci->fd, vc);
+   if (vc > MAX_VC) return -1;
+
+   /* itz 10-22-96 this shouldn't happen now */
+   if (vc == -1) gpm_report(GPM_PR_OOPS, GPM_MESS_UNKNOWN_FD);
+
+   rc = get_data(ci->fd, &conn);
+
+   if (rc == 0) { /* no data */
+      gpm_report(GPM_PR_INFO, GPM_MESS_CLOSE);
+      close(ci->fd);
+      return 0;
+   }
+ 
+   if (rc == -1) return -1; /* too few bytes */
+
+   if (conn.pid != 0) {
+      ci->data = conn;
+      return 1;
+   }
+
+   /* Aha, request for information (so-called snapshot) */
+   switch (conn.vc) {
+      case GPM_REQ_SNAPSHOT:
+         event.vc = get_console_state(&event.modifiers);
+         event.x = x; event.y = y;
+         event.buttons = buttons;
+         event.clicks = clicks;
+         event.dx = console.max_x; event.dy = console.max_y;
+         /* fall through */
+
+      case GPM_REQ_BUTTONS:
+         event.type = (three_button_mouse == 1 ? 3 : 2); /* buttons */
+         write(ci->fd, &event, sizeof(Gpm_Event));
+         break;
+
+      case GPM_REQ_NOPASTE:
+         selection_disable_paste();
+         gpm_report(GPM_PR_INFO, GPM_MESS_DISABLE_PASTE, vc);
+         break;
+   }
+
+   return 1;
+}
+
diff -urN gpm-1.20.1/src/console.c gpm/src/console.c
--- gpm-1.20.1/src/console.c	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/console.c	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,257 @@
+/*
+ * console.c - GPM console and selection/paste handling
+ *
+ * Copyright (C) 1993        Andreq Haylett <ajh@gec-mrc.co.uk>
+ * Copyright (C) 1994-1999   Alessandro Rubini <rubini@linux.it>
+ * Copyright (C) 1998        Ian Zimmerman <itz@rahul.net>
+ * Copyright (c) 2001,2002   Nico Schottelius <nico@schottelius.org>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>        /* strerror(); ?!?  */
+#include <errno.h>
+#include <unistd.h>        /* select(); */
+#include <time.h>          /* time() */
+#include <sys/fcntl.h>     /* O_RDONLY */
+#include <sys/stat.h>      /* mkdir()  */
+#include <asm/types.h>     /* __u32 */
+
+#include <linux/vt.h>      /* VT_GETSTATE */
+#include <sys/kd.h>        /* KDGETMODE */
+#include <termios.h>       /* winsize */
+
+#include "headers/gpmInt.h"
+#include "headers/console.h"
+#include "headers/message.h"
+
+#ifndef HAVE___U32
+# ifndef _I386_TYPES_H /* /usr/include/asm/types.h */
+typedef unsigned int __u32;
+# endif
+#endif
+
+struct gpm_console console = { 0, DEF_LUT, 0, 0 };
+
+/*-------------------------------------------------------------------*/
+static int count_digits(int num)
+{
+   int digits = 1;
+
+   while ((num /= 10))
+      digits++;
+
+   return digits;
+}
+
+/*-------------------------------------------------------------------*/
+char *compose_vc_name(int vc)
+{   
+   char  *tty;
+  
+   tty = malloc(strlen(console.device) + count_digits(vc) + sizeof(char));
+   if (tty) {
+      /* console is /dev/vc/0 or /dev/tty0 and we trimming the ending 0 */
+      strncpy(tty, console.device, strlen(console.device) - 1);
+      sprintf(&tty[strlen(console.device) - 1], "%d", vc);
+   }
+
+   return tty;
+}
+
+/*-------------------------------------------------------------------*/
+int open_console(int mode)
+{
+   int fd;
+
+   if ((fd = open(console.device, mode)) < 0)
+      gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN_CON);
+
+   return fd;
+}
+
+/*-------------------------------------------------------------------*/
+int is_text_console(void)
+{
+   int fd;
+   int kd_mode;
+
+   fd = open_console(O_RDONLY);
+   if (ioctl(fd, KDGETMODE, &kd_mode)<0)
+      gpm_report(GPM_PR_OOPS, GPM_MESS_IOCTL_KDGETMODE);
+   close(fd);
+   
+   return kd_mode == KD_TEXT;
+}
+
+/*-------------------------------------------------------------------*/
+void wait_text_console(void)
+{
+   do {
+      sleep(2);
+   } while (!is_text_console());
+}
+
+/*-------------------------------------------------------------------*/
+void refresh_console_size(void)
+{
+   struct winsize win;
+   int fd = open_console(O_RDONLY);
+
+   ioctl(fd, TIOCGWINSZ, &win);
+   close(fd);
+
+   if (!win.ws_col || !win.ws_row) {
+      gpm_report(GPM_PR_DEBUG, GPM_MESS_ZERO_SCREEN_DIM);
+      console.max_x = 80; console.max_y = 25;
+   } else {
+      console.max_x = win.ws_col; console.max_y = win.ws_row;
+   }
+   gpm_report(GPM_PR_DEBUG, GPM_MESS_SCREEN_SIZE, console.max_x, console.max_y);
+}
+
+/*-------------------------------------------------------------------*/
+int get_console_state(unsigned char *shift_state)
+{
+   struct vt_stat stat;
+   int fd;
+
+   fd = open_console(O_RDONLY);
+
+   *shift_state = 6; /* code for the ioctl */
+   if (ioctl(fd, TIOCLINUX, shift_state) < 0)
+      gpm_report(GPM_PR_OOPS, GPM_MESS_GET_SHIFT_STATE);
+
+   if (ioctl(fd, VT_GETSTATE, &stat) < 0) 
+      gpm_report(GPM_PR_OOPS, GPM_MESS_GET_CONSOLE_STAT);
+
+   close(fd);
+
+   return stat.v_active;
+}
+
+/*-------------------------------------------------------------------*/
+int is_console_owner(int vc, uid_t uid)
+{   
+   struct stat statbuf;
+   char  *tty;
+   int   rc;
+  
+   if ((tty = compose_vc_name(vc)) == NULL)
+      gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM);
+
+   if ((rc = stat(tty, &statbuf)) == -1)
+      gpm_report(GPM_PR_ERR, GPM_MESS_STAT_FAILS, tty);
+   
+   free(tty);
+
+   return rc != -1 && uid == statbuf.st_uid;
+}
+
+/*-------------------------------------------------------------------*/
+/* octal digit */
+static int isodigit(const unsigned char c)
+{
+   return ((c & ~7) == '0');
+}
+
+/*-------------------------------------------------------------------*/
+/* routine to convert digits from octal notation (Andries Brouwer) */
+static int getsym(const unsigned char *p0, unsigned char *res)
+{
+   const unsigned char *p = p0;
+   char c;
+
+   c = *p++;
+   if (c == '\\' && *p) {
+      c = *p++;
+      if (isodigit(c)) {
+         c -= '0';
+         if (isodigit(*p)) c = 8*c + (*p++ - '0');
+         if (isodigit(*p)) c = 8*c + (*p++ - '0');
+      }
+   }
+   *res = c;
+   return (p - p0);
+}
+
+/*-------------------------------------------------------------------*/
+/* description missing! FIXME */
+void console_load_lut(void)
+{
+   extern int errno;
+   int i, c, fd;
+   unsigned char this, next;
+   static __u32 long_array[9] = {
+      0x05050505, /* ugly, but preserves alignment */
+      0x00000000, /* control chars     */
+      0x00000000, /* digits            */
+      0x00000000, /* uppercase and '_' */
+      0x00000000, /* lowercase         */
+      0x00000000, /* Latin-1 control   */
+      0x00000000, /* Latin-1 misc      */
+      0x00000000, /* Latin-1 uppercase */
+      0x00000000  /* Latin-1 lowercase */
+   };
+
+#define inwordLut (long_array+1)
+
+   for (i = 0; console.charset[i]; ) {
+      i += getsym(console.charset + i, &this);
+      if (console.charset[i] == '-' && console.charset[i + 1] != '\0')
+         i += getsym(console.charset + i + 1, &next) + 1;
+      else
+         next = this;
+      for (c = this; c <= next; c++)
+         inwordLut[c >> 5] |= 1 << (c & 0x1F);
+   }
+  
+   fd = open_console(O_WRONLY);
+
+   if (ioctl(fd, TIOCLINUX, &long_array) < 0) { /* fd <0 is checked */
+      if (errno == EPERM && getuid())
+         gpm_report(GPM_PR_WARN, GPM_MESS_ROOT); /* why do we still continue?*/
+      else if (errno == EINVAL)
+         gpm_report(GPM_PR_OOPS, GPM_MESS_CSELECT);
+   }
+   close(fd);
+}
+
+/*-------------------------------------------------------------------*/
+/* Returns the name of the console (/dev/tty0 or /dev/vc/0)          */
+/* Also fills console.device                                         */
+char *get_console_name()
+{
+   struct stat buf;
+
+   /* first try the devfs device, because in the next time this will be
+    * the preferred one. If that fails, take the old console */
+   
+   /* Check for open new console */
+   if (stat(GPM_DEVFS_CONSOLE, &buf) == 0)
+      console.device = GPM_DEVFS_CONSOLE;
+  
+   /* Failed, try OLD console */
+   else if (stat(GPM_OLD_CONSOLE, &buf) == 0)
+      console.device = GPM_OLD_CONSOLE;
+   else
+      gpm_report(GPM_PR_OOPS, "Can't determine console device"); 
+
+   return console.device;
+}
+
diff -urN gpm-1.20.1/src/evdev.c gpm/src/evdev.c
--- gpm-1.20.1/src/evdev.c	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/evdev.c	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,851 @@
+/*
+ * evdev.c - support for event input devices in linux 2.4 & 2.6
+ *
+ * Copyright (C) 2003        Dmitry Torokhov <dtor@mail.ru>
+ * Based on XFree86 driver by Stefan Gmeiner & Peter Osterlund
+ *
+ *   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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <linux/input.h>
+#include "headers/input-defines.h" /* misisng bits in case <linux/input.h> is old */ 
+
+#include "headers/gpm.h"
+#include "headers/gpmInt.h"
+#include "headers/console.h"
+#include "headers/message.h"
+#include "headers/optparser.h"
+
+enum evdev_type { 
+   EVDEV_UNKNOWN,
+   EVDEV_RELATIVE, 
+   EVDEV_ABSOLUTE, 
+   EVDEV_TOUCHPAD, 
+   EVDEV_SYNAPTICS 
+};
+
+enum touch_type {
+   TOUCH_NONE, 
+   TOUCH_FINGERS, 
+   TOUCH_PALM
+};
+
+enum gesture_type {
+   GESTURE_NONE,
+   GESTURE_TAP_PENDING,
+   GESTURE_TAP,
+   GESTURE_DRAG_PENDING,
+   GESTURE_DRAG,
+   GESTURE_DOUBLE_TAP
+};
+
+enum edge_type {
+   BOTTOM_EDGE = 1,
+   TOP_EDGE = 2,
+   LEFT_EDGE = 4,
+   RIGHT_EDGE = 8,
+   LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
+   RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
+   RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
+   LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE              
+};
+ 
+struct event_data {
+   int dx, dy;
+   int wdx, wdy;
+   int abs_x, abs_y;
+   int buttons;
+   int touch;  /* dumb touchpad report touch events, smart ones - pressure */
+   int pressure;
+   int w;
+   int finger_count;
+   int synced;   
+};
+
+struct touch_data {
+   int touching;
+   int x, y;
+   int finger_count;
+   int buttons;
+   int clicks;
+   struct timeval start;
+   enum gesture_type gesture;
+};
+
+struct event_device {
+   enum evdev_type type;
+   int dont_sync;
+
+   struct event_data pkt;
+   int pkt_count;
+
+   int prev_x[4], prev_y[4];
+   int prev_pressure, avg_w;
+   struct touch_data touch;
+  
+   int left_edge, right_edge;
+   int top_edge, bottom_edge;
+   int touch_high, touch_low;
+   int tap_time, tap_move;
+   int y_inverted;   
+
+   enum touch_type (*detect_touch)(struct event_device *evdev);
+   void (*update_finger_count)(struct event_device *evdev);
+};
+
+struct evdev_capabilities {
+   unsigned char evbits[EV_MAX/8 + 1];
+   unsigned char keybits[KEY_MAX/8 + 1];
+   unsigned char absbits[ABS_MAX/8 + 1];
+   unsigned char mscbits[MSC_MAX/8 + 1];
+};
+
+#ifndef max
+#define max(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+#define fx(i)  (evdev->prev_x[(evdev->pkt_count - (i)) & 03])
+#define fy(i)  (evdev->prev_y[(evdev->pkt_count - (i)) & 03])
+
+#define toggle_btn(btn, val) do { if (val) data->buttons |= (btn);\
+                                  else     data->buttons &= ~(btn);\
+                             } while (0)
+#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 test_bit(bit, array)    (array[bit / 8] & (1 << (bit % 8)))
+
+/* ------------- evdev protocol handling routines ---------------------*/
+
+static void parse_input_event(struct input_event *event, struct event_data *data)
+{
+   switch (event->type) {
+      case EV_REL:
+         switch (event->code) {
+            case REL_X:
+               data->dx = (signed char)event->value;
+               break;
+            case REL_Y:
+               data->dy = (signed char)event->value;
+               break;
+            case REL_WHEEL:
+               data->wdy += event->value;
+               break;
+            case REL_HWHEEL:
+               data->wdx += event->value;
+               break;
+         }
+         break;
+
+      case EV_ABS:
+         switch (event->code) {
+            case ABS_X:
+               data->abs_x = event->value;
+               break;
+
+            case ABS_Y:
+               data->abs_y = event->value;
+               break;
+
+            case ABS_PRESSURE:
+               data->pressure = event->value;
+               break;
+
+            case ABS_TOOL_WIDTH:
+               data->w = event->value;
+               break;
+         }
+         break;
+
+      case EV_MSC:
+         switch (event->code) {
+            case MSC_GESTURE:
+               data->w = event->value;
+               break;
+         }
+         break;
+
+
+      case EV_KEY:
+         switch(event->code) {
+            case BTN_0:
+            case BTN_LEFT:
+               toggle_btn(GPM_B_LEFT, event->value);
+               break;
+
+            case BTN_2:
+            case BTN_STYLUS2:
+            case BTN_SIDE:
+            case BTN_MIDDLE:
+               toggle_btn(GPM_B_MIDDLE, event->value);
+               break;
+
+            case BTN_STYLUS:
+            case BTN_1:
+            case BTN_RIGHT:
+               toggle_btn(GPM_B_RIGHT, event->value);
+               break;
+
+            case BTN_TOUCH:
+               data->touch = event->value ? 1 : 0;
+               break;
+
+            case BTN_TOOL_FINGER:
+               if (event->value) data->finger_count = 1;
+               break;
+
+            case BTN_TOOL_DOUBLETAP:
+               if (event->value) data->finger_count = 2;
+               break;
+
+            case BTN_TOOL_TRIPLETAP:
+               if (event->value) data->finger_count = 3;
+               break;
+ 
+         }
+         break;
+
+      case EV_SYNC:
+         switch(event->code) {
+            case SYN_REPORT:
+               data->synced = 1;
+               break;
+         }
+         break;
+   }
+}
+
+static void tp_figure_deltas(struct event_device *evdev, struct Gpm_Event *state)
+{
+   struct event_data *pkt = &evdev->pkt;
+
+   state->dx = state->dy = 0;
+   if (evdev->touch.touching) {
+      fx(0) = pkt->abs_x; 
+      fy(0) = pkt->abs_y;
+      if (evdev->pkt_count >= 2 && 
+          evdev->touch.gesture != GESTURE_DRAG_PENDING) {
+         state->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; //SYN_REL_DECEL_FACTOR;
+         state->dy = ((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; //SYN_REL_DECEL_FACTOR;
+      }
+      evdev->pkt_count++;
+   } else  {
+      evdev->pkt_count = 0;
+   }
+}
+
+static enum touch_type dumb_tp_detect_touch(struct event_device *evdev)
+{
+   return evdev->pkt.touch ? TOUCH_FINGERS : TOUCH_NONE;
+}
+
+static enum touch_type smart_tp_detect_touch(struct event_device *evdev)
+{
+   if (evdev->touch.touching)
+      return evdev->pkt.pressure > evdev->touch_low ? TOUCH_FINGERS : TOUCH_NONE;
+   else 
+      return evdev->pkt.pressure > evdev->touch_high ? TOUCH_FINGERS : TOUCH_NONE;
+}
+
+static enum touch_type syn_detect_touch(struct event_device *evdev)
+{
+   struct event_data *pkt = &evdev->pkt;
+   enum touch_type type = TOUCH_NONE;
+
+   if (pkt->pressure > 200 || pkt->w > 10)
+      return TOUCH_PALM;
+
+   if (pkt->abs_x == 0)
+      evdev->avg_w = 0;
+   else
+      evdev->avg_w = (pkt->w - evdev->avg_w + 1) / 2;
+  
+   if (evdev->touch.touching) {
+      type = pkt->pressure > evdev->touch_low ? TOUCH_FINGERS : TOUCH_NONE;
+   } else if (pkt->pressure > evdev->touch_high) {
+      int safe_w = max(pkt->w, evdev->avg_w);
+
+      if (pkt->finger_count > 1)    
+         type = TOUCH_FINGERS;
+      else if (pkt->w < 2)
+         type = TOUCH_FINGERS;                  /* more than one finger -> not a palm */
+      else if (safe_w < 6 && evdev->prev_pressure < evdev->touch_high)
+         type = TOUCH_FINGERS;                  /* thin finger, distinct touch -> not a palm */
+      else if (safe_w < 7 && evdev->prev_pressure < evdev->touch_high / 2)
+         type = TOUCH_FINGERS;                  /* thin finger, distinct touch -> not a palm */
+      else if (pkt->pressure > evdev->prev_pressure + 1)
+         type = TOUCH_NONE;                     /* pressure not stable, may be a palm */
+      else if (pkt->pressure < evdev->prev_pressure - 5)
+         type = TOUCH_NONE;                     /* pressure not stable, may be a palm */
+      else
+         type = TOUCH_FINGERS;      
+   }
+
+   evdev->prev_pressure = pkt->pressure;
+   return type;
+}
+
+static enum edge_type tp_detect_edges(struct event_device *evdev, int x, int y)
+{
+   enum edge_type edge = 0;
+   
+   if (x > evdev->right_edge)
+      edge |= RIGHT_EDGE;
+   else if (x < evdev->left_edge)
+      edge |= LEFT_EDGE;
+
+   if (y < evdev->top_edge)
+      edge |= TOP_EDGE;
+   else if (y > evdev->bottom_edge)
+      edge |= BOTTOM_EDGE;
+
+   return edge;
+}
+
+static int tp_touch_expired(struct event_device *evdev)
+{
+   struct timeval now;
+
+   GET_TIME(now);
+   return DIF_TIME(evdev->touch.start, now) > evdev->tap_time;
+}
+
+static int tp_detect_tap(struct event_device *evdev)
+{
+   return !tp_touch_expired(evdev) &&
+          (evdev->touch.finger_count > 1 ||
+           (abs(evdev->pkt.abs_x - evdev->touch.x) < evdev->tap_move &&
+            abs(evdev->pkt.abs_y - evdev->touch.y) < evdev->tap_move));
+}
+
+static int tp_tap_to_buttons(struct event_device *evdev)
+{
+   enum edge_type edge;
+   if (evdev->touch.finger_count < 2) {
+      edge = tp_detect_edges(evdev, evdev->pkt.abs_x, evdev->pkt.abs_y);
+      switch (edge) {
+         case RIGHT_TOP_EDGE:
+            return GPM_B_MIDDLE;
+            break;
+         case RIGHT_BOTTOM_EDGE:
+            return GPM_B_RIGHT;
+            break;
+         default:
+            return GPM_B_LEFT;
+            break;
+      }
+   } else {
+      switch (evdev->touch.finger_count) {
+         case 2:
+            return GPM_B_MIDDLE;
+         case 3:
+            return GPM_B_RIGHT;
+         default:
+            return GPM_B_LEFT;
+      }
+   }
+}
+
+static void tp_detect_gesture(struct event_device *evdev, int timed_out, enum touch_type touch_type)
+{
+   struct touch_data *touch = &evdev->touch;
+   int was_touching = touch->touching;
+  
+   touch->touching = touch_type == TOUCH_FINGERS;
+
+   if (touch->touching) {
+      if (!was_touching) {
+         GET_TIME(touch->start);
+         touch->finger_count = 0; 
+         if (touch->gesture == GESTURE_TAP_PENDING) {
+            touch->gesture = GESTURE_DRAG_PENDING;
+         } else {
+            touch->x = evdev->pkt.abs_x;
+            touch->y = evdev->pkt.abs_y;
+            touch->buttons = 0;
+         }
+      } else if (touch->gesture == GESTURE_DRAG_PENDING && tp_touch_expired(evdev)) {
+         touch->gesture = GESTURE_DRAG;
+      }
+   } else {
+      if (was_touching) {
+        if (tp_detect_tap(evdev)) {
+            if (touch->gesture == GESTURE_DRAG_PENDING) {
+               touch->gesture = GESTURE_DOUBLE_TAP;
+               touch->clicks = 4;
+            } else {
+               if ((touch->buttons = tp_tap_to_buttons(evdev)) == GPM_B_LEFT) {
+                  touch->gesture = GESTURE_TAP_PENDING;
+               } else {
+                  touch->gesture = GESTURE_TAP;
+                  touch->clicks = 2;
+               }
+            }
+         } else {
+            touch->gesture = GESTURE_NONE;
+         }
+      } else {
+         if (touch->gesture == GESTURE_TAP_PENDING && tp_touch_expired(evdev)) {
+            touch->gesture = GESTURE_TAP;
+            touch->clicks = 2;
+         }
+      }
+   }
+}
+
+static int tp_process_gesture(struct event_device *evdev, struct Gpm_Event *state)
+{
+   int next_timeout = -1;
+
+   switch(evdev->touch.gesture) {
+      case GESTURE_DOUBLE_TAP:
+      case GESTURE_TAP:
+         if (--evdev->touch.clicks == 0) 
+            evdev->touch.gesture = GESTURE_NONE;
+         else 
+            next_timeout = 0;
+
+         if (evdev->touch.clicks % 2)
+            state->buttons |= evdev->touch.buttons;
+         else
+            state->buttons &= ~evdev->touch.buttons;
+         break;
+
+      case GESTURE_DRAG:
+         state->buttons |= evdev->touch.buttons;
+         break;
+
+      case GESTURE_DRAG_PENDING:
+      case GESTURE_TAP_PENDING:
+         next_timeout = evdev->tap_time;
+         break;
+               
+      default:
+         break;
+   }
+   return next_timeout;
+}
+
+static void tp_update_finger_count(struct event_device *evdev)
+{
+   evdev->touch.finger_count = max(evdev->pkt.finger_count, evdev->touch.finger_count);
+}
+
+static void syn_update_finger_count(struct event_device *evdev)
+{
+   if (evdev->pkt.w == 1)
+      evdev->touch.finger_count = 3;
+   else if (evdev->pkt.w == 0 && evdev->touch.finger_count != 3) 
+      evdev->touch.finger_count = 2;
+   else
+      evdev->touch.finger_count = 1;
+}
+ 
+static int compose_gpm_event(struct event_device *evdev, int timed_out, Gpm_Event *state)
+{
+   struct event_data *pkt = &evdev->pkt;
+   enum touch_type touch_type;
+   int next_timeout = -1;
+
+	if (!timed_out) {
+      state->buttons = pkt->buttons;
+      state->wdx = pkt->wdx; state->wdy = pkt->wdy;
+   }
+
+   switch (evdev->type) {
+      case EVDEV_RELATIVE:
+         if (!timed_out) {
+            state->dx = pkt->dx; state->dy = pkt->dy;
+            if (evdev->pkt.touch)
+               state->buttons |=  GPM_B_LEFT;
+            else
+               state->buttons &= ~GPM_B_LEFT;
+         }
+         break;
+
+      case EVDEV_ABSOLUTE:
+         if (!timed_out) {
+            if (pkt->abs_x < evdev->left_edge) 
+               pkt->abs_x = evdev->left_edge;
+            else if (pkt->abs_x > evdev->right_edge) 
+               pkt->abs_x = evdev->right_edge;
+
+            if (pkt->abs_y > evdev->bottom_edge) 
+               pkt->abs_y = evdev->bottom_edge;
+            else if (pkt->abs_y < evdev->top_edge) 
+               pkt->abs_y = evdev->top_edge;
+
+            state->x = (pkt->abs_x - evdev->left_edge) * 
+                        console.max_x / (evdev->right_edge - evdev->left_edge);
+            state->y = (pkt->abs_y - evdev->top_edge) * 
+                        console.max_y / (evdev->bottom_edge - evdev->top_edge);
+
+            if (evdev->y_inverted) state->y = console.max_y - state->y;
+
+            if (evdev->pkt.touch)
+               state->buttons |=  GPM_B_LEFT;
+            else
+               state->buttons &= ~GPM_B_LEFT;
+         }
+         break;
+
+      case EVDEV_TOUCHPAD:
+      case EVDEV_SYNAPTICS:
+         touch_type = timed_out ? TOUCH_NONE : evdev->detect_touch(evdev);
+
+         if (touch_type != TOUCH_PALM) {
+            tp_detect_gesture(evdev, timed_out, touch_type);
+
+            if (evdev->touch.touching && !tp_touch_expired(evdev))
+               evdev->update_finger_count(evdev);
+
+            if (evdev->touch.finger_count < 2)
+               tp_figure_deltas(evdev, state);
+
+            next_timeout = tp_process_gesture(evdev, state);
+         }
+         break;
+
+      default:
+         /* should not happen */
+         gpm_report(GPM_PR_OOPS, "Bad evdev type %d", evdev->type);
+         break;
+   }
+
+   if (evdev->y_inverted) state->dy = -state->dy;
+
+   return next_timeout;   
+}
+
+int M_evdev(struct micedev *dev, struct miceopt *opts, 
+            unsigned char *data, struct Gpm_Event *state)
+{
+   struct event_device *evdev = dev->private;
+   struct input_event *event = (struct input_event *)data;
+   int timed_out = data == NULL;
+
+   if (!timed_out)
+      parse_input_event(event, &evdev->pkt);
+
+   if (timed_out || evdev->pkt.synced || evdev->dont_sync) {
+      dev->timeout = compose_gpm_event(evdev, timed_out, state);
+      evdev->pkt.dx = evdev->pkt.dy = 0;
+      evdev->pkt.wdx = evdev->pkt.wdy = 0;
+      evdev->pkt.finger_count = 0;
+      evdev->pkt.synced = 0;
+      return 0;
+   }
+
+   dev->timeout = -1;
+   return -1;
+}
+
+/* ------------- evdev initialization routines ---------------------*/
+
+static int evdev_get_id(int fd, struct input_id *id)
+{
+   if (ioctl(fd, EVIOCGID, id) < 0) {
+      gpm_report(GPM_PR_ERR, "evdev: cannot query device identification");
+      return -1;
+   }
+   return 0;
+}
+
+static int evdev_get_capabilities(int fd, struct evdev_capabilities *caps)
+{
+   memset(caps, 0, sizeof(*caps));
+
+   if (ioctl(fd, EVIOCGBIT(0, EV_MAX), caps->evbits) < 0) {
+      gpm_report(GPM_PR_ERR, "evdev: cannot query device capabilities");
+      return -1;
+   }
+
+   if (test_bit(EV_ABS, caps->evbits) &&
+       ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(caps->absbits)), caps->absbits) < 0) {
+      gpm_report(GPM_PR_ERR, "evdev: cannot query ABS device capabilities");
+      return -1;
+   }
+
+   if (test_bit(EV_KEY, caps->evbits) &&
+       ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(caps->keybits)), caps->keybits) < 0) {
+      gpm_report(GPM_PR_ERR, "evdev: cannot query KEY device capabilities");
+      return -1;
+   }
+
+   if (test_bit(EV_MSC, caps->evbits) &&
+       ioctl(fd, EVIOCGBIT(EV_MSC, sizeof(caps->mscbits)), caps->mscbits) < 0) {
+      /* don't complain as 2.4 kernels didnt have it 
+      gpm_report(GPM_PR_ERR, "evdev: cannot query MSC device capabilities");
+      return -1;
+      */
+   }
+   return 0;
+}
+
+static int evdev_query_axis(int fd, int axis, int *axis_min, int *axis_max)
+{
+   struct input_absinfo axis_info;
+
+   if (ioctl(fd, EVIOCGABS(axis), &axis_info) == -1) {
+      gpm_report(GPM_PR_ERR, "evdev: could not query axis data");
+      return -1;
+   }
+
+   *axis_min = axis_info.minimum;
+   *axis_max = axis_info.maximum;
+   return 0;
+}
+
+static int evdev_get_limits(int fd, struct event_device *evdev,
+                            struct evdev_capabilities *caps)
+{
+   if (test_bit(ABS_X, caps->absbits) &&
+         evdev_query_axis(fd, ABS_X, &evdev->left_edge, &evdev->right_edge) < 0)
+      return -1;
+   
+   if (test_bit(ABS_Y, caps->absbits) &&
+         evdev_query_axis(fd, ABS_Y, &evdev->top_edge, &evdev->bottom_edge) < 0)
+      return -1; 
+
+   return 0;
+}
+
+static int is_synaptics(struct input_id *id)
+{
+   return id->bustype == BUS_I8042 && id->vendor == 0x0002 && id->product == PSMOUSE_SYNAPTICS;
+}
+
+static enum evdev_type evdev_guess_type(struct input_id *id, struct evdev_capabilities *caps) 
+{
+   if (test_bit(EV_ABS, caps->evbits)) {
+      if (is_synaptics(id))
+         return EVDEV_SYNAPTICS;
+
+      if (test_bit(BTN_TOUCH, caps->keybits) && caps->keybits[BTN_MOUSE / 8])
+         return EVDEV_TOUCHPAD;
+
+      return EVDEV_ABSOLUTE;
+   }
+
+   if (!test_bit(EV_REL, caps->evbits)) {
+      gpm_report(GPM_PR_ERR, 
+                 "evdev: device does not report neither absolute nor relative coordinates");
+      return EVDEV_UNKNOWN;
+   }
+
+   return EVDEV_RELATIVE;
+}
+
+static enum evdev_type evdev_str_to_type(const char *type)
+{
+   if (!strcmp(type, "relative")) {
+      return EVDEV_RELATIVE;
+   } else if (!strcmp(type, "absolute")) {
+      return EVDEV_ABSOLUTE;
+   } else if (!strcmp(type, "touchpad")) {
+      return EVDEV_TOUCHPAD;
+   } else if (!strcmp(type, "synaptics")) {
+      return EVDEV_SYNAPTICS;
+   } else {
+      gpm_report(GPM_PR_ERR, "evdev: unknown type '%s'", type);
+      return EVDEV_UNKNOWN;
+   }
+}
+
+static void warn_if_present(struct option_helper *optinfo, const char *name, const char *type)
+{
+   if (is_option_present(optinfo, name))
+      gpm_report(GPM_PR_WARN,
+                 "evdev: option '%s' is not valud for type '%s', ignored",
+                 name, type);
+}
+
+// -o type=(auto|synaptics|touchpad|relative|absolute),y_inverse,
+//    left=1234,right=1234,top=1234,bottom=1234,
+//    touch_high=30,touch_low=25,tap_time=30,tap_move=100
+static int evdev_apply_options(struct event_device *evdev, char *optstring)
+{
+   char *type = "auto";
+   struct option_helper optinfo[] = {
+      { "type",         OPT_STRING, u: { sptr: &type } },
+      { "y_inverted",   OPT_BOOL,   u: { iptr: &evdev->y_inverted }, value: 1 },
+      { "left",         OPT_INT,    u: { iptr: &evdev->left_edge } }, 
+      { "right",        OPT_INT,    u: { iptr: &evdev->right_edge } }, 
+      { "top",          OPT_INT,    u: { iptr: &evdev->top_edge } }, 
+      { "bottom",       OPT_INT,    u: { iptr: &evdev->bottom_edge } }, 
+      { "touch_high",   OPT_INT,    u: { iptr: &evdev->touch_high } }, 
+      { "touch_low",    OPT_INT,    u: { iptr: &evdev->touch_low } }, 
+      { "tap_time",     OPT_INT,    u: { iptr: &evdev->tap_time } }, 
+      { "tap_move",     OPT_INT,    u: { iptr: &evdev->tap_move } }, 
+      { "",             OPT_END }
+   }; 
+
+   if (parse_options("evdev", optstring, ',', optinfo) < 0)
+      return -1;
+
+   if (strcmp(type, "auto"))
+      evdev->type = evdev_str_to_type(type);
+
+   switch (evdev->type) {
+      case EVDEV_RELATIVE:
+         warn_if_present(optinfo, "left", type);
+         warn_if_present(optinfo, "right", type);
+         warn_if_present(optinfo, "top", type);
+         warn_if_present(optinfo, "bottom", type);
+         warn_if_present(optinfo, "tap_move", type);
+         warn_if_present(optinfo, "tap_time", type);
+         warn_if_present(optinfo, "touch_high", type);
+         warn_if_present(optinfo, "touch_low", type);
+         break;
+      
+      case EVDEV_ABSOLUTE:
+         warn_if_present(optinfo, "tap_move", type);
+         warn_if_present(optinfo, "tap_time", type);
+         warn_if_present(optinfo, "touch_high", type);
+         warn_if_present(optinfo, "touch_low", type);
+         break;
+     
+      case EVDEV_TOUCHPAD:
+         break;      
+
+      case EVDEV_SYNAPTICS:
+         warn_if_present(optinfo, "y_inverted", type);
+         break;
+
+      default:
+         return -1;
+   }
+   return 0;
+}
+
+int I_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");
+
+      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->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;
+         }
+      }
+      
+      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");
+            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;
+
+         default:
+            break;
+      }
+   }
+   
+   return 0;
+
+init_fail:
+   free(dev->private);
+   return -1;      
+}
+
diff -urN gpm-1.20.1/src/gpm.c gpm/src/gpm.c
--- gpm-1.20.1/src/gpm.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/gpm.c	2003-10-02 01:22:42.000000000 -0500
@@ -24,1108 +24,607 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>        /* strerror(); ?!?  */
+#include <limits.h>
 #include <errno.h>
 #include <unistd.h>        /* select(); */
 #include <signal.h>        /* SIGPIPE */
 #include <time.h>          /* time() */
-#include <sys/param.h>
 #include <sys/fcntl.h>     /* O_RDONLY */
 #include <sys/wait.h>      /* wait()   */
-#include <sys/stat.h>      /* mkdir()  */
 #include <sys/time.h>      /* timeval */
-#include <sys/types.h>     /* socket() */
-#include <sys/socket.h>    /* socket() */
-#include <sys/un.h>        /* struct sockaddr_un */
-
-#include <linux/vt.h>      /* VT_GETSTATE */
-#include <sys/kd.h>        /* KDGETMODE */
-#include <termios.h>       /* winsize */
 
 #include "headers/gpmInt.h"
 #include "headers/message.h"
-
-/* who the f*** runs gpm without glibc? doesn't have dietlibc __socklent_t? */
-#if !defined(__GLIBC__)
-   typedef unsigned int __socklen_t;
-#endif    /* __GLIBC__ */
+#include "headers/console.h"
+#include "headers/selection.h"
+#include "headers/client.h"
 
 #ifndef max
 #define max(a,b) ((a)>(b) ? (a) : (b))
 #endif
 
-extern int errno;
-
-static void gpm_killed(int);
-
-/*
- * all the values duplicated for dual-mouse operation are
- * now in this structure (see gpmInt.h)
- * mouse_table[0] is single mouse, mouse_table[1] and mouse_table[2]
- * are copied data from mouse_table[0] for dual mouse operation.
- */
-
-struct mouse_features mouse_table[3] = {
-   {
-      DEF_TYPE, DEF_DEV, DEF_SEQUENCE,
-      DEF_BAUD, DEF_SAMPLE, DEF_DELTA, DEF_ACCEL, DEF_SCALE, 0 /* scaley */,
-      DEF_TIME, DEF_CLUSTER, DEF_THREE, DEF_GLIDEPOINT_TAP,
-      (char *)NULL /* extra */,
-      (Gpm_Type *)NULL,
-      -1
-   }
-};
-struct mouse_features *which_mouse;
-
-/* These are only the 'global' options */
-
-char *opt_lut=DEF_LUT;
-int opt_test=DEF_TEST;
-int opt_ptrdrag=DEF_PTRDRAG;
-int opt_double=0;
-int opt_aged = 0;
-char *opt_special=NULL; /* special commands, like reboot or such */
-int opt_rawrep=0;
-Gpm_Type *repeated_type=0;
-
-static int opt_resize=0; /* not really an option */
-struct winsize win;
-int maxx, maxy;
-int fifofd=-1;
-
-int eventFlag=0;
-Gpm_Cinfo *cinfo[MAX_VC+1];
-fd_set selSet, readySet, connSet;
-
-time_t last_selection_time;
-time_t opt_age_limit = 0;
-
-/* BRAINDEAD..ok not really, but got to leave anyway... FIXME */
-/* argc and argv for mice initialization */
-static int mouse_argc[3]; /* 0 for default (unused) and two mice */
-static char **mouse_argv[3]; /* 0 for default (unused) and two mice */
-
-/*===================================================================*/
-/*
- *      first, all the stuff that used to be in gpn.c (i.e., not main-loop)
- */
-/*-------------------------------------------------------------------*/
+#ifndef min
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#endif
 
-/* build_argv is used for mouse initialization routines */
-static char **build_argv(char *argv0, char *str, int *argcptr, char sep)
-{
-   int argc = 1;
-   char **argv;
-   char *s;
-
-   /* argv0 is never NULL, but the extra string may well be */
-   if (str)
-      for (s=str; sep && (s = strchr(s, sep)); argc++) s++;
-   
-   argv = calloc(argc+2, sizeof(char **));
-   if (!argv) gpm_report(GPM_PR_OOPS,GPM_MESS_ALLOC_FAILED);
-   argv[0] = argv0;
-
-   if (!str) {
-      *argcptr = argc; /* 1 */
-      return argv;
-   }
-   /* else, add arguments */
-   s = argv[1] = strdup(str);
-   argc = 2; /* first to fill */
-
-   /* ok, now split: the first one is in place, and s is the whole string */
-   for ( ; sep && (s = strchr(s, sep)) ; argc++) {
-      *s = '\0';
-      s++;
-      argv[argc] = s;
-   }
-   *argcptr = argc;
-   return argv;
-}
+#define NULL_SET ((fd_set *)NULL)
+#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)
 
-/*-------------------------------------------------------------------*/
-/* The old console option is removed. We are taking stderr now
- * In the next update there should also be support for syslog
- ********************************************************************/
 
-static inline int open_console(const int mode)
-{
-   int fd;
+enum mouse_rslt { MOUSE_NO_DATA, MOUSE_DATA_OK, MOUSE_MORE_DATA };
 
-   if ((fd=open(option.consolename, mode)) < 0)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN_CON);
-   return fd;
-}
+extern int errno;
 
-/*-------------------------------------------------------------------*/
-static inline int wait_text(int *fdptr)
-{
-   int fd;
-   int kd_mode;
+char *opt_special=NULL; /* special commands, like reboot or such */
+struct repeater repeater;
 
-   close(*fdptr);
-   do
-   {
-      sleep(2);
-      fd = open_console(O_RDONLY);
-      if (ioctl(fd, KDGETMODE, &kd_mode)<0)
-         gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_KDGETMODE);
-      close(fd);
-   }
-   while (kd_mode != KD_TEXT) ;
-
-   /* reopen, reinit (the function is only used if we have one mouse device) */
-   if ((*fdptr=open(opt_dev,O_RDWR))<0)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,opt_dev);
-   if (m_type->init)
-      m_type=(m_type->init)(*fdptr, m_type->flags, m_type, mouse_argc[1],
-              mouse_argv[1]);
-   return (1);
-}
+static int console_resized; /* not really an option */
 
 /*-------------------------------------------------------------------*/
-static inline void selection_copy(int x1, int y1, int x2, int y2, int mode)
+static void gpm_killed(int signo)
 {
-/*
- * The approach in "selection" causes a bus error when run under SunOS 4.1
- * due to alignment problems...
- */
-   unsigned char buf[6*sizeof(short)];
-   unsigned short *arg = (unsigned short *)buf + 1;
-   int fd;
-
-   buf[sizeof(short)-1] = 2;  /* set selection */
-
-   arg[0]=(unsigned short)x1;
-   arg[1]=(unsigned short)y1;
-   arg[2]=(unsigned short)x2;
-   arg[3]=(unsigned short)y2;
-   arg[4]=(unsigned short)mode;
-
-   if ((fd=open_console(O_WRONLY))<0)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN_CON);
-   /* FIXME: should be replaced with string constant (headers/message.h) */
-   gpm_report(GPM_PR_DEBUG,"ctl %i, mode %i",(int)*buf, arg[4]);
-   if (ioctl(fd, TIOCLINUX, buf+sizeof(short)-1) < 0)
-     gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_TIOCLINUX);
-   close(fd);
-
-   if (mode < 3) {
-      opt_aged = 0;
-      last_selection_time = time(0);
+   if (signo == SIGWINCH) {
+      gpm_report(GPM_PR_WARN, GPM_MESS_RESIZING, option.progname, getpid());
+      console_resized = 1;
+   } else {
+      if (signo == SIGUSR1) 
+         gpm_report(GPM_PR_WARN, GPM_MESS_KILLED_BY, option.progname, getpid(), option.progname);
+      exit(0);
    }
 }
 
-
-/*-------------------------------------------------------------------*/
-/* comment missing; FIXME */
-/*-------------------------------------------------------------------*/
-static inline void selection_paste(void)
-{
-   char c=3;
-   int fd;
-
-   if (!opt_aged && (0 != opt_age_limit) &&
-      (last_selection_time + opt_age_limit < time(0))) {
-      opt_aged = 1;
-   }
-
-   if (opt_aged) {
-      gpm_report(GPM_PR_DEBUG,GPM_MESS_SKIP_PASTE);
-      return;
-   } 
-
-   fd=open_console(O_WRONLY);
-   if(ioctl(fd, TIOCLINUX, &c) < 0)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_TIOCLINUX);
-   close(fd);
-}
-
-/*-------------------------------------------------------------------*/
-static  inline int do_selection(Gpm_Event *event)  /* returns 0, always */
-{
-   static int x1=1, y1=1, x2, y2;
-#define UNPOINTER() 0
-
-   x2=event->x; y2=event->y;
-   switch(GPM_BARE_EVENTS(event->type)) {
-      case GPM_MOVE:
-         if (x2<1) x2++; else if (x2>maxx) x2--;
-         if (y2<1) y2++; else if (y2>maxy) y2--;
-         selection_copy(x2,y2,x2,y2,3); /* just highlight pointer */
-         return 0;
-
-      case GPM_DRAG:
-         if (event->buttons==GPM_B_LEFT) {
-            if (event->margin) /* fix margins */
-               switch(event->margin) {
-                  case GPM_TOP: x2=1; y2++; break;
-                  case GPM_BOT: x2=maxx; y2--; break;
-                  case GPM_RGT: x2--; break;
-                  case GPM_LFT: y2<=y1 ? x2++ : (x2=maxx, y2--); break;
-               }
-            selection_copy(x1,y1,x2,y2,event->clicks);
-            if (event->clicks>=opt_ptrdrag && !event->margin) /* pointer */
-               selection_copy(x2,y2,x2,y2,3);
-         } /* if */
-         return 0;
-
-      case GPM_DOWN:
-         switch (event->buttons) {
-            case GPM_B_LEFT:
-               x1=x2; y1=y2;
-               selection_copy(x1,y1,x2,y2,event->clicks); /* start selection */
-               return 0;
-
-            case GPM_B_MIDDLE:
-               selection_paste();
-               return 0;
-
-            case GPM_B_RIGHT:
-               if (opt_three==1)
-                  selection_copy(x1,y1,x2,y2,event->clicks);
-               else
-                  selection_paste();
-               return 0;
-         }
-   } /* switch above */
-   return 0;
-}
-
-/*-------------------------------------------------------------------*/
-/* returns 0 if the event has not been processed, and 1 if it has */
-static inline int do_client(Gpm_Cinfo *cinfo, Gpm_Event *event)
-{
-   Gpm_Connect info=cinfo->data;
-   int fd=cinfo->fd;
-   /* value to return if event is not used */
-   int res = !(info.defaultMask & event->type);
-
-   /* instead of returning 0, scan the stack of clients */
-   if ((info.minMod & event->modifiers) < info.minMod)
-      goto scan;
-   if ((info.maxMod & event->modifiers) < event->modifiers) 
-      goto scan;
-
-   /* if not managed, use default mask */
-   if (!(info.eventMask & GPM_BARE_EVENTS(event->type))) {
-      if (res) return res;
-      else goto scan;
-   }   
-
-   /* WARNING */ /* This can generate a SIGPIPE... I'd better catch it */
-   MAGIC_P((write(fd,&magic, sizeof(int))));
-   write(fd,event, sizeof(Gpm_Event));
-
-   return info.defaultMask & GPM_HARD ? res : 1; /* HARD forces pass-on */
-
-   scan:
-   if (cinfo->next != 0) 
-      return do_client (cinfo->next, event); /* try the next */
-   return 0; /* no next, not used */
-}
-
 /*-------------------------------------------------------------------
  * fetch the actual device data from the mouse device, dependent on
  * what Gpm_Type is being passed.
  *-------------------------------------------------------------------*/
-static inline char *getMouseData(int fd, Gpm_Type *type, int kd_mode)
+static char *getMouseData(int fd, Gpm_Type *type, int text_mode)
 {
    static unsigned char data[32]; /* quite a big margin :) */
-   char *edata=data+type->packetlen;
-   int howmany=type->howmany;
-   int i,j;
+   unsigned char *pdata;
+   int len, togo;
 
-/*....................................... read and identify one byte */
-
-   if (read(fd, data, howmany)!=howmany) {
-      if (opt_test) exit(0);
+   /*....................................... read and identify one byte */
+   if (read(fd, data, type->howmany) != type->howmany) {
       gpm_report(GPM_PR_ERR,GPM_MESS_READ_FIRST, strerror(errno));
       return NULL;
    }
 
-   if (kd_mode!=KD_TEXT && fifofd != -1 && opt_rawrep)
-      write(fifofd, data, howmany);
+   if (!text_mode && repeater.fd != -1 && repeater.raw)
+      write(repeater.fd, data, type->howmany);
 
-   if ((data[0]&(m_type->proto)[0]) != (m_type->proto)[1]) {
-      if (m_type->getextra == 1) {
-         data[1]=GPM_EXTRA_MAGIC_1; data[2]=GPM_EXTRA_MAGIC_2;
-         gpm_report(GPM_PR_DEBUG,GPM_EXTRA_DATA,data[0]);
+   if ((data[0] & type->proto[0]) != type->proto[1]) {
+      if (type->getextra == 1) {
+         data[1] = GPM_EXTRA_MAGIC_1; data[2] = GPM_EXTRA_MAGIC_2;
+         gpm_report(GPM_PR_DEBUG, GPM_EXTRA_DATA, data[0]);
          return data;
       }
-      gpm_report(GPM_PR_DEBUG,GPM_MESS_PROT_ERR);
+      gpm_report(GPM_PR_DEBUG, GPM_MESS_PROT_ERR);
       return NULL;
    }
 
-/*....................................... read the rest */
+   /*....................................... read the rest */
 
    /*
     * well, this seems to work almost right with ps2 mice. However, I've never
     * tried ps2 with the original selection package, which called usleep()
     */
-     
-   if((i=m_type->packetlen-howmany)) /* still to get */
+   if ((togo = type->packetlen - type->howmany)) { /* still to get */
+      pdata = &data[type->howmany];
       do {
-         j = read(fd,edata-i,i); /* edata is pointer just after data */
-         if (kd_mode!=KD_TEXT && fifofd != -1 && opt_rawrep && j > 0)
-            write(fifofd, edata-i, j);
-         i -= j;
-      } while (i && j);
-
-   if (i) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_READ_REST, strerror(errno));
+         if ((len = read(fd, pdata, togo)) == 0)
+            break; 
+         if (!text_mode && repeater.fd != -1 && repeater.raw && len > 0)
+            write(repeater.fd, pdata, len);
+         pdata += len;
+         togo -= len;
+      } while (togo);
+   }
+   
+   if (togo) {
+      gpm_report(GPM_PR_ERR, GPM_MESS_READ_REST, strerror(errno));
       return NULL;
    }
      
-   if ((data[1]&(m_type->proto)[2]) != (m_type->proto)[3]) {
-      gpm_report(GPM_PR_INFO,GPM_MESS_SKIP_DATA);
+   if ((data[1] & type->proto[2]) != type->proto[3]) {
+      gpm_report(GPM_PR_INFO, GPM_MESS_SKIP_DATA);
       return NULL;
    }
-   gpm_report(GPM_PR_DEBUG,GPM_MESS_DATA_4,data[0],data[1],data[2],data[3]);
+   gpm_report(GPM_PR_DEBUG, GPM_MESS_DATA_4, data[0], data[1], data[2], data[3]);
    return data;
 }
 
-
-static int statusX,statusY,statusB; /* to return info */
-static int statusC=0; /* clicks */
-void get_console_size(Gpm_Event *ePtr);
-
-/*-------------------------------------------------------------------
- * call getMouseData to get hardware device data, call mouse device's fun() 
- * to retrieve the hardware independent event data, then optionally repeat
- * the data via repeat_fun() to the repeater device
- *-------------------------------------------------------------------*/
-static inline int processMouse(int fd, Gpm_Event *event, Gpm_Type *type,
-                int kd_mode)
+/*-------------------------------------------------------------------*/
+void handle_console_resize(Gpm_Event *event)
 {
-   char *data;
-   static int fine_dx, fine_dy;
-   static int i, j, m;
-   static Gpm_Event nEvent;
-   static struct vt_stat stat;
-   static struct timeval tv1={0,0}, tv2; /* tv1==0: first click is single */
-   static struct timeval timeout={0,0};
-   fd_set fdSet;
-   static int newB=0, oldB=0, oldT=0; /* old buttons and Type to chain events */
-   /* static int buttonlock, buttonlockflag; */
-
-#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)
-
-
-   oldT=event->type;
-
-   if (eventFlag) {
-      eventFlag=0;
-
-      if (m_type->absolute) {     /* a pen or other absolute device */
-         event->x=nEvent.x;
-         event->y=nEvent.y;
-      }
-      event->dx=nEvent.dx;
-      event->dy=nEvent.dy;
-      event->buttons=nEvent.buttons;
-   } else {
-      event->dx=event->dy=0;
-      event->wdx=event->wdy=0;
-      nEvent.modifiers = 0; /* some mice set them */
-      FD_ZERO(&fdSet); FD_SET(fd,&fdSet); i=0;
-
-      do { /* cluster loop */
-         if(((data=getMouseData(fd,m_type,kd_mode))==NULL)
-            || ((*(m_type->fun))(&nEvent,data)==-1) ) {
-            if (!i) return 0;
-            else break;
-         }
-
-         event->modifiers = nEvent.modifiers; /* propagate modifiers */
-
-         /* propagate buttons */
-         nEvent.buttons = (opt_sequence[nEvent.buttons&7]&7) |
-            (nEvent.buttons & ~7); /* change the order */
-         oldB=newB; newB=nEvent.buttons;
-         if (!i) event->buttons=nEvent.buttons;
-
-         if (oldB!=newB) {
-            eventFlag = (i!=0)*(which_mouse-mouse_table); /* 1 or 2 */
-            break;
-         }
-
-         /* propagate movement */
-         if (!(m_type->absolute)) { /* mouse */
-            if (abs(nEvent.dx)+abs(nEvent.dy) > opt_delta)
-               nEvent.dx*=opt_accel, nEvent.dy*=opt_accel;
-
-            /* increment the reported dx,dy */
-            event->dx+=nEvent.dx;
-            event->dy+=nEvent.dy;
-         } else { /* a pen */
-            /* get dx,dy to check if there has been movement */
-            event->dx = (nEvent.x) - (event->x);
-            event->dy = (nEvent.y) - (event->y);
-         }
-
-         /* propagate wheel */
-         event->wdx += nEvent.wdx;
-         event->wdy += nEvent.wdy;
-
-         select(fd+1,&fdSet,(fd_set *)NULL,(fd_set *)NULL,&timeout/* zero */);
-
-      } while (i++ <opt_cluster && nEvent.buttons==oldB && FD_ISSET(fd,&fdSet));
-     
-   } /* if(eventFlag) */
-
-/*....................................... update the button number */
+   int old_x, old_y;
+   struct micetab *mouse;
 
-   if ((event->buttons&GPM_B_MIDDLE) && !opt_three) opt_three++;
+   old_x = console.max_x; old_y = console.max_y;
+   refresh_console_size();
+   if (!old_x) { /* first invocation, place the pointer in the middle */
+      event->x = console.max_x / 2;
+      event->y = console.max_y / 2;
+   } else { /* keep the pointer in the same position where it was */
+      event->x = event->x * console.max_x / old_x;
+      event->y = event->y * console.max_y / old_y;
+   } 
 
-/*....................................... we're a repeater, aren't we? */
+   for (mouse = micelist; mouse; mouse = mouse->next) {
+      /*
+       * the following operation is based on the observation that 80x50
+       * has square cells. (An author-centric observation ;-)
+       */
+      mouse->options.scaley = mouse->options.scalex * 50 * console.max_x / 80 / console.max_y;
+      gpm_report(GPM_PR_DEBUG, GPM_MESS_X_Y_VAL, 
+                 mouse->options.scalex, mouse->options.scaley);
+   }
+}
 
-   if (kd_mode!=KD_TEXT) {
-      if (fifofd != -1 && ! opt_rawrep) {
-         if (m_type->absolute) { /* hof Wed Feb  3 21:43:28 MET 1999 */ 
-            /* prepare the values from a absolute device for repeater mode */
-            static struct timeval rept1,rept2;
-            gettimeofday(&rept2, (struct timezone *)NULL);
-            if (((rept2.tv_sec -rept1.tv_sec)
-                  *1000+(rept2.tv_usec-rept1.tv_usec)/1000)>250) {
-               event->dx=0;
-               event->dy=0;
-            }
-            rept1=rept2;
-              
-            event->dy=event->dy*((win.ws_col/win.ws_row)+1);
-            event->x=nEvent.x; 
-            event->y=nEvent.y;
-         }
-         repeated_type->repeat_fun(event, fifofd); /* itz Jan 11 1999 */
+static void handle_repeater(int absolute_dev, Gpm_Event *new_event, Gpm_Event *event)
+{
+   static struct timeval last; 
+   struct timeval now;
+ 
+   if (absolute_dev) {
+      /* prepare the values from a absolute device for repeater mode */
+      GET_TIME(now); 
+      if (((now.tv_sec - last.tv_sec) * 1000 + 
+               (now.tv_usec - last.tv_usec) / 1000) > 250) {
+         event->dx = 0;
+         event->dy = 0;
       }
-      return 0; /* no events nor information for clients */
-   } /* first if of these three */
-
-/*....................................... no, we arent a repeater, go on */
+      last = now;
 
-   /* use fine delta values now, if delta is the information */
-   if (!(m_type)->absolute) {
-      fine_dx+=event->dx;             fine_dy+=event->dy;
-      event->dx=fine_dx/opt_scale;    event->dy=fine_dy/opt_scaley;
-      fine_dx %= opt_scale;           fine_dy %= opt_scaley;
+      event->dy = event->dy * ((console.max_x / console.max_y) + 1);
+      event->x = new_event->x;
+      event->y = new_event->y;
    }
+   repeater.type->repeat_fun(event, repeater.fd);
+}
 
-   /* up and down, up and down, ... who does a do..while(0) loop ???
-      and then makes a break into it... argh ! */
-
-   if (!event->dx && !event->dy && (event->buttons==oldB))
-      do { /* so to break */
-         static long awaketime;
-         /*
-          * Ret information also if never happens, but enough time has elapsed.
-          * Note: return 1 will segfault due to missing event->vc; FIXME!
-          */
-         if (time(NULL)<=awaketime) return 0;
-         awaketime=time(NULL)+1;
-         break;
-      } while (0);
-
-/*....................................... fill missing fields */
-
-   event->x+=event->dx, event->y+=event->dy;
-   statusB=event->buttons;
-
-   i=open_console(O_RDONLY);
-   /* modifiers */
-   j = event->modifiers; /* save them */
-   event->modifiers=6; /* code for the ioctl */
-   if (ioctl(i,TIOCLINUX,&(event->modifiers))<0)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_GET_SHIFT_STATE);
-   event->modifiers |= j; /* add mouse-specific bits */
-
-   /* status */
-   j = stat.v_active;
-   if (ioctl(i,VT_GETSTATE,&stat)<0) gpm_report(GPM_PR_OOPS,GPM_MESS_GET_CONSOLE_STAT);
-
-   /*
-    * if we changed console, request the current console size,
-    * as different consoles can be of different size
-    */
-   if (stat.v_active != j)
-      get_console_size(event);
-   close(i);
-
-   event->vc = stat.v_active;
-
-   if (oldB==event->buttons)
-      event->type = (event->buttons ? GPM_DRAG : GPM_MOVE);
-   else
-      event->type = (event->buttons > oldB ? GPM_DOWN : GPM_UP);
-
+static void calculate_clicks(Gpm_Event *event, int click_tmo)
+{
+   static struct timeval release;
+   struct timeval now;
+   
    switch(event->type) {                /* now provide the cooked bits */
       case GPM_DOWN:
-         GET_TIME(tv2);
-         if (tv1.tv_sec && (DIF_TIME(tv1,tv2)<opt_time)) /* check first click */
-            statusC++, statusC%=3; /* 0, 1 or 2 */
+         GET_TIME(now);
+         if (release.tv_sec && (DIF_TIME(release, now) < click_tmo)) /* check first click */
+            event->clicks++, event->clicks %= 3; /* 0, 1 or 2 */
          else
-            statusC=0;
-         event->type|=(GPM_SINGLE<<statusC);
+            event->clicks = 0;
+         event->type |= GPM_SINGLE << event->clicks;
          break;
 
       case GPM_UP:
-         GET_TIME(tv1);
-         event->buttons^=oldB; /* for button-up, tell which one */
-         event->type|= (oldT&GPM_MFLAG);
-         event->type|=(GPM_SINGLE<<statusC);
+         GET_TIME(release);
+         event->type |= GPM_SINGLE << event->clicks;
          break;
 
       case GPM_DRAG:
-         event->type |= GPM_MFLAG;
-         event->type|=(GPM_SINGLE<<statusC);
+         event->type |= GPM_SINGLE << event->clicks;
          break;
 
       case GPM_MOVE:
-         statusC=0;
+         event->clicks = 0;
+
       default:
          break;
    }
-   event->clicks=statusC;
+}
+
+static void snap_to_screen_limits(Gpm_Event *event)
+{
+   int extent;
    
-/* UGLY - FIXME! */
-/* The current policy is to force the following behaviour:
- * - At buttons up, must fit inside the screen, though flags are set.
- * - At button down, allow going outside by one single step
- */
+   /* The current policy is to force the following behaviour:
+    * - At buttons up, must fit inside the screen, though flags are set.
+    * - At button down, allow going outside by one single step
+    * DTOR: Midnight Commander seems to want the opposite...
+    */
 
+   extent = (event->type & (GPM_DRAG|GPM_UP)) ? 1 : 0;
 
    /* selection used 1-based coordinates, so do I */
-
    /*
     * 1.05: only one margin is current. Y takes priority over X.
-    * The i variable is how much margin is allowed. "m" is which one is there.
     */
 
-   m = 0;
-   i = ((event->type&(GPM_DRAG|GPM_UP))!=0); /* i is boolean */
-
-   if (event->y>win.ws_row)  {event->y=win.ws_row+1-!i; i=0; m = GPM_BOT;}
-   else if (event->y<=0)     {event->y=1-i;             i=0; m = GPM_TOP;}
-
-   if (event->x>win.ws_col)  {event->x=win.ws_col+1-!i; if (!m) m = GPM_RGT;}
-   else if (event->x<=0)     {event->x=1-i;             if (!m) m = GPM_LFT;}
+   event->margin = 0;
 
-   event->margin=m;
+   if (event->y > console.max_y) {
+      event->y = console.max_y + extent; 
+      extent = 0; 
+      event->margin = GPM_BOT;
+   } else if (event->y <= 0) {
+      event->y = 1 - extent;
+      extent = 0; 
+      event->margin = GPM_TOP;
+   }
 
-   gpm_report(GPM_PR_DEBUG,"M: %3i %3i (%3i %3i) - butt=%i vc=%i cl=%i",
-                                       event->dx,event->dy,
-                                       event->x,event->y,
-                                       event->buttons, event->vc,
-                                       event->clicks);
+   if (event->x > console.max_x) {
+      event->x = console.max_x + extent; 
+      if (!event->margin) event->margin = GPM_RGT;
+   } else if (event->x <= 0) {
+      event->x = 1 - extent;
+      if (!event->margin) event->margin = GPM_LFT;
+   }
+}
 
-   /* update the global state */
-   statusX=event->x; statusY=event->y;
+static int more_data_waiting(int fd)
+{
+   static struct timeval timeout = {0, 0};
+   fd_set fdSet;
 
-   if (opt_special && event->type & GPM_DOWN) 
-      return processSpecial(event);
+   FD_ZERO(&fdSet);
+   FD_SET(fd, &fdSet);
+   select(fd + 1, &fdSet, NULL_SET, NULL_SET, &timeout/* zero */);
 
-   return 1;
+   return FD_ISSET(fd, &fdSet);
 }
 
-/*-------------------------------------------------------------------*
- * This  was inline, and incurred in a compiler bug (2.7.0)
- *-------------------------------------------------------------------*/
-static int get_data(Gpm_Connect *where, int whence)
+static int multiplex_buttons(struct micetab *mouse, int new_buttons)
 {
-   static int i;
+   static int left_btn_clicks, mid_btn_clicks, right_btn_clicks;
+   int mask;
+   int muxed_buttons = 0;
+  
+   new_buttons = 
+      (mouse->options.sequence[new_buttons & 7] & 7) | (new_buttons & ~7);
+   mask = new_buttons ^ mouse->buttons;
+   mouse->buttons = new_buttons;
 
-#ifdef GPM_USE_MAGIC
-   while ((i=read(whence,&check,sizeof(int)))==4 && check!=GPM_MAGIC)
-      gpm_report(GPM_PR_INFO,GPM_MESS_NO_MAGIC);
-
-   if (!i) return 0;
-   if (check!=GPM_MAGIC) {
-     gpm_report(GPM_PR_INFO,GPM_MESS_NOTHING_MORE);
-     return -1;
+   if (mask & GPM_B_LEFT) {
+      if (new_buttons & GPM_B_LEFT) left_btn_clicks++;
+      else left_btn_clicks--;   
    }
-#endif
+   if (left_btn_clicks) muxed_buttons |= GPM_B_LEFT;
 
-   if ((i=read(whence, where, sizeof(Gpm_Connect)))!=sizeof(Gpm_Connect)) {
-      return i ? -1 : 0;
+   if (mask & GPM_B_MIDDLE) {
+      if (new_buttons & GPM_B_MIDDLE) mid_btn_clicks++;
+      else mid_btn_clicks--;
    }
+   if (mid_btn_clicks) muxed_buttons |= GPM_B_MIDDLE;
 
-   return 1;
-}
+   if (mask & GPM_B_RIGHT) {
+      if (new_buttons & GPM_B_RIGHT) right_btn_clicks++;
+      else right_btn_clicks--;
+   }
+   if (right_btn_clicks) muxed_buttons |= GPM_B_RIGHT;
 
-static void disable_paste(int vc)
-{
-   opt_aged++;
-   gpm_report(GPM_PR_INFO,GPM_MESS_DISABLE_PASTE,vc);
+   return muxed_buttons; 
 }
 
-/*-------------------------------------------------------------------*/
-                                  /* returns -1 if closing connection */
-static inline int processRequest(Gpm_Cinfo *ci, int vc) 
+/*-------------------------------------------------------------------
+ * call getMouseData to get hardware device data, call mouse device's fun() 
+ * to retrieve the hardware independent event data, then optionally repeat
+ * the data via repeat_fun() to the repeater device
+ *-------------------------------------------------------------------*/
+static enum mouse_rslt processMouse(struct micetab *mouse, int timeout, int attempt, 
+                                    Gpm_Event *event, int text_mode)
 {
+   static int last_active;
+   static int fine_dx, fine_dy;
+   static int oldB; 
+
+   static Gpm_Event nEvent;
+   struct Gpm_Type *type = mouse->type;
+   struct miceopt *opt = &mouse->options;
+   enum mouse_rslt rslt = MOUSE_DATA_OK;
+   unsigned char shift_state;
+   char *data = NULL;
    int i;
-   Gpm_Cinfo *cinfoPtr, *next;
-   Gpm_Connect conn;
-   static Gpm_Event event;
-   static struct vt_stat stat;
-
-   gpm_report(GPM_PR_INFO,GPM_MESS_CON_REQUEST, ci->fd, vc);
-   if (vc>MAX_VC) return -1;
-
-   /* itz 10-22-96 this shouldn't happen now */
-   if (vc==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_UNKNOWN_FD);
-
-   i=get_data(&conn,ci->fd);
-
-   if (!i) { /* no data */
-      gpm_report(GPM_PR_INFO,GPM_MESS_CLOSE);
-      close(ci->fd);
-      FD_CLR(ci->fd,&connSet);
-      FD_CLR(ci->fd,&readySet);
-      if (cinfo[vc]->fd == ci->fd) { /* it was on top of the stack */
-         cinfoPtr = cinfo[vc];
-         cinfo[vc]=cinfo[vc]->next; /* pop the stack */
-         free(cinfoPtr);
-         return -1;
-      }
-      /* somewhere inside the stack, have to walk it */
-      cinfoPtr = cinfo[vc];
-      while (cinfoPtr && cinfoPtr->next) {
-         if (cinfoPtr->next->fd == ci->fd) {
-            next = cinfoPtr->next;
-            cinfoPtr->next = next->next;
-            free (next);
+  
+   if (attempt > 1) {          /* continue interrupted cluster loop */
+      if (opt->absolute) {     
+         event->x = nEvent.x;
+         event->y = nEvent.y;
+      }
+      event->dx = nEvent.dx;
+      event->dy = nEvent.dy;
+      event->buttons = nEvent.buttons;
+   } else {
+      event->dx = event->dy = 0;
+      event->wdx = event->wdy = 0;
+      nEvent.modifiers = 0; /* some mice set them */
+      i = 0;
+
+      do { /* cluster loop */
+         if (!timeout && (data = getMouseData(mouse->dev.fd, type, text_mode)) != NULL) {
+            GET_TIME(mouse->timestamp);
+         }
+
+         /* in case of timeout data passed to typr->fun() is NULL */
+         if ((!timeout && data == NULL) || 
+             type->fun(&mouse->dev, &mouse->options, data, &nEvent) == -1) {
+            if (!i) return MOUSE_NO_DATA;
+            else break;
+         }
+         
+         event->modifiers = nEvent.modifiers; /* propagate modifiers */
+
+         /* propagate buttons */
+         nEvent.buttons = multiplex_buttons(mouse, nEvent.buttons);
+
+         if (!i) event->buttons = nEvent.buttons;
+
+         if (oldB != nEvent.buttons) {
+            rslt = MOUSE_MORE_DATA;
             break;
          }
-         cinfoPtr = cinfoPtr->next;
-      }
-      return -1;
-   } /* not data */
- 
-   if (i == -1) return -1; /* too few bytes */
 
-   if (conn.pid!=0) {
-      ci->data = conn;
-      return 0;
-   }
-
-   /* Aha, request for information (so-called snapshot) */
-   switch(conn.vc) {
-      case GPM_REQ_SNAPSHOT:
-         i=open_console(O_RDONLY);
-         ioctl(i,VT_GETSTATE,&stat);
-         event.modifiers=6; /* code for the ioctl */
-         if (ioctl(i,TIOCLINUX,&(event.modifiers))<0)
-         gpm_report(GPM_PR_OOPS,GPM_MESS_GET_SHIFT_STATE);
-         close(i);
-         event.vc = stat.v_active;
-         event.x=statusX;   event.y=statusY;
-         event.dx=maxx;     event.dy=maxy;
-         event.buttons= statusB;
-         event.clicks=statusC;
-         /* fall through */
-         /* missing break or do you want this ??? */
-
-      case GPM_REQ_BUTTONS:
-         event.type= (opt_three==1 ? 3 : 2); /* buttons */
-         write(ci->fd,&event,sizeof(Gpm_Event));
-         break;
+         /* propagate movement */
+         if (!opt->absolute) { /* mouse */
+            if (abs(nEvent.dx) + abs(nEvent.dy) > opt->delta)
+               nEvent.dx *= opt->accel, nEvent.dy *= opt->accel;
 
-      case GPM_REQ_NOPASTE:
-         disable_paste(vc);
-         break;
+            /* increment the reported dx,dy */
+            event->dx += nEvent.dx;
+            event->dy += nEvent.dy;
+         } else { /* a pen */
+            /* get dx,dy to check if there has been movement */
+            event->dx = nEvent.x - event->x;
+            event->dy = nEvent.y - event->y;
+         }
+
+         /* propagate wheel */
+         event->wdx += nEvent.wdx;
+         event->wdy += nEvent.wdy;
+         
+      } while (i++ < opt->cluster && more_data_waiting(mouse->dev.fd));
+   } /* if(eventFlag) */
+
+   /*....................................... update the button number */
+
+   if ((event->buttons & GPM_B_MIDDLE) && !opt->three_button) opt->three_button++;
+
+   /*....................................... we're a repeater, aren't we? */
+
+   if (!text_mode) {
+      if (repeater.fd != -1 && !repeater.raw)
+         handle_repeater(opt->absolute, &nEvent, event);
+      oldB = nEvent.buttons;
+      return MOUSE_NO_DATA; /* no events nor information for clients */
    }
 
-   return 0;
-}
+/*....................................... no, we arent a repeater, go on */
 
-/*-------------------------------------------------------------------*/
-static inline int processConn(int fd) /* returns newfd or -1 */
-{
-   Gpm_Cinfo *info;
-   Gpm_Connect *request;
-   Gpm_Cinfo *next;
-   int vc, newfd;
-#if !defined(__GLIBC__)
-   int len;
-#else /* __GLIBC__ */
-   size_t len; /* isn't that generally defined in C ???  -- nico */
-#endif /* __GLIBC__ */
-   struct sockaddr_un addr; /* reuse this each time */
-   struct stat statbuf;
-   uid_t uid;
-   char *tty = NULL;
-
-/*....................................... Accept */
-
-   bzero((char *)&addr,sizeof(addr));
-   addr.sun_family=AF_UNIX;
-
-   len=sizeof(addr);
-   if ((newfd=accept(fd,(struct sockaddr *)&addr, &len))<0) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_ACCEPT_FAILED,strerror(errno));
-      return -1;
-   }
-
-   gpm_report(GPM_PR_INFO,GPM_MESS_CONECT_AT,newfd);
-
-   info=malloc(sizeof(Gpm_Cinfo));
-   if (!info) gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM);
-   request=&(info->data);
-
-   if(get_data(request,newfd)==-1) {
-      free(info);
-      close(newfd);
-      return -1;
-   }
-
-   if ((vc=request->vc)>MAX_VC) {
-      gpm_report(GPM_PR_WARN,GPM_MESS_REQUEST_ON, vc, MAX_VC);
-      free(info);
-      close(newfd);
-      return -1;
-   }
-
-#ifndef SO_PEERCRED
-   if (stat (addr.sun_path, &statbuf) == -1 || !S_ISSOCK(statbuf.st_mode)) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_ADDRES_NSOCKET,addr.sun_path);
-      free(info);         /* itz 10-12-95 verify client's right */
-      close(newfd);
-      return -1;         /* to read requested tty */
+   /* use fine delta values now, if delta is the information */
+   if (!opt->absolute) {
+      fine_dx += event->dx;
+      fine_dy += event->dy;
+      event->dx = fine_dx / opt->scalex;
+      event->dy = fine_dy / opt->scaley;
+      fine_dx %= opt->scalex;           
+      fine_dy %= opt->scaley;
    }
-   
-   unlink(addr.sun_path);   /* delete socket */
 
-   staletime = time(0) - 30;
-   if (statbuf.st_atime < staletime
-    || statbuf.st_ctime < staletime
-    || statbuf.st_mtime < staletime) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_SOCKET_OLD);
-      free (info);
-      close(newfd);
-      return -1;         /* socket is ancient */
+   /* up and down, up and down, ... who does a do..while(0) loop ???
+      and then makes a break into it... argh ! */
+
+   if (!event->dx && !event->dy && event->buttons == oldB) {
+      static time_t awaketime;
+      /*
+       * Ret information also if never happens, but enough time has elapsed.
+       * Note: return 1 will segfault due to missing event->vc; FIXME!
+       */
+      if (time(NULL) <= awaketime) return MOUSE_NO_DATA;
+      awaketime = time(NULL) + 1;
    }
    
-   uid = statbuf.st_uid;      /* owner of socket */
-#else
-   {
-      struct ucred sucred;
-      socklen_t credlen = sizeof(struct ucred);
-
-      if(getsockopt(newfd, SOL_SOCKET, SO_PEERCRED, &sucred, &credlen) == -1) {
-         gpm_report(GPM_PR_ERR,GPM_MESS_GETSOCKOPT, strerror(errno));
-         free(info);
-         close(newfd);
-         return -1;
-      }
-      uid = sucred.uid;
-      gpm_report(GPM_PR_DEBUG,GPM_MESS_PEER_SCK_UID, uid);
-   }
-#endif
-   if (uid != 0) {
-      if(( tty =
-         malloc(strlen(option.consolename)+Gpm_cnt_digits(vc) + sizeof(char))) == NULL)
-            gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM);
-      
-      strncpy(tty,option.consolename,strlen(option.consolename)-1);
-      sprintf(&tty[strlen(option.consolename)-1],"%d",vc);
+   /*....................................... fill missing fields */
+   event->x += event->dx; event->y += event->dy;
 
-      if(stat(tty, &statbuf) == -1) {
-         gpm_report(GPM_PR_ERR,GPM_MESS_STAT_FAILS,tty);
-         free(info);
-         free(tty);
-         close(newfd);
-         return -1;
-      }
-      if (uid != statbuf.st_uid) {
-         gpm_report(GPM_PR_WARN,GPM_MESS_FAILED_CONNECT, uid, tty); /*SUSPECT!*/
-         free(info);
-         free(tty);
-         close(newfd);
-         return -1;
+   event->vc = get_console_state(&shift_state);
+   if (event->vc != last_active) {
+      handle_console_resize(event);
+      last_active = event->vc;
+   }
+   event->modifiers |= shift_state;
+
+   if (oldB == event->buttons)
+      event->type = (event->buttons ? (GPM_DRAG | GPM_MFLAG) : GPM_MOVE);
+   else {
+      if (event->buttons > oldB)
+         event->type = GPM_DOWN;
+      else {
+         event->type &= GPM_MFLAG;
+         event->type |= GPM_UP;
+         event->buttons ^= oldB; /* for button-up, tell which one */
       }
-      free(tty); /* at least here it's not needed anymore */
    }
+   calculate_clicks(event, opt->time);
+   snap_to_screen_limits(event);
+   
+   gpm_report(GPM_PR_DEBUG,"M: %3i %3i (%3i %3i) - butt=%i vc=%i cl=%i",
+                            event->dx, event->dy, event->x, event->y,
+                            event->buttons, event->vc, event->clicks);
 
-   /* register the connection information in the right place */
-   info->next=next=cinfo[vc];
-   info->fd=newfd;
-   cinfo[vc]=info;
-   gpm_report(GPM_PR_DEBUG,GPM_MESS_LONG_STATUS,
-        request->pid, request->vc, request->eventMask, request->defaultMask,
-        request->minMod, request->maxMod);
-
-   /* if the client gets motions, give it the current position */
-   if(request->eventMask & GPM_MOVE) {
-      Gpm_Event event={0,0,vc,0,0,statusX,statusY,GPM_MOVE,0,0};
-      do_client(info, &event);
-   }
+   oldB = nEvent.buttons;
 
-   return newfd;
+   if (opt_special && (event->type & GPM_DOWN) && !processSpecial(event))
+      rslt = MOUSE_NO_DATA;
+   
+   return rslt;
 }
 
-/*-------------------------------------------------------------------*/
-void get_console_size(Gpm_Event *ePtr)
+static int wait_for_data(fd_set *connSet, int maxfd, fd_set *selSet)
 {
-   int i, prevmaxx, prevmaxy;
-   struct mouse_features *which_mouse; /* local */
+   struct micetab *mouse;
+   struct timeval now, timeout = { 0, 0 };
+   int mouse_tmo, tmo = INT_MAX;
 
-   /* before asking the new console size, save the previous values */
-   prevmaxx = maxx; prevmaxy = maxy;
+   GET_TIME(now);
 
-   i=open_console(O_RDONLY);
-   ioctl(i, TIOCGWINSZ, &win);
-   close(i);
-   if (!win.ws_col || !win.ws_row) {
-      gpm_report(GPM_PR_DEBUG,GPM_MESS_ZERO_SCREEN_DIM);
-      win.ws_col=80; win.ws_row=25;
-   }
-   maxx=win.ws_col; maxy=win.ws_row;
-   gpm_report(GPM_PR_DEBUG,GPM_MESS_SCREEN_SIZE,maxx,maxy);
-
-   if (!prevmaxx) { /* first invocation, place the pointer in the middle */
-      statusX = ePtr->x = maxx/2;
-      statusY = ePtr->y = maxy/2;
-   } else { /* keep the pointer in the same position where it was */
-      statusX = ePtr->x = ePtr->x * maxx / prevmaxx;
-      statusY = ePtr->y = ePtr->y * maxy / prevmaxy;
-   } 
-
-   for (i=1; i <= 1+opt_double; i++) {
-      which_mouse=mouse_table+i; /* used to access options */
-     /*
-      * the following operation is based on the observation that 80x50
-      * has square cells. (An author-centric observation ;-)
-      */
-     opt_scaley=opt_scale*50*maxx/80/maxy;
-     gpm_report(GPM_PR_DEBUG,GPM_MESS_X_Y_VAL,opt_scale,opt_scaley);
+   *selSet = *connSet;
+   for (mouse = micelist; mouse; mouse = mouse->next) {
+      FD_SET(mouse->dev.fd, selSet);
+      maxfd = max(maxfd, mouse->dev.fd);
+      if (mouse->dev.timeout >= 0) {
+         mouse_tmo = mouse->dev.timeout - DIF_TIME(mouse->timestamp, now);
+         tmo = min(tmo, mouse_tmo);
+      }
    }
+   
+   if (tmo == INT_MAX)
+      timeout.tv_sec = SELECT_TIME;
+   else if (tmo > 0) {
+      timeout.tv_sec = tmo / 1000;
+      timeout.tv_usec = (tmo % 1000) * 1000;
+   }
+   
+   return select(maxfd + 1, selSet, NULL_SET, NULL_SET, &timeout);
 }
 
-/*-------------------------------------------------------------------*/
-static void gpm_killed(int signo)
-{
-   if(signo==SIGWINCH) {
-      gpm_report(GPM_PR_WARN,GPM_MESS_RESIZING, option.progname, getpid());
-      opt_resize++;
-      return;
-   }
-   if (signo==SIGUSR1)
-     gpm_report(GPM_PR_WARN,GPM_MESS_KILLED_BY,option.progname, getpid(),option.progname);
-   exit(0);
-}
+
 
 /*-------------------------------------------------------------------*/
 int old_main()
 {
-   int ctlfd, newfd;
-   struct sockaddr_un ctladdr;
-   int i, len, kd_mode, fd;
-   struct timeval timeout;
-   int maxfd=-1;
-   int pending;
+   int ctlfd;
+   int i, text_mode;
+   struct timeval now;
+   int maxfd = -1;
+   int pending, attempt;
+   int timed_out;
    Gpm_Event event;
+   struct micetab *mouse;
+   struct client_info *ci;
+   fd_set selSet, connSet;
+   enum mouse_rslt rslt;
 
-   for (i = 1; i <= 1+opt_double; i++) {
-      which_mouse=mouse_table+i; /* used to access options */
-
-      if (!opt_dev) gpm_report(GPM_PR_OOPS,GPM_MESS_NEED_MDEV);
-
-      if(!strcmp(opt_dev,"-")) fd=0; /* use stdin */
-      else if( (fd=open(opt_dev,O_RDWR | O_NDELAY)) < 0)
-         gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,opt_dev); 
-             
-      /* and then reset the flag */
-      fcntl(fd,F_SETFL,fcntl(fd,F_GETFL) & ~O_NDELAY);
-
-      /* create argc and argv for this device */
-      mouse_argv[i] = build_argv(opt_type, opt_options, &mouse_argc[i], ',');
-
-      /* init the device, and use the return value as new mouse type */
-      if (m_type->init)
-         m_type=(m_type->init)(fd, m_type->flags, m_type, mouse_argc[i],
-         mouse_argv[i]);
-      if (!m_type) gpm_report(GPM_PR_OOPS,GPM_MESS_MOUSE_INIT);
-
-      which_mouse->fd=fd;
-      maxfd=max(fd, maxfd);
-   }
-
-/*....................................... catch interesting signals */
-
+   /*....................................... catch interesting signals */
    signal(SIGTERM, gpm_killed);
    signal(SIGINT,  gpm_killed);
    signal(SIGUSR1, gpm_killed); /* usr1 is used by a new gpm killing the old */
    signal(SIGWINCH,gpm_killed); /* winch can be sent if console is resized */
+   signal(SIGPIPE, SIG_IGN);    /* WARN */
 
-/*....................................... create your nodes */
-
-   /* control node */
-
-   if((ctlfd=socket(AF_UNIX,SOCK_STREAM,0))==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_SOCKET_PROB);
-   bzero((char *)&ctladdr,sizeof(ctladdr));
-   ctladdr.sun_family=AF_UNIX;
-   strcpy(ctladdr.sun_path,GPM_NODE_CTL);
-   unlink(GPM_NODE_CTL);
-
-   len=sizeof(ctladdr.sun_family)+strlen(GPM_NODE_CTL);
-   if(bind(ctlfd,(struct sockaddr *)(&ctladdr),len) == -1)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_BIND_PROB,ctladdr.sun_path);
-   maxfd=max(maxfd,ctlfd);
-
-   /* needs to be 0777, so all users can _try_ to access gpm */
-   chmod(GPM_NODE_CTL,0777);
-
-   get_console_size(&event); /* get screen dimensions */
-
-/*....................................... wait for mouse and connections */
-
-   listen(ctlfd, 5);          /* Queue up calls */
-
-#define NULL_SET ((fd_set *)NULL)
-#define resetTimeout() (timeout.tv_sec=SELECT_TIME,timeout.tv_usec=0)
+   init_mice();
+   handle_console_resize(&event); /* get screen dimensions */
+   ctlfd = listen_for_clients();
 
+   /*....................................... wait for mouse and connections */
    FD_ZERO(&connSet);
-   FD_SET(ctlfd,&connSet);
-
-   if (opt_double) FD_SET(mouse_table[2].fd,&connSet);
-
-   readySet=connSet;
-   FD_SET(mouse_table[1].fd,&readySet);
-
-   signal(SIGPIPE,SIG_IGN);  /* WARN */
-
-/*--------------------------------------- main loop begins here */
+   FD_SET(ctlfd, &connSet);
+   maxfd = max(maxfd, ctlfd);
+   
+   /*--------------------------------------- main loop begins here */
 
-   while(1) {
-      selSet=readySet;
-      resetTimeout();
-      if (opt_test) timeout.tv_sec=0;
+   while (1) {
 
-      if (eventFlag) { /* an event left over by clustering */
-         pending=1;
-         FD_ZERO(&selSet);
-         FD_SET(mouse_table[eventFlag].fd,&selSet);
-      }
-      else
-         while((pending=select(maxfd+1,&selSet,NULL_SET,NULL_SET,&timeout))==0){
-            selSet=readySet;
-            resetTimeout();
-         } /* go on */
-
-      if(opt_resize) { /* did the console resize? */
-         get_console_size(&event);
-         opt_resize--;
-         signal(SIGWINCH,gpm_killed); /* reinstall handler */
-
-         /* and notify clients */
-         for(i=0; i<MAX_VC+1; i++) {
-            Gpm_Cinfo *ci;
-            for (ci = cinfo[i]; ci; ci = ci->next) kill(ci->data.pid,SIGWINCH);
-         }
+      pending = wait_for_data(&connSet, maxfd, &selSet);
+      
+      if (console_resized) { /* did the console resize? */
+         handle_console_resize(&event);
+         console_resized = 0;
+         signal(SIGWINCH, gpm_killed); /* reinstall handler */
+         notify_clients_resize();
       }
 
       if (pending < 0) {
-         if (errno==EBADF) gpm_report(GPM_PR_OOPS,GPM_MESS_SELECT_PROB);
-         gpm_report(GPM_PR_ERR,GPM_MESS_SELECT_STRING,strerror(errno));
-         selSet=readySet;
-         resetTimeout();
+         if (errno == EBADF) gpm_report(GPM_PR_OOPS,GPM_MESS_SELECT_PROB);
+         gpm_report(GPM_PR_ERR, GPM_MESS_SELECT_STRING, strerror(errno));
          continue;
       }
 
-      gpm_report(GPM_PR_DEBUG,GPM_MESS_SELECT_TIMES,pending);
+      gpm_report(GPM_PR_DEBUG, GPM_MESS_SELECT_TIMES, pending);
 
-/*....................................... manage graphic mode */
+      /*....................................... manage graphic mode */
 
-     /* 
-      * Be sure to be in text mode. This used to be before select,
-      * but actually it only matters if you have events.
-      */
-      {
-      int fd = open_console(O_RDONLY);
-      if (ioctl(fd, KDGETMODE, &kd_mode) < 0)
-         gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_KDGETMODE);
-      close(fd);
-      if(kd_mode != KD_TEXT && !option.repeater) {
-         wait_text(&mouse_table[1].fd);
-         maxfd=max(maxfd,mouse_table[1].fd);
-         readySet=connSet;
-         FD_SET(mouse_table[1].fd,&readySet);
+      /* 
+       * Be sure to be in text mode. This used to be before select,
+       * but actually it only matters if you have events.
+       */
+      text_mode = is_text_console();
+      if (!text_mode && !repeater.type && !repeater.raw) {
+         /* if we don;t have repeater then there is only one mouse so
+          * we can safely use micelist
+          */
+         close(micelist->dev.fd);
+         wait_text_console();
+         /* reopen, reinit (the function is only used if we have one mouse device) */
+         if ((micelist->dev.fd = open(micelist->device, O_RDWR)) < 0)
+            gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, micelist->device);
+         if (micelist->type->init)
+            micelist->type->init(&micelist->dev, &micelist->options, micelist->type); 
          continue; /* reselect */
       }
-      }
 
-/*....................................... got mouse, process event */
-/*
- * Well, actually, run a loop to maintain inlining of functions without
- * lenghtening the file. This is not too clean a code, but it works....
- */
-
-      for (i=1; i <= 1+opt_double; i++) {
-         which_mouse=mouse_table+i; /* used to access options */
-         if (FD_ISSET(which_mouse->fd,&selSet)) {
-            FD_CLR(which_mouse->fd,&selSet); pending--;
-            if (processMouse(which_mouse->fd, &event, m_type, kd_mode))
-               /* pass it to the client, if any
-                * or to the default handler, if any
-                * or to the selection handler
-                */ /* FIXME -- check event.vc */
-               /* can't we please rewrite the following a bit nicer?*/
-               (cinfo[event.vc] && do_client(cinfo[event.vc], &event))
-               || (cinfo[0]        && do_client(cinfo[0],        &event))
-               ||  do_selection(&event);
+      /*....................................... got mouse, process event */
+      /*
+       * Well, actually, run a loop to maintain inlining of functions without
+       * lenghtening the file. This is not too clean a code, but it works....
+       */
+      GET_TIME(now);
+      for (mouse = micelist; mouse; mouse = mouse->next) {
+         timed_out = mouse->dev.timeout >= 0 &&
+                     DIF_TIME(mouse->timestamp, now) >= mouse->dev.timeout;
+         if (timed_out || FD_ISSET(mouse->dev.fd, &selSet)) {
+            if (FD_ISSET(mouse->dev.fd, &selSet)) {
+               FD_CLR(mouse->dev.fd, &selSet); 
+               pending--;
             }
+            attempt = 0;
+            do {
+               rslt = processMouse(mouse, timed_out, ++attempt, &event, text_mode);
+               if (rslt != MOUSE_NO_DATA) {
+                  /* pass it to the client or to the default handler,
+                   * or to the selection handler
+                   */
+                  if (event.vc > MAX_VC) event.vc = 0; 
+                  if (event.vc == 0 || !cinfo[event.vc] || !do_client(cinfo[event.vc], &event))
+                     if (!cinfo[0] || !do_client(cinfo[0], &event))
+                        do_selection(&event, mouse->options.three_button);
+               }
+            } while (rslt == MOUSE_MORE_DATA);
+         }
       }
 
       /*..................... got connection, process it */
-
-      if (pending && FD_ISSET(ctlfd,&selSet)) {
-         FD_CLR(ctlfd,&selSet); pending--;
-         newfd=processConn(ctlfd);
-         if (newfd>=0) {
-            FD_SET(newfd,&connSet);
-            FD_SET(newfd,&readySet);
-            maxfd=max(maxfd,newfd);
+      if (pending && FD_ISSET(ctlfd, &selSet)) {
+         FD_CLR(ctlfd, &selSet); 
+         pending--;
+         if ((ci = accept_client_connection(ctlfd))) {
+            if (ci->data.eventMask & GPM_MOVE) {
+               Gpm_Event e = { 0, 0, ci->data.vc, 0, 0, 
+                               event.x, event.y, GPM_MOVE, 0, 0 };
+               do_client(ci, &e);
+            }
+            FD_SET(ci->fd, &connSet);
+            maxfd = max(maxfd, ci->fd);
          }
       }
 
       /*........................ got request */
-
-     /* itz 10-22-96 check _all_ clients, not just those on top! */
-      for (i=0; pending && (i<=MAX_VC); i++) {
-         Gpm_Cinfo* ci;
+      /* itz 10-22-96 check _all_ clients, not just those on top! */
+      for (i = 0; pending && i <= MAX_VC; i++) {
          for (ci = cinfo[i]; pending && ci; ci = ci->next) {
-            if (FD_ISSET(ci->fd,&selSet)) {
-               FD_CLR(ci->fd,&selSet); pending--;
-           /* itz Sat Sep 12 21:10:22 PDT 1998 */
-           /* this code is clearly incorrect; the next highest
-              descriptor after the one we're closing is not necessarily
-              being used.  Fortunately, it doesn't hurt simply to leave this
-              out. */
-
-#ifdef NOTDEF
-               if ((processRequest(ci,i)==-1) && maxfd==ci->fd) maxfd--;
-#else
-               (void)processRequest(ci,i);
-#endif
+            if (FD_ISSET(ci->fd, &selSet)) {
+               FD_CLR(ci->fd, &selSet); 
+               pending--;
+               if (!process_client_request(ci, i, event.x, event.y, event.clicks,
+                                           event.buttons, micelist->options.three_button)) {
+                  FD_CLR(ci->fd, &connSet);
+                  remove_client(ci, i);
+               }
             }
          }
       }
 
       /*.................. look for a spare fd */
-
       /* itz 10-22-96 this shouldn't happen now! */
-      for (i=0; pending && i<=maxfd; i++) {
-         if (FD_ISSET(i,&selSet)) {
-            FD_CLR(i,&selSet);
+      for (i = 0; pending && i <= maxfd; i++) {
+         if (FD_ISSET(i, &selSet)) {
+            FD_CLR(i, &selSet);
             pending--;
-            gpm_report(GPM_PR_WARN,GPM_MESS_STRANGE_DATA,i);
+            gpm_report(GPM_PR_WARN, GPM_MESS_STRANGE_DATA,i);
          }
       }
         
       /*................... all done. */
-     
-     if(pending) gpm_report(GPM_PR_OOPS,GPM_MESS_SELECT_PROB);
+      if (pending) gpm_report(GPM_PR_OOPS, GPM_MESS_SELECT_PROB);
    } /* while(1) */
 }
diff -urN gpm-1.20.1/src/gpn.c gpm/src/gpn.c
--- gpm-1.20.1/src/gpn.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/gpn.c	2003-10-02 01:22:42.000000000 -0500
@@ -28,201 +28,104 @@
 #include <stdlib.h>
 #include <string.h>        /* strerror(); ?!? memcpy() */
 #include <ctype.h>         /* isdigit */
-#include <signal.h>
-#include <stdarg.h>        /* Log uses it */
-#include <errno.h>
 #include <unistd.h>        /* getopt(),symlink() */
-#include <sys/stat.h>      /* mkdir()  */
-#include <sys/param.h>
-#include <sys/time.h>      /* timeval */
-#include <sys/wait.h>      /* wait() */
-#include <sys/types.h>     /* socket() */
-#include <sys/socket.h>    /* socket() */
-#include <sys/un.h>        /* struct sockaddr_un */
-#include <asm/types.h>     /* __u32  */
-
-#ifdef	SIGTSTP		/* true if BSD system */
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#endif
-
-#ifndef HAVE___U32
-# ifndef _I386_TYPES_H /* /usr/include/asm/types.h */
-typedef unsigned int __u32;
-# endif
-#endif
 
 #include "headers/message.h"
 #include "headers/gpmInt.h"
 #include "headers/gpm.h"
+#include "headers/console.h"
+#include "headers/selection.h"
 
-extern int errno;
-
-/*===================================================================*/
-/* octal digit */
-static int isodigit(const unsigned char c)
+/* usage: display for usage informations */
+int usage(char *whofailed)
 {
-   return ((c & ~7) == '0');
+   if (whofailed) {
+      gpm_report(GPM_PR_ERR, GPM_MESS_SPEC_ERR, whofailed, option.progname);
+      return 1;
+   }
+   printf(GPM_MESS_USAGE, option.progname, DEF_ACCEL, DEF_BAUD, DEF_SEQUENCE,
+          DEF_DELTA, DEF_TIME, DEF_LUT, DEF_SCALE, DEF_SAMPLE, DEF_TYPE);
+   return 1;
 }
 
-/* routine to convert digits from octal notation (Andries Brouwer) */
-static int getsym(const unsigned char *p0, unsigned char *res)
+/*****************************************************************************
+ * the function returns a valid type pointer or NULL if not found
+ *****************************************************************************/
+static struct Gpm_Type *find_mouse_by_name(char *name)
 {
-   const unsigned char *p = p0;
-   char c;
+   Gpm_Type *type;
+   char *s;
+   int len = strlen(name);
 
-   c = *p++;
-   if (c == '\\' && *p) {
-      c = *p++;
-      if (isodigit(c)) {
-         c -= '0';
-         if (isodigit(*p)) c = 8*c + (*p++ - '0');
-         if (isodigit(*p)) c = 8*c + (*p++ - '0');
+   for (type = mice; type->fun; type++) {
+      if (!strcasecmp(name, type->name)) break;
+      /* otherwise, look in the synonym list */
+      for (s = type->synonyms; s; s = strchr(s, ' ')) {
+         while (*s && isspace(*s)) s++; /* skip spaces */
+         if (!strncasecmp(name, s, len) && !isprint(*(s + len))) break;/*found*/
       }
+   	if (s) break; /* found a synonym */
    }
-   *res = c;
-   return (p - p0);
+   return type->fun ? type : NULL;
 }
 
-/* description missing! FIXME */
-int loadlut(char *charset)
+static void init_button_sequence(struct miceopt *opt, char *arg)
 {
-   int i, c, fd;
-   unsigned char this, next;
-   static __u32 long_array[9]={
-      0x05050505, /* ugly, but preserves alignment */
-      0x00000000, /* control chars     */
-      0x00000000, /* digits            */
-      0x00000000, /* uppercase and '_' */
-      0x00000000, /* lowercase         */
-      0x00000000, /* Latin-1 control   */
-      0x00000000, /* Latin-1 misc      */
-      0x00000000, /* Latin-1 uppercase */
-      0x00000000  /* Latin-1 lowercase */
+	int i;
+   static struct {
+      char *in;
+      char *out;
+   } seq[] = {
+      {"123", "01234567"},
+      {"132", "02134657"},
+      {"213", "01452367"}, /* warning: these must be readable as integers... */
+      {"231", "02461357"},
+      {"312", "04152637"},
+      {"321", "04261537"},
+      {NULL, NULL}
    };
 
+	if (strlen(arg) != 3 || atoi(arg) < 100)
+		exit(usage("sequence"));
 
-#define inwordLut (long_array+1)
-
-   for (i=0; charset[i]; ) {
-      i += getsym(charset+i, &this);
-      if (charset[i] == '-' && charset[i + 1] != '\0')
-         i += getsym(charset+i+1, &next) + 1;
-      else
-         next = this;
-      for (c = this; c <= next; c++)
-         inwordLut[c>>5] |= 1 << (c&0x1F);
-   }
-  
-   if ((fd=open(option.consolename, O_WRONLY)) < 0) {
-      /* try /dev/console, if /dev/tty0 failed -- is that really senseful ??? */
-      free(option.consolename); /* allocated by main */
-      if((option.consolename=malloc(strlen(GPM_SYS_CONSOLE)+1)) == NULL)
-         gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM);
-      strcpy(option.consolename,GPM_SYS_CONSOLE);
-     
-      if ((fd=open(option.consolename, O_WRONLY)) < 0) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN_CON);
-   }
-   if (ioctl(fd, TIOCLINUX, &long_array) < 0) { /* fd <0 is checked */
-      if (errno==EPERM && getuid())
-         gpm_report(GPM_PR_WARN,GPM_MESS_ROOT); /* why do we still continue?*/
-      else if (errno==EINVAL)
-         gpm_report(GPM_PR_OOPS,GPM_MESS_CSELECT);
-   }
-   close(fd);
-
-   return 0;
+	for (i = 0; seq[i].in && strcmp(seq[i].in, arg); i++);
+   if (!seq[i].in) 
+		exit(usage("button sequence"));
+   opt->sequence = strdup(seq[i].out); /* I can rewrite on it */
 }
 
-/* usage: display for usage informations */
-int usage(char *whofailed)
+static void validate_mouse(struct micetab *mouse, int mouse_no)
 {
-   if (whofailed) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_SPEC_ERR,whofailed,option.progname);
-      return 1;
-   }
-   printf(GPM_MESS_USAGE,option.progname, DEF_ACCEL, DEF_BAUD, DEF_SEQUENCE,
-   DEF_DELTA, DEF_TIME, DEF_LUT,DEF_SCALE, DEF_SAMPLE, DEF_TYPE);
-   return 1;
-}
-
-/* itz Sat Sep 12 10:55:51 PDT 1998 Added this as replacement for the
-   unwanted functionality in check_uniqueness. */
-
-void check_kill(void)
-{
-   int old_pid;
-   FILE* fp = fopen(GPM_NODE_PID, "r");
-
-   /* if we cannot find the old pid file, leave */
-   if (fp == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN, GPM_NODE_PID);
-  
-   /* else read the pid */
-   if (fscanf(fp,"%d",&old_pid) != 1)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_READ_PROB,GPM_NODE_PID);
-   fclose(fp);
-
-   gpm_report(GPM_PR_DEBUG,GPM_MESS_KILLING,old_pid);
-
-   /* first check if we run */
-   if (kill(old_pid,0) == -1) {
-      gpm_report(GPM_PR_INFO,GPM_MESS_STALE_PID, GPM_NODE_PID);
-      unlink(GPM_NODE_PID);
+   if (!mouse->device) {
+      if (!mouse->type && mouse_no > 1)
+         gpm_report(GPM_PR_OOPS, 
+            "No device/protocol specified for mouse #%d, probably extra -M option?", mouse_no);
+      else
+         gpm_report(GPM_PR_OOPS, "No device specified for mouse #%d", mouse_no); 
    }
-   /* then kill us (not directly, but the other instance ... ) */
-   if (kill(old_pid,SIGTERM) == -1)
-      gpm_report(GPM_PR_OOPS,GPM_MESS_CANT_KILL, old_pid);
 
-   gpm_report(GPM_PR_INFO,GPM_MESS_KILLED,old_pid);
-   exit(0);
-}
+   if (!mouse->type)
+      mouse->type = find_mouse_by_name(DEF_TYPE);
 
-/* itz Sat Sep 12 10:30:05 PDT 1998 this function used to mix two
-   completely different things; opening a socket to a running daemon
-   and checking that a running daemon existed.  Ugly. */
-/* rewritten mostly on 20th of February 2002 - nico */   
-void check_uniqueness(void)
-{
-   FILE *fp    =  0;
-   int old_pid = -1;
+   mouse->options.absolute = mouse->type->absolute;
 
-   if((fp = fopen(GPM_NODE_PID, "r")) != NULL) {
-      fscanf(fp, "%d", &old_pid);
-      if (kill(old_pid,0) == -1) {
-         gpm_report(GPM_PR_INFO,GPM_MESS_STALE_PID, GPM_NODE_PID);
-         unlink(GPM_NODE_PID);
-      } else /* we are really running, exit asap! */ 
-         gpm_report(GPM_PR_OOPS,GPM_MESS_ALREADY_RUN, old_pid);
-   }
-   /* now try to sign ourself */
-   if ((fp = fopen(GPM_NODE_PID,"w")) != NULL) {
-      fprintf(fp,"%d\n",getpid());
-      fclose(fp);
-   } else {
-      gpm_report(GPM_PR_OOPS,GPM_MESS_NOTWRITE,GPM_NODE_PID);
-   }
+   if (!mouse->options.sequence)
+      init_button_sequence(&mouse->options, DEF_SEQUENCE);
 }
 
-/*****************************************************************************
- * the function returns a valid type pointer or NULL if not found
- *****************************************************************************/
-struct Gpm_Type *find_mouse_by_name(char *name)
+static void validate_repeater(char *type)
 {
-   Gpm_Type *type;
-   char *s;
-   int len = strlen(name);
-
-   for (type=mice; type->fun; type++) {
-      if (!strcasecmp(name, type->name)) break;
-      /* otherwise, look in the synonym list */
-      for (s = type->synonyms; s; s = strchr(s, ' ')) {
-         while (*s && isspace(*s)) s++; /* skip spaces */
-         if(!strncasecmp(name, s, len) && !isprint(*(s + len))) break;/*found*/
-      }
-   	if(s) break; /* found a synonym */
+   if (strcmp(type, "raw") == 0)
+      repeater.raw = 1;
+   else {
+      repeater.raw = 0; 
+      
+      if (!(repeater.type = find_mouse_by_name(type)))
+         exit(M_listTypes()); /* not found */
+ 
+      if (!repeater.type->repeat_fun) /* unsupported translation */
+         gpm_report(GPM_PR_OOPS, GPM_MESS_NO_REPEAT, type);
    }
-   if (!type->fun) return NULL;
-   return type;
 }
 
 /*****************************************************************************
@@ -230,60 +133,86 @@
  * Can't believe it, today cmdline() really does what the name tries to say
  *****************************************************************************/
 void cmdline(int argc, char **argv)
-{
-   extern struct options option;
+{  
+   struct micetab *mouse;
+   struct miceopt *opt;   
    char options[]="a:A::b:B:d:Dg:hi:kl:m:Mo:pr:R::s:S:t:TuvV::23";
-   int  opt;
+   int  opt_char, tmp;
+   int  mouse_no = 1;
+
+   mouse = add_mouse();
+   opt = &mouse->options;
 
-   /* initialize for the dual mouse */ 
-   mouse_table[2]=mouse_table[1]=mouse_table[0]; /* copy defaults */
-   which_mouse=mouse_table+1; /* use the first */
-
-   while ((opt = getopt(argc, argv, options)) != -1) {
-      switch (opt) {
-         case 'a': opt_accel = atoi(optarg);             break;
-         case 'A': opt_aged++;
-                   if (optarg)
-                     opt_age_limit = atoi(optarg);       break;
-         case 'b': opt_baud = atoi(optarg);              break;
-         case 'B': opt_sequence = optarg;                break;
-         case 'd': opt_delta = atoi(optarg);             break;
-         case 'D': option.run_status = GPM_RUN_DEBUG;    break;
-         case 'g': opt_glidepoint_tap=atoi(optarg);      break;
-         case 'h': exit(usage(NULL));
-         case 'i': opt_time=atoi(optarg);                break;
-         case 'k': check_kill();                         break;
-         case 'l': opt_lut = optarg;                     break;
-         case 'm': add_mouse(GPM_ADD_DEVICE,optarg);     
-                   opt_dev = optarg;                     break; /* GO AWAY!*/
-         case 'M': opt_double++; option.repeater++;
-            if (option.repeater_type == 0)
-               option.repeater_type = "msc";
-            which_mouse=mouse_table+2;                   break;
-         case 'o': add_mouse(GPM_ADD_OPTIONS,optarg);
-                   gpm_report(GPM_PR_DEBUG,"options: %s",optarg);
-                   opt_options = optarg;                 break; /* GO AWAY */
-         case 'p': opt_ptrdrag = 0;                      break;
-         case 'r':
-            /* being called responsiveness, I must take the inverse */
-            opt_scale=atoi(optarg);
-            if(!opt_scale || opt_scale > 100) opt_scale=100; /* the maximum */
-            else opt_scale=100/opt_scale;                break;
-         case 'R':
-            option.repeater++;
-            if (optarg) option.repeater_type = optarg;
-            else        option.repeater_type = "msc";    break;
-         case 's': opt_sample = atoi(optarg);            break;
-         case 'S': if (optarg) opt_special = optarg;
-                   else opt_special="";                  break;
-         case 't': add_mouse(GPM_ADD_TYPE,optarg);
-                   opt_type = optarg;                    break; /* GO AWAY */
-         case 'u': option.autodetect = 1;                break;
-         case 'T': opt_test++;                           break;
-         case 'v': printf(GPM_MESS_VERSION "\n");        exit(0);
-         case '2': opt_three = -1;                       break;
-         case '3': opt_three =  1;                       break;
-         default: exit(usage("commandline"));
+   while ((opt_char = getopt(argc, argv, options)) != -1) {
+      switch (opt_char) {
+         case 'a':   if ((opt->accel = atoi(optarg)) < 1)
+                        exit(usage("acceleration"));
+                     break;
+         case 'A':   sel_opts.aged = 1;
+                     if (optarg)
+                        sel_opts.age_limit = atoi(optarg); 
+                     break;
+         case 'b':   opt->baud = atoi(optarg);
+                     break;
+         case 'B':   init_button_sequence(opt, optarg);
+                     break;
+         case 'd':   if ((opt->delta = atoi(optarg)) < 2)
+                        exit(usage("delta"));
+                     break;
+         case 'D':   option.run_status = GPM_RUN_DEBUG;
+                     break;
+         case 'g':   if (atoi(optarg) > 3)
+                        exit(usage("glidepoint tap button"));
+                     opt->glidepoint_tap = GPM_B_LEFT >> (atoi(optarg) - 1);
+                     break;
+         case 'h':   exit(usage(NULL));
+         case 'i':   opt->time = atoi(optarg);
+                     break;
+         case 'k':   kill_gpm();
+                     break;
+         case 'l':   console.charset = optarg;
+                     break;
+         case 'm':   mouse->device = optarg;     
+                     break;
+         case 'M':   validate_mouse(mouse, mouse_no);
+                     mouse = add_mouse();
+                     opt = &mouse->options;
+                     mouse_no++;
+                     if (!repeater.type && !repeater.raw)
+                        repeater.type = find_mouse_by_name(DEF_REP_TYPE);
+                     break;
+         case 'o':   gpm_report(GPM_PR_DEBUG,"options: %s", optarg);
+                     opt->text = optarg;
+                     break;
+         case 'p':   sel_opts.ptrdrag = 0;
+                     break;
+         case 'r':   /* being called responsiveness, I must take the inverse */
+                     tmp = atoi(optarg);
+                     if (!tmp || tmp > 100) tmp = 1;
+                     opt->scalex = 100 / tmp;
+                     break;
+         case 'R':   validate_repeater((optarg) ? optarg : DEF_REP_TYPE);
+                     break;
+         case 's':   opt->sample = atoi(optarg);
+                     break;
+         case 'S':   if (optarg) opt_special = optarg;
+                     else opt_special="";
+                     break;
+         case 't':   mouse->type = find_mouse_by_name(optarg);
+                     if (!mouse->type)
+                        exit(M_listTypes());
+                     break;
+         case 'u':   option.autodetect = 1;
+                     break;
+         case 'v':   printf(GPM_MESS_VERSION "\n");
+                     exit(0);
+         case '2':   opt->three_button = -1;
+                     break;
+         case '3':   opt->three_button = 1;
+                     break;
+         default:    exit(usage("commandline"));
       }
    }
+   
+   validate_mouse(micelist, mouse_no);
 }
diff -urN gpm-1.20.1/src/headers/client.h gpm/src/headers/client.h
--- gpm-1.20.1/src/headers/client.h	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/headers/client.h	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,57 @@
+/* -*-mode:C;tab-width:3-*-
+ * client.h - GPM client handling (server side)
+ *
+ * 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_CLIENT_H
+#define __GPM_CLIENT_H_
+
+#ifdef HAVE_LINUX_TTY_H
+#include <linux/tty.h>
+#endif
+
+#include "headers/gpm.h"
+
+/* FIXME: still needed ?? */
+/* How many virtual consoles are managed? */
+#ifndef MAX_NR_CONSOLES
+#  define MAX_NR_CONSOLES 64 /* this is always sure */
+#endif
+
+#define MAX_VC    MAX_NR_CONSOLES  /* doesn't work before 1.3.77 */
+
+struct client_info {
+  Gpm_Connect data;
+  int fd;
+  struct client_info *next;
+};
+
+struct Gpm_Event;
+
+extern struct client_info *cinfo[MAX_VC + 1];
+
+int   listen_for_clients(void);
+struct client_info *accept_client_connection(int fd);
+void  remove_client(struct client_info *ci, int vc);
+void  notify_clients_resize(void);
+int   do_client(struct client_info *cinfo, struct Gpm_Event *event);
+int   process_client_request(struct client_info *ci, int vc,
+                             int x, int y, int buttons, int clicks,
+                             int three_button_mouse);
+
+#endif /* __GPM_CLIENT_H_ */
diff -urN gpm-1.20.1/src/headers/console.h gpm/src/headers/console.h
--- gpm-1.20.1/src/headers/console.h	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/headers/console.h	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,42 @@
+/* -*-mode:C;tab-width:3-*-
+ * console.h - GPM console and selection/paste handling
+ *
+ * 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_CONSOLE_H_
+#define __GPM_CONSOLE_H_
+
+struct gpm_console {
+   char  *device;
+   char  *charset;
+   int   max_x, max_y;
+};
+
+extern struct gpm_console console;
+
+int   open_console(int mode);
+char  *get_console_name();
+char  *compose_vc_name(int vc);
+int   is_text_console(void);
+void  wait_text_console(void);
+void  refresh_console_size(void);
+int   is_console_owner(int vc, uid_t uid);
+int   get_console_state(unsigned char *shift_state);
+void  console_load_lut(void);
+
+#endif /* __GPM_CONSOLE_H_ */
diff -urN gpm-1.20.1/src/headers/gpmInt.h gpm/src/headers/gpmInt.h
--- gpm-1.20.1/src/headers/gpmInt.h	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/headers/gpmInt.h	2003-10-02 01:22:42.000000000 -0500
@@ -23,8 +23,7 @@
 #ifndef _GPMINT_INCLUDED
 #define _GPMINT_INCLUDED
 
-#include <sys/types.h>          /* time_t */ /* for whom ????  FIXME */
-
+#include <sys/time.h>   /* timeval */
 #include "gpm.h"
 
 #if !defined(__GNUC__)
@@ -35,23 +34,12 @@
 /* timeout for the select() syscall */
 #define SELECT_TIME 86400 /* one day */
 
-#ifdef HAVE_LINUX_TTY_H
-#include <linux/tty.h>
-#endif
-
-/* FIXME: still needed ?? */
-/* How many virtual consoles are managed? */
-#ifndef MAX_NR_CONSOLES
-#  define MAX_NR_CONSOLES 64 /* this is always sure */
-#endif
-
-#define MAX_VC    MAX_NR_CONSOLES  /* doesn't work before 1.3.77 */
-
 /* How many buttons may the mouse have? */
 /* #define MAX_BUTTONS 3  ===> not used, it is hardwired :-( */
 
 /* all the default values */
 #define DEF_TYPE          "ms"
+#define DEF_REP_TYPE     "msc"
 #define DEF_DEV           NULL     /* use the type-related one */
 #define DEF_LUT   "-a-zA-Z0-9_./\300-\326\330-\366\370-\377"
 #define DEF_SEQUENCE     "123"     /* how buttons are reordered */
@@ -62,12 +50,10 @@
 #define DEF_SCALE           10
 #define DEF_TIME           250    /* time interval (ms) for multiple clicks */
 #define DEF_THREE            0    /* have three buttons? */
-#define DEF_KERNEL           0    /* no kernel module, by default */
 
 /* 10 on old computers (<=386), 0 on current machines */
 #define DEF_CLUSTER          0    /* maximum number of clustered events */
 
-#define DEF_TEST             0
 #define DEF_PTRDRAG          1    /* double or triple click */
 #define DEF_GLIDEPOINT_TAP   0    /* tapping emulates no buttons by default */
 
@@ -84,11 +70,6 @@
 #define GPM_DEVFS_CONSOLE    "/dev/vc/0"
 #define GPM_OLD_CONSOLE      "/dev/tty0"
 
-/* for adding a mouse; add_mouse */
-#define GPM_ADD_DEVICE        0
-#define GPM_ADD_TYPE          1
-#define GPM_ADD_OPTIONS       2
-
 /*** mouse commands ***/ 
 
 #define GPM_AUX_SEND_ID    0xF2
@@ -117,126 +98,95 @@
 
 /*....................................... Structures */
 
+struct micedev {
+   int   fd;
+   int   timeout;             /* the protocol driver wants to be called 
+                                 after X msec even if there is no new data
+                                 arrived (-1 to disable/default) */
+   void  *private;            /* private data maintained by protocol driver */
+};
+
+struct miceopt {
+   char  *sequence;
+   int   baud;
+   int   sample;
+   int   delta;
+   int   accel;
+   int   scalex, scaley;
+   int   time;
+   int   cluster;
+   int   three_button;
+   int   glidepoint_tap;
+   int   absolute;         /* device reports absolute coordinates - initially copied 
+                              from Gpm_Type; allows same protocol (type) control devices
+                              in absolute and relative mode */  
+   char  *text;            /* extra textual options supplied via '-o text' */   
+};
+
 /*
  * and this is the entry in the mouse-type table
  */
 typedef struct Gpm_Type {
-  char *name;
-  char *desc;             /* a descriptive line */
-  char *synonyms;         /* extra names (the XFree name etc) as a list */
-  int (*fun)(Gpm_Event *state, unsigned char *data);
-  struct Gpm_Type *(*init)(int fd, unsigned short flags,
-			   struct Gpm_Type *type, int argc, char **argv);
-  unsigned short flags;
-  unsigned char proto[4];
-  int packetlen;
-  int howmany;            /* how many bytes to read at a time */
-  int getextra;           /* does it get an extra byte? (only mouseman) */
-  int absolute;           /* flag indicating absolute pointing device */
+   char *name;
+   char *desc;             /* a descriptive line */
+   char *synonyms;         /* extra names (the XFree name etc) as a list */
+   int (*fun)(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state);
+   int (*init)(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type);
+   unsigned short flags;
+   unsigned char proto[4];
+   int packetlen;
+   int howmany;            /* how many bytes to read at a time */
+   int getextra;           /* does it get an extra byte? (only mouseman) */
+   int absolute;           /* flag indicating absolute pointing device */
 
-  int (*repeat_fun)(Gpm_Event *state, int fd); /* repeat this event into fd */
+   int (*repeat_fun)(Gpm_Event *state, int fd); /* repeat this event into fd */
                           /* itz Mon Jan 11 23:27:54 PST 1999 */
 }                   Gpm_Type;
 
 #define GPM_EXTRA_MAGIC_1 0xAA
 #define GPM_EXTRA_MAGIC_2 0x55
 
-typedef struct Gpm_Cinfo {
-  Gpm_Connect data;
-  int fd;
-  struct Gpm_Cinfo *next;
-}              Gpm_Cinfo;
-
-
-/*....................................... Global variables */
-
-/* this structure is used to hide the dual-mouse stuff */
-
-struct mouse_features {
-  char *opt_type, *opt_dev, *opt_sequence;
-  int opt_baud,opt_sample,opt_delta, opt_accel, opt_scale, opt_scaley;
-  int opt_time, opt_cluster, opt_three, opt_glidepoint_tap;
-  char *opt_options; /* extra textual configuration */
-  Gpm_Type *m_type;
-  int fd;
-};
-
-extern struct mouse_features mouse_table[3], *which_mouse; /*the current one*/
-
-// looks unused; delete
-//typedef struct Opt_struct_type {int a,B,d,i,p,r,V,A;} Opt_struct_type;
-
-/* this is not very clean, actually, but it works fine */
-#define opt_type     (which_mouse->opt_type)
-#define opt_dev      (which_mouse->opt_dev)
-#define opt_sequence (which_mouse->opt_sequence)
-#define opt_baud     (which_mouse->opt_baud)
-#define opt_sample   (which_mouse->opt_sample)
-#define opt_delta    (which_mouse->opt_delta)
-#define opt_accel    (which_mouse->opt_accel)
-#define opt_scale    (which_mouse->opt_scale)
-#define opt_scaley   (which_mouse->opt_scaley)
-#define opt_time     (which_mouse->opt_time)
-#define opt_cluster  (which_mouse->opt_cluster)
-#define opt_three    (which_mouse->opt_three)
-#define opt_glidepoint_tap (which_mouse->opt_glidepoint_tap)
-#define opt_options  (which_mouse->opt_options)
-
-#define m_type       (which_mouse->m_type)
-
-/* the other variables */
-
-extern char *opt_lut;
-extern int opt_test, opt_ptrdrag;
-extern int opt_kill;
-extern int opt_kernel, opt_explicittype;
-extern int opt_aged;
-extern time_t opt_age_limit;
 extern char *opt_special;
-extern int opt_rawrep;
-extern int fifofd;
-extern int opt_double;
-
-extern Gpm_Type *repeated_type;
 extern Gpm_Type mice[];             /* where the hell are the descriptions...*/
-extern struct winsize win;
-extern int maxx, maxy;
-extern Gpm_Cinfo *cinfo[MAX_VC+1];
 
 /* new variables <CLEAN> */
 
 /* structure prototypes */
+struct repeater {
+   int      fd;
+   int      raw;
+   Gpm_Type *type;
+};
 
 /* contains all mice */
 struct micetab {
    struct micetab *next;
-   char *device;
-   char *protocol;
-   char *options;
+   struct micedev dev;
+   struct miceopt options;
+   Gpm_Type       *type;
+   char           *device;
+   int            buttons;    /* mouse's button state from last read */
+   struct timeval timestamp;  /* last time mouse data arrived */ 
 };  
 
 struct options {
    int autodetect;            /* -u [aUtodetect..'A' is not available] */
-   int no_mice;               /* number of mice */
-   int repeater;              /* repeat data */
-   char *repeater_type;       /* repeat data as which mouse type */
    int run_status;            /* startup/daemon/debug */
    char *progname;            /* hopefully gpm ;) */
-   struct micetab *micelist;  /* mice and their options */
-   char *consolename;         /* /dev/tty0 || /dev/vc/0 */
 };
 
 /* global variables */
 struct options option;        /* one should be enough for us */
+extern struct repeater repeater; /* again, only one */
+extern struct micetab *micelist;
 
 /* new variables </CLEAN> */
 
-
 /*....................................... Prototypes */
          /* server_tools.c */
-void add_mouse (int type, char *value);
-int  init_mice (struct micetab *micelist);
-int  reset_mice(struct micetab *micelist);
+struct micetab *add_mouse(void);
+void init_mice(void);
+void cleanup_mice(void);
 
          /* startup.c */
 void startup(int argc, char **argv);
@@ -246,17 +196,15 @@
 
        /* gpn.c */
 void cmdline(int argc, char **argv);
-int giveInfo(int request, int fd);
-int loadlut(char *charset);
-int usage(char *whofailed);
-struct Gpm_Type *find_mouse_by_name(char *name);
+int  giveInfo(int request, int fd);
+int  usage(char *whofailed);
 void check_uniqueness(void);
-void check_kill(void);
-
+void kill_gpm(void);
 
        /* mice.c */
 extern int M_listTypes(void);
-       /* special.c */
+
+      /* special.c */
 int processSpecial(Gpm_Event *event);
 int twiddler_key(unsigned long message);
 int twiddler_key_init(void);
diff -urN gpm-1.20.1/src/headers/input-defines.h gpm/src/headers/input-defines.h
--- gpm-1.20.1/src/headers/input-defines.h	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/headers/input-defines.h	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,81 @@
+/*
+ * input-defines.h - complements <linux/input.h> adding missing bits
+ *
+ * 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_INPUT_DEFINES_H
+#define __GPM_INPUT_DEFINES_H
+
+#include <linux/input.h>
+#include "headers/config.h"
+
+#ifndef ABS_TOOL_WIDTH  
+#define ABS_TOOL_WIDTH        0x1c
+#endif
+
+#ifndef BTN_TOOL_FINGER  
+#define BTN_TOOL_FINGER       0x145
+#endif
+
+#ifndef BTN_TOUCH  
+#define BTN_TOUCH             0x14a
+#endif
+
+#ifndef BTN_TOOL_DOUBLETAP  
+#define BTN_TOOL_DOUBLETAP    0x14d
+#endif
+
+#ifndef BTN_TOOL_TRIPLETAP  
+#define BTN_TOOL_TRIPLETAP    0x14e
+#endif
+
+#ifndef MSC_GESTURE
+#define MSC_GESTURE           2
+#endif
+
+#ifndef EV_SYNC     
+#define EV_SYNC               0
+#endif
+
+#ifndef SYN_REPORT 
+#define SYN_REPORT            0
+#endif
+
+#ifndef PSMOUSE_SYNAPTICS
+#define PSMOUSE_SYNAPTICS     7
+#endif
+
+#ifndef HAVE_INPUT_ID
+struct input_id {
+   unsigned short bustype;
+   unsigned short vendor;
+   unsigned short product;
+   unsigned short version;
+};
+#endif
+
+#ifndef HAVE_INPUT_ABSINFO
+struct input_absinfo {
+   int value;
+   int minimum;
+   int maximum;
+   int fuzz;
+   int flat;
+};
+#endif
+
+#endif
diff -urN gpm-1.20.1/src/headers/message.h gpm/src/headers/message.h
--- gpm-1.20.1/src/headers/message.h	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/headers/message.h	2003-10-02 01:22:42.000000000 -0500
@@ -96,7 +96,6 @@
          "    -S [commands]    enable special commands (see man page)\n" \
          "    -t mouse-type    sets mouse type (default '%s')\n" \
          "                     Use a non-existent type (e.g. \"help\") to get a list\n" \
-         "    -T               test: read mouse, no clients\n" \
          "    -v               print version and exit\n" \
          "    -V verbosity     increase number of logged messages\n\n\n" \
          "    Examples:\n\n" \
@@ -168,7 +167,8 @@
 #define GPM_MESS_SELECT_TIMES       "selected %i times"
 
 #define GPM_MESS_OPTION_NO_ARG      "%s: Option \"%s\" takes no argument: ignoring \"%s\""
-#define GPM_MESS_INVALID_ARG        "%s: Invalid arg. \"%s\" to \"%s\""
+#define GPM_MESS_INVALID_ARG        "%s: Invalid argument \"%s\" for option \"%s\""
+#define GPM_MESS_MISSING_ARG        "%s: Option \"%s\" requires an argument"
 #define GPM_MESS_CONT_WITH_ERR      "%s: Continuing despite errors in option parsing"
 #define GPM_MESS_TOO_MANY_OPTS      "%s: Too many options for \"-t %s\""
 
@@ -196,7 +196,7 @@
 
 /* warnings */
 #define GPM_MESS_REQUEST_ON         "Request on vc %i > %i"
-#define GPM_MESS_FAILED_CONNECT     "Failed gpm connect attempt by uid %d for vc %s"
+#define GPM_MESS_FAILED_CONNECT     "Failed gpm connect attempt by uid %d for vc %d"
 #define GPM_MESS_ZERO_SCREEN_DIM    "zero screen dimension, assuming 80x25"
 #define GPM_MESS_STRANGE_DATA       "Data on strange file descriptor %d"
 #define GPM_MESS_RESIZING           "%s pid %i is resizing :-)"
diff -urN gpm-1.20.1/src/headers/optparser.h gpm/src/headers/optparser.h
--- gpm-1.20.1/src/headers/optparser.h	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/headers/optparser.h	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,50 @@
+/*
+ * optparser.h - GPM mouse options parser 
+ *
+ * Copyright (C) 1993        Andrew Haylett <ajh@gec-mrc.co.uk>
+ * 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
+ *   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_OPTPARSER_H_
+#define __GPM_OPTPARSER_H_
+
+enum option_type {
+   OPT_BOOL = 1,
+   OPT_INT, /* "%i" */
+   OPT_DEC, /* "%d" */
+   OPT_STRING,
+   /* other types must be added */
+   OPT_END = 0
+};
+
+struct option_helper {
+   char *name;
+   enum option_type type;
+   union u {
+      int *iptr;   /* used for int and bool arguments */
+      char **sptr; /* used for string arguments, by strdup()ing the value */
+   } u;
+   int value; /* used for boolean arguments */
+   int present;
+};
+
+int   parse_options(const char *who, const char *opt, char sep, struct option_helper *info);
+int   check_no_options(const char *proto, const char *opts, char sep);
+int   is_option_present(struct option_helper *info, const char *name);
+#endif
diff -urN gpm-1.20.1/src/headers/selection.h gpm/src/headers/selection.h
--- gpm-1.20.1/src/headers/selection.h	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/headers/selection.h	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,37 @@
+/* 
+ * console.h - GPM selection/paste handling
+ *
+ * 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_SELECTION_H_
+#define __GPM_SELECTION_H_
+
+struct sel_options {
+   int      aged;
+   int      age_limit;
+   int      ptrdrag;
+};
+
+struct Gpm_Event;
+
+extern struct sel_options sel_opts; /* only one exists */
+
+void  do_selection(struct Gpm_Event *event, int three_button_mode);
+void  selection_disable_paste(void);
+
+#endif /* __GPM_CONSOLE_H_ */
diff -urN gpm-1.20.1/src/headers/synaptics.h gpm/src/headers/synaptics.h
--- gpm-1.20.1/src/headers/synaptics.h	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/headers/synaptics.h	2003-10-02 01:22:42.000000000 -0500
@@ -62,7 +62,7 @@
 **
 ** Process the touchpad 6/7/8 byte data.
 */
-void syn_process_serial_data (Gpm_Event *state,
+void syn_process_serial_data (int fd, Gpm_Event *state,
 			      unsigned char *data);
 
 
@@ -72,7 +72,7 @@
 **
 ** Process the touchpad 6 byte data.
 */
-void syn_process_ps2_data (Gpm_Event *state,
+void syn_process_ps2_data (int fd, Gpm_Event *state,
 			   unsigned char *data);
 
 
diff -urN gpm-1.20.1/src/lib/liblow.c gpm/src/lib/liblow.c
--- gpm-1.20.1/src/lib/liblow.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/lib/liblow.c	2003-10-02 01:22:42.000000000 -0500
@@ -80,6 +80,8 @@
 int gpm_consolefd=-1;  /* used to invoke ioctl() */
 int gpm_morekeys=0;
 
+static char *consolename;
+ 
 int gpm_convert_event(unsigned char *mdata, Gpm_Event *ePtr);
 
 /*----------------------------------------------------------------------------*
@@ -192,14 +194,13 @@
    char *tty = NULL;
    char *term = NULL;
    int i;
-   extern struct options option;
    static int checked_con = 0;
    struct sockaddr_un addr;
    struct winsize win;
    Gpm_Stst *new = NULL;
    char* sock_name = 0;
 
-   option.consolename = NULL;
+   consolename = NULL;
 
    gpm_report(GPM_PR_DEBUG,"VC: %d",flag);
 
@@ -216,7 +217,7 @@
 
    /* check whether we know what name the console is: what's with the lib??? */
    if(checked_con == 0) {
-      option.consolename = Gpm_get_console();
+      consolename = Gpm_get_console();
       checked_con++;
    }   
 
@@ -245,10 +246,10 @@
       conn->vc=0;                 /* default handler */
       if (flag > 0) {  /* forced vc number */
          conn->vc=flag;
-         if((tty = malloc(strlen(option.consolename)+Gpm_cnt_digits(flag))) == NULL)
+         if((tty = malloc(strlen(consolename)+Gpm_cnt_digits(flag))) == NULL)
             gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM);
-         memcpy(tty,option.consolename,strlen(option.consolename)-1);
-         sprintf(&tty[strlen(option.consolename)-1],"%i",flag);
+         memcpy(tty,consolename,strlen(consolename)-1);
+         sprintf(&tty[strlen(consolename)-1],"%i",flag);
       } else { /* use your current vc */ 
          if (isatty(0)) tty = ttyname(0);             /* stdin */
          if (!tty && isatty(1)) tty = ttyname(1);     /* stdout */
@@ -258,13 +259,13 @@
             goto err;
          }   
          /* do we really need this check ? */
-         if(strncmp(tty,option.consolename,strlen(option.consolename)-1)
-            || !isdigit(tty[strlen(option.consolename)-1])) {
-            gpm_report(GPM_PR_ERR,"strncmp/isdigit/option.consolename failed");
+         if(strncmp(tty,consolename,strlen(consolename)-1)
+            || !isdigit(tty[strlen(consolename)-1])) {
+            gpm_report(GPM_PR_ERR,"strncmp/isdigit/consolename failed");
             goto err;
          }
           
-         conn->vc=atoi(&tty[strlen(option.consolename)-1]);
+         conn->vc=atoi(&tty[strlen(consolename)-1]);
       }
 
       if (gpm_consolefd == -1)
@@ -272,6 +273,8 @@
             gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,tty,strerror(errno));
             goto err;
          }
+
+      if (flag > 0) free(tty);
    }
 
    new->info=*conn;
diff -urN gpm-1.20.1/src/lib/tools.c gpm/src/lib/tools.c
--- gpm-1.20.1/src/lib/tools.c	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/lib/tools.c	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,93 @@
+/*
+ * tools.c - tools which are needed by client and server
+ *
+ * Copyright (c) 2001 	     Nico Schottelius <nico@schottelius.org>
+ *
+ *   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 <stdio.h> /* NULL */
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>  /* these three are */
+#include <sys/stat.h>   /* needed for      */
+#include <unistd.h>     /* stat() */
+
+#include "headers/gpmInt.h"   /* only used for some defines */
+#include "headers/message.h"
+
+/*****************************************************************************
+ * check, whether devfs is used or not.
+ * See /usr/src/linux/Documentation/filesystems/devfs/ for details.
+ * Returns: the name of the console (/dev/tty0 or /dev/vc/0)
+ *****************************************************************************/
+char *Gpm_get_console( void )
+{
+
+   char *back = NULL, *tmp = NULL;
+   struct stat buf;
+
+   /* first try the devfs device, because in the next time this will be
+    * the preferred one. If that fails, take the old console */
+   
+   /* Check for open new console */
+   if (stat(GPM_DEVFS_CONSOLE,&buf) == 0)
+      tmp = GPM_DEVFS_CONSOLE;
+  
+   /* Failed, try OLD console */
+   else if(stat(GPM_OLD_CONSOLE,&buf) == 0)
+      tmp = GPM_OLD_CONSOLE;
+  
+   if(tmp != NULL)
+      if((back = malloc(strlen(tmp) + sizeof(char)) ) != NULL)
+         strcpy(back,tmp);
+
+   return(back);
+}
+
+/* what's the english name for potenz ? */
+int Gpm_x_high_y(int base, int pot_y)
+{
+   int val = 1;
+   
+   if(pot_y == 0) val = 1;
+   else if(pot_y  < 0) val = 0;     /* ugly hack ;) */
+   else while(pot_y > 0) {
+      val = val * base;
+      pot_y--;
+   }   
+   return val;
+}   
+      
+/* return characters needed to display int */
+int Gpm_cnt_digits(int number)
+{
+   /* 0-9 = 1        10^0 <-> (10^1)-1
+    * 10 - 99 = 2    10^1 <-> (10^2)-1
+    * 100 - 999 = 3  10^2 <-> (10^3)-1
+    * 1000 - 9999 = 4 ...  */
+   
+   int ret = 0, num = 0;
+
+   /* non negative, please */
+   if(number < 0) number *= -1;
+   else if(number == 0) ret = 1;
+   else while(number > num) {
+      ret++;
+      num = (Gpm_x_high_y(10,ret) - 1);
+   }   
+
+   return(ret);
+}      
diff -urN gpm-1.20.1/src/Makefile.in gpm/src/Makefile.in
--- gpm-1.20.1/src/Makefile.in	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/Makefile.in	2003-10-02 01:22:42.000000000 -0500
@@ -12,15 +12,16 @@
 include $(top_builddir)/Makefile.include
 
 # Main portion: regular build rules
+MICESRC = mice.c twiddler.c synaptics.c @EVDEV_SRCS@
 
-GSRC = main.c gpm.c gpn.c mice.c special.c twiddler.c synaptics.c \
-       startup.c server_tools.c
+GSRC = main.c gpm.c gpn.c special.c startup.c server_tools.c console.c \
+       selection.c client.c optparser.c $(MICESRC)
 
-GOBJ = $(GSRC:.c=.o) report.o tools.o
+GOBJ = $(GSRC:.c=.o) report.o
 
-LSRC = lib/liblow.c lib/libhigh.c lib/libxtra.c lib/report-lib.c
+LSRC = lib/liblow.c lib/libhigh.c lib/libxtra.c lib/report-lib.c lib/tools.c
 
-LOBJ = $(LSRC:.c=.o) tools.o @CURSES_OBJS@
+LOBJ = $(LSRC:.c=.o) @CURSES_OBJS@
 
 PICS = $(LOBJ:.o=.lo)
 
@@ -143,7 +144,7 @@
 	$(CC) -I. @CPPFLAGS@ $(CPPFLAGS) @CFLAGS@ $(CFLAGS) -c -o $@.o $<
 	$(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $@.o @LIBS@ $(LIBS) lib/libgpm.a
 
-prog/mouse-test:	mice.o twiddler.o synaptics.o
+prog/mouse-test:	$(MICESRC:.c=.o) console.o optparser.o
 
 $(PROG):	lib/libgpm.so lib/@SHLIB@ lib/libgpm.a
 
diff -urN gpm-1.20.1/src/mice.c gpm/src/mice.c
--- gpm-1.20.1/src/mice.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/mice.c	2003-10-02 01:22:42.000000000 -0500
@@ -46,15 +46,11 @@
 #include <string.h>
 #include <stdlib.h>
 #include <termios.h>
-#include <fcntl.h>
-#include <termios.h>
 #include <errno.h>
 #include <unistd.h>
 #include <ctype.h>
 
-#include <sys/types.h>
 #include <sys/stat.h> /* stat() */
-#include <sys/time.h> /* select() */
 
 #include <linux/kdev_t.h> /* MAJOR */
 #include <linux/keyboard.h>
@@ -72,135 +68,40 @@
 
 
 #include "headers/gpmInt.h"
+#include "headers/console.h"
 #include "headers/twiddler.h"
 #include "headers/synaptics.h"
 #include "headers/message.h"
-
-/*========================================================================*/
-/* Parsing argv: helper dats struct function (should they get elsewhere?) */
-/*========================================================================*/
-
-enum argv_type {
-   ARGV_BOOL = 1,
-   ARGV_INT, /* "%i" */
-   ARGV_DEC, /* "%d" */
-   ARGV_STRING,
-   /* other types must be added */
-   ARGV_END = 0
-};
-
-typedef struct argv_helper {
-   char *name;
-   enum argv_type type;
-   union u {
-      int *iptr;   /* used for int and bool arguments */
-      char **sptr; /* used for string arguments, by strdup()ing the value */
-   } u;
-   int value; /* used for boolean arguments */
-} argv_helper;
-
-static int parse_argv(argv_helper *info, int argc, char **argv)
-{
-   int i, j = 0, errors = 0;
-   long l;
-   argv_helper *p;
-   char *s, *t;
-   int base = 0; /* for strtol */
-
-
-   for (i=1; i<argc; i++) {
-      for (p = info; p->type != ARGV_END; p++) {
-         j = strlen(p->name);
-         if (strncmp(p->name, argv[i], j))
-            continue;
-         if (isalnum(argv[i][j]))
-            continue;
-         break;
-      }
-      if (p->type == ARGV_END) { /* not found */
-         fprintf(stderr, "%s: Uknown option \"%s\" for pointer \"%s\"\n",
-                  option.progname, argv[i], argv[0]);
-         errors++;
-         continue;
-      }
-      /* Found. Look for trailing stuff, if any */
-      s = argv[i]+j;
-      while (*s && isspace(*s)) s++; /* skip spaces */
-      if (*s == '=') s++; /* skip equal */
-      while (*s && isspace(*s)) s++; /* skip other spaces */
-
-      /* Now parse what s is */
-      switch(p->type) {
-         case ARGV_BOOL:
-            if (*s) {
-               gpm_report(GPM_PR_ERR,GPM_MESS_OPTION_NO_ARG,option.progname,p->name,s);
-               errors++;
-            }
-            *(p->u.iptr) = p->value;
-            break;
-
-         case ARGV_DEC:
-            base = 10; /* and fall through */
-         case ARGV_INT:
-            l = strtol(s, &t, base);
-            if (*t) {
-               gpm_report(GPM_PR_ERR,GPM_MESS_INVALID_ARG, option.progname, s, p->name);
-               errors++;
-               break;
-            }
-            *(p->u.iptr) = (int)l;
-            break;
-
-         case ARGV_STRING:
-            *(p->u.sptr) = strdup(s);
-            break;
-
-         case ARGV_END: /* let's please "-Wall" */
-            break;
-      }
-   } /* for i in argc */
-   if (errors) gpm_report(GPM_PR_ERR,GPM_MESS_CONT_WITH_ERR, option.progname);
-   return errors;
-}
-
-/*========================================================================*/
-/* Provide a common error engine by parsing with an empty option-set */
-/*========================================================================*/
-static volatile int check_no_argv(int argc, char **argv)
-{
-   static argv_helper optioninfo[] = {
-      {"",       ARGV_END}
-      };
-   return parse_argv(optioninfo, argc, argv);
-}
+#include "headers/optparser.h"
 
 /*========================================================================*/
 /* Parse the "old" -o options */
 /*========================================================================*/
-static int option_modem_lines(int fd, int argc, char **argv)
+static int option_modem_lines(int fd, char *proto, char *opts)
 {
-   static unsigned int err, lines, reallines;
+   static unsigned int lines, reallines;
+   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},
+      {"",     OPT_END}
+   };
 
-   static argv_helper optioninfo[] = {
-      {"dtr",  ARGV_BOOL, u: {iptr: &lines}, value: TIOCM_DTR},
-      {"rts",  ARGV_BOOL, u: {iptr: &lines}, value: TIOCM_RTS},
-      {"both", ARGV_BOOL, u: {iptr: &lines}, value: TIOCM_DTR | TIOCM_RTS},
-      {"",       ARGV_END}
-      };
+   int rslt = parse_options(proto, opts, ',', optioninfo);
 
-   if (argc<2) return 0;
-   if (argc > 2) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_TOO_MANY_OPTS,option.progname, argv[0]);
+   if (rslt < 0) {
+      errno = EINVAL;
+      return -1;
+   } else if (rslt > 1) {
+      gpm_report(GPM_PR_ERR, GPM_MESS_TOO_MANY_OPTS, option.progname, proto);
       errno = EINVAL; /* used by gpm_oops(), if the caller reports failure */
       return -1;
+   } else if (rslt == 1) {
+      /* ok, move the lines */
+      ioctl(fd, TIOCMGET, &reallines);
+      reallines &= ~lines;
+      ioctl(fd, TIOCMSET, &reallines);
    }
-   err = parse_argv(optioninfo, argc, argv);
-   if(err) return 0; /* a message has been printed, but go on as good */
-
-   /* ok, move the lines */
-   ioctl(fd, TIOCMGET, &reallines);
-   reallines &= ~lines;
-   ioctl(fd, TIOCMSET, &reallines);
    return 0;
 }
 
@@ -233,28 +134,12 @@
 /*========================================================================*/
 
 #ifdef HAVE_LINUX_INPUT_H
-static int M_evdev (Gpm_Event * state, unsigned char *data)
-{
-   struct input_event thisevent;
-   (void) memcpy (&thisevent, data, sizeof (struct input_event));
-   if (thisevent.type == EV_REL) {
-      if (thisevent.code == REL_X)
-         state->dx = (signed char) thisevent.value;
-      else if (thisevent.code == REL_Y)
-         state->dy = (signed char) thisevent.value;
-   } else if (thisevent.type == EV_KEY) {
-      switch(thisevent.code) {
-         case BTN_LEFT:    state->buttons ^= GPM_B_LEFT;    break;
-         case BTN_MIDDLE:  state->buttons ^= GPM_B_MIDDLE;  break;
-         case BTN_RIGHT:   state->buttons ^= GPM_B_RIGHT;   break;
-         case BTN_SIDE:    state->buttons ^= GPM_B_MIDDLE;  break;
-      }   
-   }
-   return 0;
-}
+/* defined in evdev.c */
+extern int M_evdev(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state);
+extern int I_evdev(struct micedev *dev, struct miceopt *opt, Gpm_Type *type);
 #endif /* HAVE_LINUX_INPUT_H */
 
-static int M_ms(Gpm_Event *state,  unsigned char *data)
+static int M_ms(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    /*
     * some devices report a change of middle-button state by
@@ -273,7 +158,7 @@
    return 0;
 }
 
-static int M_ms_plus(Gpm_Event *state, unsigned char *data)
+static int M_ms_plus(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    static unsigned char prev=0;
 
@@ -293,7 +178,7 @@
    return 0;
 }
 
-static int M_ms_plus_lr(Gpm_Event *state,  unsigned char *data)
+static int M_ms_plus_lr(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    /*
     * Same as M_ms_plus but with an addition by Edmund GRIMLEY EVANS
@@ -329,19 +214,19 @@
 int SUMMA_BORDER=100;
 int summamaxx,summamaxy;
 char summaid=-1;
-static int M_summa(Gpm_Event *state, unsigned char *data)
+static int M_summa(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    int x, y;
 
    x = ((data[2]<<7) | data[1])-SUMMA_BORDER;
    if (x<0) x=0;
    if (x>summamaxx) x=summamaxx;
-   state->x = (x * win.ws_col / summamaxx);
+   state->x = (x * console.max_x / summamaxx);
    realposx = (x * 16383 / summamaxx);
 
    y = ((data[4]<<7) | data[3])-SUMMA_BORDER;
    if (y<0) y=0; if (y>summamaxy) y=summamaxy;
-   state->y = 1 + y * (win.ws_row-1)/summamaxy;
+   state->y = 1 + y * (console.max_y-1)/summamaxy;
    realposy = y * 16383 / summamaxy;  
 
    state->buttons=
@@ -396,7 +281,7 @@
 
 
 /* 'Genitizer' (kw@dtek.chalmers.se 11/12/97) */
-static int M_geni(Gpm_Event *state,  unsigned char *data)
+static 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
@@ -419,7 +304,7 @@
 
 
 /* m$ 'Intellimouse' (steveb 20/7/97) */
-static int M_ms3(Gpm_Event *state,  unsigned char *data)
+static int M_ms3(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    state->wdx = state->wdy = 0;
    state->buttons= ((data[0] & 0x20) >> 3)   /* left */
@@ -470,7 +355,7 @@
 }
 
 /* M_brw is a variant of m$ 'Intellimouse' the middle button is different */
-static int M_brw(Gpm_Event *state,  unsigned char *data)
+static 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 */
@@ -491,7 +376,7 @@
    return 0;
 }
 
-static int M_bare(Gpm_Event *state,  unsigned char *data)
+static int M_bare(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    /* a bare ms protocol */
    state->buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
@@ -500,7 +385,7 @@
    return 0;
 }
 
-static int M_sun(Gpm_Event *state,  unsigned char *data)
+static int M_sun(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    state->buttons= (~data[0]) & 0x07;
    state->dx=      (signed char)(data[1]);
@@ -508,7 +393,7 @@
    return 0;
 }
 
-static int M_msc(Gpm_Event *state,  unsigned char *data)
+static int M_msc(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    state->buttons= (~data[0]) & 0x07;
    state->dx=      (signed char)(data[1]) + (signed char)(data[3]);
@@ -558,7 +443,7 @@
 
 }
 
-static int M_logimsc(Gpm_Event *state,  unsigned char *data) /* same as msc */
+static int M_logimsc(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    state->buttons= (~data[0]) & 0x07;
    state->dx=      (signed char)(data[1]) + (signed char)(data[3]);
@@ -566,7 +451,7 @@
    return 0;
 }
 
-static int M_mm(Gpm_Event *state,  unsigned char *data)
+static int M_mm(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    state->buttons= data[0] & 0x07;
    state->dx=      (data[0] & 0x10) ?   data[1] : - data[1];
@@ -574,7 +459,7 @@
    return 0;
 }
 
-static int M_logi(Gpm_Event *state,  unsigned char *data) /* equal to mm */
+static int M_logi(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    state->buttons= data[0] & 0x07;
    state->dx=      (data[0] & 0x10) ?   data[1] : - data[1];
@@ -582,7 +467,7 @@
    return 0;
 }
 
-static int M_bm(Gpm_Event *state,  unsigned char *data) /* equal to sun */
+static int M_bm(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    state->buttons= (~data[0]) & 0x07;
    state->dx=      (signed char)data[1];
@@ -590,7 +475,7 @@
    return 0;
 }
 
-static int M_ps2(Gpm_Event *state,  unsigned char *data)
+static int M_ps2(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    static int tap_active=0; /* there exist glidepoint ps2 mice */
 
@@ -599,8 +484,8 @@
       !!(data[0]&2) * GPM_B_RIGHT +
       !!(data[0]&4) * GPM_B_MIDDLE;
 
-   if (data[0]==0 && opt_glidepoint_tap) /* by default this is false */
-      state->buttons = tap_active = opt_glidepoint_tap;
+   if (data[0]==0 && opt->glidepoint_tap) /* by default this is false */
+      state->buttons = tap_active = opt->glidepoint_tap;
    else if (tap_active) {
       if (data[0]==8)
          state->buttons = tap_active = 0;
@@ -623,10 +508,11 @@
       state->dy= -((data[0] & 0x20) ? data[2]-256 : data[2]);
    else
       state->dy = 0;
+
    return 0;
 }
 
-static int M_imps2(Gpm_Event *state,  unsigned char *data)
+static int M_imps2(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    
    static int tap_active=0;         /* there exist glidepoint ps2 mice */
@@ -636,8 +522,8 @@
    state->buttons= ((data[0] & 1) << 2)   /* left              */
       | ((data[0] & 6) >> 1);             /* middle and right  */
    
-   if (data[0]==0 && opt_glidepoint_tap) // by default this is false
-      state->buttons = tap_active = opt_glidepoint_tap;
+   if (data[0]==0 && opt->glidepoint_tap) // by default this is false
+      state->buttons = tap_active = opt->glidepoint_tap;
    else if (tap_active) {
       if (data[0]==8)
          state->buttons = tap_active = 0;
@@ -667,7 +553,7 @@
 
 }
 
-static int M_netmouse(Gpm_Event *state,  unsigned char *data)
+static int M_netmouse(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    /* Avoid these beasts if you can.  They connect to normal PS/2 port,
     * but their protocol is one byte longer... So if you have notebook
@@ -706,47 +592,45 @@
 }
 
 /* standard ps2 */
-static Gpm_Type *I_ps2(int fd, unsigned short flags,
-        struct Gpm_Type *type, int argc, char **argv)
+int I_ps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    static unsigned char s[] = { 246, 230, 244, 243, 100, 232, 3, };
-   write (fd, s, sizeof (s));
+   write(dev->fd, s, sizeof (s));
    usleep (30000);
-   tcflush (fd, TCIFLUSH);
-   return type;
+   tcflush (dev->fd, TCIFLUSH);
+   return 0;
 }
 
-static Gpm_Type *I_netmouse(int fd, unsigned short flags,
-         struct Gpm_Type *type, int argc, char **argv)
+static int I_netmouse(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    unsigned char magic[6] = { 0xe8, 0x03, 0xe6, 0xe6, 0xe6, 0xe9 };
    int i;
 
-   if (check_no_argv(argc, argv)) return NULL;
+   if (!check_no_options(type->name, opt->text, ',')) return -1;
    for (i=0; i<6; i++) {
       unsigned char c = 0;
-      write( fd, magic+i, 1 );
-      read( fd, &c, 1 );
+      write(dev->fd, magic+i, 1 );
+      read(dev->fd, &c, 1 );
       if (c != 0xfa) {
          gpm_report(GPM_PR_ERR,GPM_MESS_NETM_NO_ACK,c);
-         return NULL;
+         return -1;
       }
    }
    {
       unsigned char rep[3] = { 0, 0, 0 };
-      read( fd, rep, 1 );
-      read( fd, rep+1, 1 );
-      read( fd, rep+2, 1 );
+      read( dev->fd, rep, 1 );
+      read( dev->fd, rep+1, 1 );
+      read( dev->fd, rep+2, 1 );
       if (rep[0] || (rep[1] != 0x33) || (rep[2] != 0x55)) {
          gpm_report(GPM_PR_ERR,GPM_MESS_NETM_INV_MAGIC, rep[0], rep[1], rep[2]);
-         return NULL;
+         return -1;
       }
    }
-   return type;
+   return 0;
 }
 
 #define GPM_B_BOTH (GPM_B_LEFT|GPM_B_RIGHT)
-static int M_mman(Gpm_Event *state,  unsigned char *data)
+static int M_mman(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    /*
     * the damned MouseMan has 3/4 bytes packets. The extra byte 
@@ -784,7 +668,7 @@
          mytype->getextra=1;
       } else {
          if (b & 0x2) prev |= GPM_B_MIDDLE;
-         if (b & 0x1) prev |= opt_glidepoint_tap;
+         if (b & 0x1) prev |= opt->glidepoint_tap;
       }
    }
    state->buttons=prev;
@@ -828,7 +712,7 @@
 
 #define IsA(m) ((WacomModell==(-1))? 0:!strcmp(#m,wcmodell[WacomModell].name))
 
-static int M_wacom(Gpm_Event *state, unsigned char *data)
+static int M_wacom(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    static int ox=-1, oy;
    int x, y;
@@ -878,8 +762,8 @@
    if (WacomAbsoluteWanted) { /* Absolute Mode */
       if (x>wmaxx) x=wmaxx; if (x<0) x=0;
       if (y>wmaxy) y=wmaxy; if (y<0) y=0;
-      state->x  = (x * win.ws_col / wmaxx);
-      state->y  = (y * win.ws_row / wmaxy);
+      state->x  = (x * console.max_x / wmaxx);
+      state->y  = (y * console.max_y / wmaxy);
        
       realposx = (x / wmaxx); /* this two lines come from the summa driver. */
       realposy = (y / wmaxy); /* they seem to be buggy (always give zero).  */
@@ -889,8 +773,8 @@
       if( abs(x-ox)>(wmaxx/wcmodell[WacomModell].treshold) 
        || abs(y-oy)>(wmaxy/wcmodell[WacomModell].treshold) ) ox=x; oy=y;
 
-      state->dx= (x-ox) / (wmaxx / win.ws_col / wcmodell[WacomModell].treshold);
-      state->dy= (y-oy) / (wmaxy / win.ws_row / wcmodell[WacomModell].treshold);
+      state->dx= (x-ox) / (wmaxx / console.max_x / wcmodell[WacomModell].treshold);
+      state->dy= (y-oy) / (wmaxy / console.max_y / wcmodell[WacomModell].treshold);
    }
 
    ox=x; oy=y;    
@@ -918,7 +802,7 @@
 #define CAL_Y_MAX 0xF40
 #define CAL_Y_SIZE (CAL_Y_MAX - CAL_Y_MIN)
 
-static int M_calus(Gpm_Event *state, unsigned char *data)
+static int M_calus(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    int x, y;
 
@@ -932,12 +816,12 @@
    state->dx = 0; state->dy = 0;
 
    state->x = x < CAL_X_MIN ? 0
-     : x > CAL_X_MAX ? win.ws_col+1
-     : (long)(x-CAL_X_MIN) * (long)(win.ws_col-1) / CAL_X_SIZE+2;
+     : x > CAL_X_MAX ? console.max_x+1
+     : (long)(x-CAL_X_MIN) * (long)(console.max_x-1) / CAL_X_SIZE+2;
 
-   state->y = y < CAL_Y_MIN ? win.ws_row + 1
+   state->y = y < CAL_Y_MIN ? console.max_y + 1
      : y > CAL_Y_MAX ? 0
-     : (long)(CAL_Y_MAX-y) * (long)win.ws_row / CAL_Y_SIZE + 1;
+     : (long)(CAL_Y_MAX-y) * (long)console.max_y / CAL_Y_SIZE + 1;
 
    realposx = x < CAL_X_MIN ? 0
      : x > CAL_X_MAX ? 16384
@@ -950,7 +834,7 @@
    return 0;
 }
 
-static int M_calus_rel(Gpm_Event *state, unsigned char *data)
+static int M_calus_rel(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    static int ox=-1, oy;
    int x, y;
@@ -984,7 +868,7 @@
 #define NCR_DELTA_X    (NCR_RIGHT_X - NCR_LEFT_X)
 #define NCR_DELTA_Y    (NCR_TOP_Y - NCR_BOTTOM_Y)
 
-static int M_ncr(Gpm_Event *state,  unsigned char *data)
+static int M_ncr(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    int x,y;
 
@@ -1002,14 +886,14 @@
    state->x = x < NCR_LEFT_X
              ? 0
              : x > NCR_RIGHT_X
-               ? win.ws_col+1
-               : (long)(x-NCR_LEFT_X) * (long)(win.ws_col-1) / NCR_DELTA_X+2;
+               ? console.max_x+1
+               : (long)(x-NCR_LEFT_X) * (long)(console.max_x-1) / NCR_DELTA_X+2;
 
    state->y = y < NCR_BOTTOM_Y
-             ? win.ws_row + 1
+             ? console.max_y + 1
              : y > NCR_TOP_Y
           ? 0
-          : (long)(NCR_TOP_Y-y) * (long)win.ws_row / NCR_DELTA_Y + 1;
+          : (long)(NCR_TOP_Y-y) * (long)console.max_y / NCR_DELTA_Y + 1;
 
    realposx = x < NCR_LEFT_X
              ? 0
@@ -1026,7 +910,7 @@
    return 0;
 }
 
-static int M_twid(Gpm_Event *state,  unsigned char *data)
+static int M_twid(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    unsigned long message=0UL; int i,h,v;
    static int lasth, lastv, lastkey, key, lock=0, autorepeat=0;
@@ -1144,7 +1028,7 @@
 #ifdef HAVE_LINUX_JOYSTICK_H
 /* Joystick mouse emulation (David Given) */
 
-static int M_js(Gpm_Event *state,  unsigned char *data)
+static int M_js(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    struct JS_DATA_TYPE *jdata = (void*)data;
    static int centerx = 0;
@@ -1193,21 +1077,21 @@
 #endif /* have joystick.h */
 
 /* Synaptics TouchPad mouse emulation (Henry Davies) */
-static int M_synaptics_serial(Gpm_Event *state,  unsigned char *data)
+static int M_synaptics_serial(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
-   syn_process_serial_data (state, data);
+   syn_process_serial_data(dev->fd, state, data);
    return 0;
 }
 
 
 /* Synaptics TouchPad mouse emulation (Henry Davies) */
-static int M_synaptics_ps2(Gpm_Event *state,  unsigned char *data)
+static int M_synaptics_ps2(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
-   syn_process_ps2_data(state, data);
+   syn_process_ps2_data(dev->fd, state, data);
    return 0;
 }
 
-static int M_mtouch(Gpm_Event *state,  unsigned char *data)
+static int M_mtouch(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    /*
     * This is a simple decoder for the MicroTouch touch screen
@@ -1219,8 +1103,8 @@
    static int upx, upy;            /* keep track of last finger-up place */
    static struct timeval uptv, tv; /* time of last up, and down events */
 
-   #define REAL_TO_XCELL(x) (x * win.ws_col / 0x3FFF)
-   #define REAL_TO_YCELL(y) (y * win.ws_row / 0x3FFF)
+   #define REAL_TO_XCELL(x) (x * console.max_x / 0x3FFF)
+   #define REAL_TO_YCELL(y) (y * console.max_y / 0x3FFF)
 
    #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
    #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
@@ -1245,7 +1129,7 @@
 
    if (avgx < 0) { /* press event */
       GET_TIME(tv);
-      if (DIF_TIME(uptv, tv) < opt_time) {
+      if (DIF_TIME(uptv, tv) < opt->time) {
          /* count as button press placed at finger-up pixel */
          state->buttons = GPM_B_LEFT;
          realposx = avgx = upx; state->x = REAL_TO_XCELL(realposx);
@@ -1287,7 +1171,7 @@
 static int gunze_calib[4]; /* x0,y0 x1,y1 (measured at 1/8 and 7/8) */
 static int gunze_debounce = 100; /* milliseconds: ignore shorter taps */
 
-static int M_gunze(Gpm_Event *state,  unsigned char *data)
+static int M_gunze(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    /*
     * This generates button-1 events, by now.
@@ -1300,8 +1184,8 @@
    static struct timeval uptv, tv; /* time of last up, and down events */
    int timediff;
     
-   #define REAL_TO_XCELL(x) (x * win.ws_col / 0x3FFF)
-   #define REAL_TO_YCELL(y) (y * win.ws_row / 0x3FFF)
+   #define REAL_TO_XCELL(x) (x * console.max_x / 0x3FFF)
+   #define REAL_TO_YCELL(y) (y * console.max_y / 0x3FFF)
     
    #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
    #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
@@ -1350,7 +1234,7 @@
       GET_TIME(tv);
       timediff = DIF_TIME(uptv, tv);
       released = 0;
-      if (timediff > gunze_debounce && timediff < opt_time) {
+      if (timediff > gunze_debounce && timediff < opt->time) {
          /* count as button press placed at finger-up pixel */
          dragging = 1;
          state->buttons = GPM_B_LEFT;
@@ -1399,7 +1283,7 @@
 /* corresponding correction of the protocol identification     */
 /* mask) 2001/07/12 by Maciej W. Rozycki (macro@ds2.pg.gda.pl) */
 
-static int M_vsxxx_aa(Gpm_Event *state, unsigned char *data)
+static int M_vsxxx_aa(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
 
 /* The mouse protocol is as follows:
@@ -1449,16 +1333,16 @@
 /*  Genius Wizardpad tablet  --  Matt Kimball (mkimball@xmission.com)  */
 static int wizardpad_width = -1;
 static int wizardpad_height = -1;
-static int M_wp(Gpm_Event *state,  unsigned char *data)
+static int M_wp(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state)
 {
    int x, y, pressure;
 
    x = ((data[4] & 0x1f) << 12) | ((data[3] & 0x3f) << 6) | (data[2] & 0x3f);
-   state->x = x * win.ws_col / (wizardpad_width * 40);
+   state->x = x * console.max_x / (wizardpad_width * 40);
    realposx = x * 16383 / (wizardpad_width * 40);
 
    y = ((data[7] & 0x1f) << 12) | ((data[6] & 0x3f) << 6) | (data[5] & 0x3f);
-   state->y = win.ws_row - y * win.ws_row / (wizardpad_height * 40) - 1;
+   state->y = console.max_y - y * console.max_y / (wizardpad_height * 40) - 1;
    realposy = 16383 - y * 16383 / (wizardpad_height * 40) - 1;  
 
    pressure = ((data[9] & 0x0f) << 4) | (data[8] & 0x0f);
@@ -1475,11 +1359,9 @@
 /*========================================================================*/
 /* Then, mice should be initialized */
 
-static Gpm_Type* I_empty(int fd, unsigned short flags,
-    struct Gpm_Type *type, int argc, char **argv)
+static int I_empty(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-    if (check_no_argv(argc, argv)) return NULL;
-    return type;
+    return check_no_options(type->name, opt->text, ',') ? 0 : -1;
 }
 
 static int setspeed(int fd,int old,int new,int needtowrite,unsigned short flags)
@@ -1536,28 +1418,27 @@
     {125,"Q"},
     {1E9,"N"}, };
 
-static Gpm_Type* I_serial(int fd, unsigned short flags,
-    struct Gpm_Type *type, int argc, char **argv)
+static int I_serial(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    int i; unsigned char c;
    fd_set set; struct timeval timeout={0,0}; /* used when not debugging */
 
    /* accept "-o dtr", "-o rts" and "-o both" */
-   if (option_modem_lines(fd, argc, argv)) return NULL;
+   if (option_modem_lines(dev->fd, type->name, opt->text)) return -1;
 
 #ifndef DEBUG
    /* flush any pending input (thanks, Miguel) */
    FD_ZERO(&set);
    for(i=0; /* always */ ; i++) {
-      FD_SET(fd,&set);
-      switch(select(fd+1,&set,(fd_set *)NULL,(fd_set *)NULL,&timeout/*zero*/)){
-         case  1: if (read(fd,&c,1)==0) break;
+      FD_SET(dev->fd,&set);
+      switch(select(dev->fd+1,&set,(fd_set *)NULL,(fd_set *)NULL,&timeout/*zero*/)){
+         case  1: if (read(dev->fd,&c,1)==0) break;
          case -1: continue;
       }
       break;
    }
 
-   if (type->fun==M_logimsc) write(fd, "QU", 2 );
+   if (type->fun==M_logimsc) write(dev->fd, "QU", 2 );
 
 #if 0 /* Did this ever work? -- I don't know, but should we not remove it,
        * if it doesn't work ??? -- Nico */
@@ -1570,7 +1451,7 @@
 
    /* Non mman: change from any available speed to the chosen one */
    for (i=9600; i>=1200; i/=2)
-      setspeed(fd, i, opt_baud, (type->fun != M_mman) /* write */, flags);
+      setspeed(dev->fd, i, opt->baud, (type->fun != M_mman) /* write */, type->flags);
 
    /*
     * reset the MouseMan/TrackMan to use the 3/4 byte protocol
@@ -1578,51 +1459,50 @@
     * Changed after 1.14; why not having "I_mman" now?
     */
    if (type->fun==M_mman) {
-      setspeed(fd, 1200, 1200, 0, flags); /* no write */
-      write(fd, "*X", 2);
-      setspeed(fd, 1200, opt_baud, 0, flags); /* no write */
-      return type;
+      setspeed(dev->fd, 1200, 1200, 0, type->flags); /* no write */
+      write(dev->fd, "*X", 2);
+      setspeed(dev->fd, 1200, opt->baud, 0, type->flags); /* no write */
+      return 0;
    }
 
    if(type->fun==M_geni) {
       gpm_report(GPM_PR_INFO,GPM_MESS_INIT_GENI);
-      setspeed(fd, 1200, 9600, 1, flags); /* write */
-      write(fd, ":" ,1); 
-      write(fd, "E" ,1); /* setup tablet. relative mode, resolution... */
-      write(fd, "@" ,1); /* setup tablet. relative mode, resolution... */
+      setspeed(dev->fd, 1200, 9600, 1, type->flags); /* write */
+      write(dev->fd, ":" ,1); 
+      write(dev->fd, "E" ,1); /* setup tablet. relative mode, resolution... */
+      write(dev->fd, "@" ,1); /* setup tablet. relative mode, resolution... */
     }
 
    if (type->fun==M_synaptics_serial) {
       int packet_length;
 
-      setspeed (fd, 1200, 1200, 1, flags);
-      packet_length = syn_serial_init (fd);
-      setspeed (fd, 1200, 9600, 1, flags);
+      setspeed (dev->fd, 1200, 1200, 1, type->flags);
+      packet_length = syn_serial_init (dev->fd);
+      setspeed (dev->fd, 1200, 9600, 1, type->flags);
 
       type->packetlen = packet_length;
       type->howmany   = packet_length;
     }
 
    if (type->fun==M_vsxxx_aa) {
-      setspeed (fd, 4800, 4800, 0, flags); /* no write */
-      write(fd, "R", 1); /* initialize a mouse; without getting an "R" */
+      setspeed (dev->fd, 4800, 4800, 0, type->flags); /* no write */
+      write(dev->fd, "R", 1); /* initialize a mouse; without getting an "R" */
                          /* a mouse does not send a bytestream         */
    }
 
-   return type;
+   return 0;
 }
 
-static Gpm_Type* I_logi(int fd, unsigned short flags,
-       struct Gpm_Type *type, int argc, char **argv)
+static int I_logi(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    int i;
    struct stat buf;
    int busmouse;
 
-   if (check_no_argv(argc, argv)) return NULL;
+   if (!check_no_options(type->name, opt->text, ',')) return -1;
 
    /* is this a serial- or a bus- mouse? */
-   if(fstat(fd,&buf)==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_FSTAT);
+   if(fstat(dev->fd,&buf)==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_FSTAT);
    i=MAJOR(buf.st_rdev);
    
    /* I don't know why this is herein, but I remove it. I don't think a 
@@ -1635,21 +1515,20 @@
    type->howmany = busmouse ? 3 : 1;
 
    /* change from any available speed to the chosen one */
-   for (i=9600; i>=1200; i/=2) setspeed(fd, i, opt_baud, 1 /* write */, flags);
+   for (i=9600; i>=1200; i/=2) setspeed(dev->fd, i, opt->baud, 1 /* write */, type->flags);
 
    /* this stuff is peculiar of logitech mice, also for the serial ones */
-   write(fd, "S", 1);
-   setspeed(fd, opt_baud, opt_baud, 1 /* write */,
+   write(dev->fd, "S", 1);
+   setspeed(dev->fd, opt->baud, opt->baud, 1 /* write */,
       CS8 |PARENB |PARODD |CREAD |CLOCAL |HUPCL);
 
    /* configure the sample rate */
-   for (i=0;opt_sample<=sampletab[i].sample;i++) ;
-   write(fd,sampletab[i].code,1);
-   return type;
+   for (i=0;opt->sample<=sampletab[i].sample;i++) ;
+   write(dev->fd,sampletab[i].code,1);
+   return 0;
 }
 
-static Gpm_Type *I_wacom(int fd, unsigned short flags,
-                         struct Gpm_Type *type, int argc, char **argv)
+static int I_wacom(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
 /* wacom graphire tablet */
 #define UD_RESETBAUD     "\r$"      /* reset baud rate to default (wacom V) */
@@ -1664,19 +1543,19 @@
    { 
       /* Init Wacom communication; this is modified from xf86Wacom.so module */
       /* Set speed to 19200 */
-      setspeed (fd, 1200, 19200, 0, B19200|CS8|CREAD|CLOCAL|HUPCL);
+      setspeed (dev->fd, 1200, 19200, 0, B19200|CS8|CREAD|CLOCAL|HUPCL);
       /* Send Reset Baudrate Command */ 
-      write(fd, UD_RESETBAUD, strlen(UD_RESETBAUD));
+      write(dev->fd, UD_RESETBAUD, strlen(UD_RESETBAUD));
       usleep(250000);   
       /* Send Reset Command */
-      write(fd, UD_RESET,     strlen(UD_RESET));
+      write(dev->fd, UD_RESET,     strlen(UD_RESET));
       usleep(75000);
       /* Set speed to 9600bps */
-      setspeed (fd, 1200, 9600, 0, B9600|CS8|CREAD|CLOCAL|HUPCL);
+      setspeed (dev->fd, 1200, 9600, 0, B9600|CS8|CREAD|CLOCAL|HUPCL);
       /* Send Reset Command */
-      write(fd, UD_RESET, strlen(UD_RESET));
+      write(dev->fd, UD_RESET, strlen(UD_RESET));
       usleep(250000);  
-      write(fd, UD_STOP, strlen(UD_STOP));
+      write(dev->fd, UD_STOP, strlen(UD_STOP));
       usleep(100000);
    }
 
@@ -1690,7 +1569,7 @@
       struct timeval timeout;
       fd_set readfds;
       int err;
-      FD_ZERO(&readfds);  FD_SET(fd, &readfds);
+      FD_ZERO(&readfds);  FD_SET(dev->fd, &readfds);
       timeout.tv_sec = 0; timeout.tv_usec = 200000;
       err = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
       return((err>0)?1:err);
@@ -1706,11 +1585,11 @@
        * Get Data to buffer until full or timeout.
        * Give back 0 for timeout and !0 for buffer full
        */
-      if (cmd) write(fd,cmd,strlen(cmd));
+      if (cmd) write(dev->fd,cmd,strlen(cmd));
       memset(buffer,0,sizeof(buffer)); p=buffer;
       err=wait_wacom();
       while (err != -1 && err && (p-buffer)<(sizeof(buffer)-1)) {
-         p+= read(fd,p,(sizeof(buffer)-1)-(p-buffer));
+         p+= read(dev->fd,p,(sizeof(buffer)-1)-(p-buffer));
          err=wait_wacom();
       }
       /* return 1 for buffer full */
@@ -1728,13 +1607,14 @@
     */
 
    /* accept boolean options absolute and relative */
-   static argv_helper optioninfo[] = {
-         {"absolute",  ARGV_BOOL, u: {iptr: &WacomAbsoluteWanted}, value: !0},
-         {"relative",  ARGV_BOOL, u: {iptr: &WacomAbsoluteWanted}, value:  0},
-         {"",       ARGV_END} 
+   static struct option_helper optioninfo[] = {
+         {"absolute",  OPT_BOOL, u: {iptr: &WacomAbsoluteWanted}, value: !0},
+         {"relative",  OPT_BOOL, u: {iptr: &WacomAbsoluteWanted}, value:  0},
+         {"",          OPT_END} 
    };
-   parse_argv(optioninfo, argc, argv); 
-   type->absolute = WacomAbsoluteWanted;
+   
+   parse_options(type->name, opt->text, ',', optioninfo); 
+   opt->absolute = WacomAbsoluteWanted;
    reset_wacom();
 
    /* "Flush" input queque */
@@ -1756,7 +1636,7 @@
    }
    if(WacomModell >= (sizeof(wcmodell) / sizeof(struct WC_MODELL))) 
       WacomModell=-1;
-   gpm_report(GPM_PR_INFO,GPM_MESS_WACOM_MOD, type->absolute? 'A':'R',
+   gpm_report(GPM_PR_INFO,GPM_MESS_WACOM_MOD, opt->absolute? 'A':'R',
                 (WacomModell==(-1))? "Unknown" : wcmodell[WacomModell].name,
                 buffer+2);
    
@@ -1767,24 +1647,23 @@
       wmaxx = (wmaxx-wcmodell[WacomModell].border);
       wmaxy = (wmaxy-wcmodell[WacomModell].border);
    }
-   write(fd,UD_SENDCOORDS,4);
+   write(dev->fd,UD_SENDCOORDS,4);
 
-   return type;
+   return 0;
 }
 
-static Gpm_Type *I_pnp(int fd, unsigned short flags,
-             struct Gpm_Type *type, int argc, char **argv)
+static int I_pnp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {  
    struct termios tty;
 
    /* accept "-o dtr", "-o rts" and "-o both" */
-   if (option_modem_lines(fd, argc, argv)) return NULL;
+   if (option_modem_lines(dev->fd, type->name, opt->text)) return -1;
 
    /*
     * Just put the device to 1200 baud. Thanks to Francois Chastrette
     * for his great help and debugging with his own pnp device.
     */
-   tcgetattr(fd, &tty);
+   tcgetattr(dev->fd, &tty);
     
    tty.c_iflag = IGNBRK | IGNPAR;
    tty.c_oflag = 0;
@@ -1792,15 +1671,15 @@
    tty.c_line = 0;
    tty.c_cc[VTIME] = 0;
    tty.c_cc[VMIN] = 1;
-   tty.c_cflag = flags | B1200;
-   tcsetattr(fd, TCSAFLUSH, &tty); /* set parameters */
+   tty.c_cflag = type->flags | B1200;
+   tcsetattr(dev->fd, TCSAFLUSH, &tty); /* set parameters */
 
    /*
     * Don't read the silly initialization string. I don't want to see
     * the vendor name: it is only propaganda, with no information.
     */
    
-   return type;
+   return 0;
 }
 
 /*
@@ -1848,8 +1727,7 @@
 
 /* intellimouse, ps2 version: Ben Pfaff and Colin Plumb */
 /* Autodetect: Steve Bennett */
-static Gpm_Type *I_imps2(int fd, unsigned short flags, struct Gpm_Type *type,
-                                                       int argc, char **argv)
+static int I_imps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    int id;
    static unsigned char basic_init[] = { GPM_AUX_ENABLE_DEV, GPM_AUX_SET_SAMPLE, 100 };
@@ -1857,36 +1735,36 @@
    static unsigned char ps2_init[] = { GPM_AUX_SET_SCALE11, GPM_AUX_ENABLE_DEV, GPM_AUX_SET_SAMPLE, 100, GPM_AUX_SET_RES, 3, };
 
    /* Do a basic init in case the mouse is confused */
-   write_to_mouse(fd, basic_init, sizeof (basic_init));
+   write_to_mouse(dev->fd, basic_init, sizeof (basic_init));
 
    /* 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(dev->fd, basic_init, sizeof (basic_init)) != 0) {
       gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_INIT);
-      return(NULL);
+      return -1;
    }
 
    /* Try to switch to 3 button mode */
-   if (write_to_mouse(fd, imps2_init, sizeof (imps2_init)) != 0) {
+   if (write_to_mouse(dev->fd, imps2_init, sizeof (imps2_init)) != 0) {
       gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_FAILED);
-      return(NULL);
+      return -1;
    }
 
    /* Read the mouse id */
-   id = read_mouse_id(fd);
+   id = read_mouse_id(dev->fd);
    if (id == GPM_AUX_ID_ERROR) {
       gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_MID_FAIL);
       id = GPM_AUX_ID_PS2;
    }
 
    /* And do the real initialisation */
-   if (write_to_mouse(fd, ps2_init, sizeof (ps2_init)) != 0) {
+   if (write_to_mouse(dev->fd, ps2_init, sizeof (ps2_init)) != 0) {
       gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_SETUP_FAIL);
    }
 
    if (id == GPM_AUX_ID_IMPS2) {
    /* Really an intellipoint, so initialise 3 button mode (4 byte packets) */
       gpm_report(GPM_PR_INFO,GPM_MESS_IMPS2_AUTO);
-      return type;
+      return 0;
    }
    if (id != GPM_AUX_ID_PS2) {
       gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_BAD_ID, id);
@@ -1894,69 +1772,64 @@
    else gpm_report(GPM_PR_INFO,GPM_MESS_IMPS2_PS2);
 
    for (type=mice; type->fun; type++)
-      if (strcmp(type->name, "ps2") == 0) return(type);
+      if (strcmp(type->name, "ps2") == 0) return 0;
 
    /* ps2 was not found!!! */
-   return(NULL);
+   return -1;
 }
 
 /*
  * This works with Dexxa Optical Mouse, but because in X same initstring
  * is named ExplorerPS/2 so I named it in the same way.
  */
-static Gpm_Type *I_exps2(int fd, unsigned short flags,
-          struct Gpm_Type *type, int argc, char **argv)
+static int I_exps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    static unsigned char s1[] = { 243, 200, 243, 200, 243, 80, };
 
-   if (check_no_argv(argc, argv)) return NULL;
+   if (!check_no_options(type->name, opt->text, ',')) return -1;
 
-   write (fd, s1, sizeof (s1));
+   write (dev->fd, s1, sizeof (s1));
    usleep (30000);
-   tcflush (fd, TCIFLUSH);
-   return type;
+   tcflush (dev->fd, TCIFLUSH);
+   return 0;
 }
 
-static Gpm_Type *I_twid(int fd, unsigned short flags,
-         struct Gpm_Type *type, int argc, char **argv)
+static int I_twid(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
 
-   if (check_no_argv(argc, argv)) return NULL;
+   if (!check_no_options(type->name, opt->text, ',')) return -1;
 
-   if (twiddler_key_init() != 0) return NULL;
+   if (twiddler_key_init() != 0) return -1;
    /*
    * the twiddler is a serial mouse: just drop dtr
    * and run at 2400 (unless specified differently) 
    */
-   if(opt_baud==DEF_BAUD) opt_baud = 2400;
-   argv[1] = "dtr"; /* argv[1] is guaranteed to be NULL (this is dirty) */
-   return I_serial(fd, flags, type, argc, argv);
+   if (opt->baud == DEF_BAUD) opt->baud = 2400;
+   opt->text = "dtr";
+   return I_serial(dev, opt, type);
 }
 
-static Gpm_Type *I_calus(int fd, unsigned short flags,
-          struct Gpm_Type *type, int argc, char **argv)
+static int I_calus(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-   if (check_no_argv(argc, argv)) return NULL;
+   if (!check_no_options(type->name, opt->text, ',')) return -1;
 
-   if (opt_baud == 1200) opt_baud=9600; /* default to 9600 */
-   return I_serial(fd, flags, type, argc, argv);
+   if (opt->baud == 1200) opt->baud = 9600; /* default to 9600 */
+   return I_serial(dev, opt, type);
 }
 
 /* synaptics touchpad, ps2 version: Henry Davies */
-static Gpm_Type *I_synps2(int fd, unsigned short flags,
-           struct Gpm_Type *type, int argc, char **argv)
+static int I_synps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
-   syn_ps2_init (fd);
-   return type;
+   syn_ps2_init (dev->fd);
+   return 0;
 }
 
 
-static Gpm_Type *I_summa(int fd, unsigned short flags,
-          struct Gpm_Type *type, int argc, char **argv) 
+static int I_summa(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) 
 {
    void resetsumma()
    {
-      write(fd,0,1); /* Reset */
+      write(dev->fd,0,1); /* Reset */
       usleep(400000); /* wait */
    }
    int waitsumma()
@@ -1964,7 +1837,7 @@
       struct timeval timeout;
       fd_set readfds;
       int err;
-      FD_ZERO(&readfds);  FD_SET(fd, &readfds);
+      FD_ZERO(&readfds);  FD_SET(dev->fd, &readfds);
       timeout.tv_sec = 0; timeout.tv_usec = 200000;
       err = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
       return(err);
@@ -1987,34 +1860,34 @@
    char GEN_MODELL=0x7f;
 
    /* Set speed to 9600bps */
-   setspeed (fd, 1200, 9600, 1, B9600|CS8|CREAD|CLOCAL|HUPCL|PARENB|PARODD);  
+   setspeed (dev->fd, 1200, 9600, 1, B9600|CS8|CREAD|CLOCAL|HUPCL|PARENB|PARODD);  
    resetsumma(); 
  
-   write(fd, SS_PROMPT_MODE, strlen(SS_PROMPT_MODE));
+   write(dev->fd, SS_PROMPT_MODE, strlen(SS_PROMPT_MODE));
   
    if (strstr(type->name,"acecad")!=NULL) summaid=11;
 
    if (summaid<0) { /* Summagraphics test */
       /* read the Summa Firm-ID */
-      write(fd, SS_FIRMID, strlen(SS_FIRMID));
+      write(dev->fd, SS_FIRMID, strlen(SS_FIRMID));
       err=waitsumma();
       if (!((err == -1) || (!err))) {
          summaid=10; /* Original Summagraphics */
-         read(fd, buffer, 255); /* Read Firm-ID */
+         read(dev->fd, buffer, 255); /* Read Firm-ID */
       }
    }
   
    if (summaid<0) { /* Genius-test */
       resetsumma();
-      write(fd,GEN_MMSERIES,1); 
-      write(fd,&GEN_MODELL,1); /* Read modell */
+      write(dev->fd,GEN_MMSERIES,1); 
+      write(dev->fd,&GEN_MODELL,1); /* Read modell */
       err=waitsumma();
       if (!((err == -1) || (!err))) { /* read Genius-ID */
            err=waitsumma();
          if (!((err == -1) || (!err))) {
             err=waitsumma();
             if (!((err == -1) || (!err))) {
-               read(fd,&config,1);
+               read(dev->fd,&config,1);
                summaid=(config[0] & 224) >> 5; /* genius tablet-id (0-7)*/
             }
          } 
@@ -2024,30 +1897,29 @@
    /* unknown tablet ?*/
    if ((summaid<0) || (summaid==11)) { 
       resetsumma(); 
-      write(fd, SS_BINARY_FMT SS_PROMPT_MODE, 3);
+      write(dev->fd, SS_BINARY_FMT SS_PROMPT_MODE, 3);
    }
 
    /* read tablet size */
    err=waitsumma();  
-   if (!((err == -1) || (!err))) read(fd,buffer,sizeof(buffer));
-   write(fd,SS_READCONFIG,1);
-   read(fd,&config,5);
+   if (!((err == -1) || (!err))) read(dev->fd,buffer,sizeof(buffer));
+   write(dev->fd,SS_READCONFIG,1);
+   read(dev->fd,&config,5);
    summamaxx=(config[2]<<7 | config[1])-(SUMMA_BORDER*2);
    summamaxy=(config[4]<<7 | config[3])-(SUMMA_BORDER*2);
   
-   write(fd,SS_ABSOLUTE SS_STREAM_MODE SS_UPPER_ORIGIN,3);
-   if (summaid<0) write(fd,SS_500LPI SS_TABID0 SS_BINARY_FMT,4);
+   write(dev->fd,SS_ABSOLUTE SS_STREAM_MODE SS_UPPER_ORIGIN,3);
+   if (summaid<0) write(dev->fd,SS_500LPI SS_TABID0 SS_BINARY_FMT,4);
 
-   return type;
+   return 0;
 }
 
-static Gpm_Type *I_mtouch(int fd, unsigned short flags,
-           struct Gpm_Type *type, int argc, char **argv)
+static int I_mtouch(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct termios tty;
 
    /* Set speed to 9600bps (copied from I_summa, above :) */
-   tcgetattr(fd, &tty);
+   tcgetattr(dev->fd, &tty);
    tty.c_iflag = IGNBRK | IGNPAR;
    tty.c_oflag = 0;
    tty.c_lflag = 0;
@@ -2055,18 +1927,17 @@
    tty.c_cc[VTIME] = 0;
    tty.c_cc[VMIN] = 1;
    tty.c_cflag = B9600|CS8|CREAD|CLOCAL|HUPCL;
-   tcsetattr(fd, TCSAFLUSH, &tty);
+   tcsetattr(dev->fd, TCSAFLUSH, &tty);
 
 
    /* Turn it to "format tablet" and "mode stream" */
-   write(fd,"\001MS\r\n\001FT\r\n",10);
+   write(dev->fd,"\001MS\r\n\001FT\r\n",10);
   
-   return type;
+   return 0;
 }
 
 /* simple initialization for the gunze touchscreen */
-static Gpm_Type *I_gunze(int fd, unsigned short flags,
-           struct Gpm_Type *type, int argc, char **argv)
+static int I_gunze(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct termios tty;
    FILE *f;
@@ -2075,29 +1946,29 @@
 
    #define GUNZE_CALIBRATION_FILE SYSCONFDIR "/gpm-calibration"
    /* accept a few options */
-   static argv_helper optioninfo[] = {
-      {"smooth",   ARGV_INT, u: {iptr: &gunze_avg}},
-      {"debounce", ARGV_INT, u: {iptr: &gunze_debounce}},
+   static struct option_helper optioninfo[] = {
+      {"smooth",   OPT_INT, u: {iptr: &gunze_avg}},
+      {"debounce", OPT_INT, u: {iptr: &gunze_debounce}},
       /* FIXME: add corner tapping */
-      {"",       ARGV_END}
+      {"",         OPT_END}
    };
-   parse_argv(optioninfo, argc, argv);
+   parse_options(type->name, opt->text, ',', optioninfo);
     
    /* check that the baud rate is valid */
-   if (opt_baud == DEF_BAUD) opt_baud = 19200; /* force 19200 as default */
-   if (opt_baud != 9600 && opt_baud != 19200) {
-      gpm_report(GPM_PR_ERR,GPM_MESS_GUNZE_WRONG_BAUD,option.progname, argv[0]);
-      opt_baud = 19200;
+   if (opt->baud == DEF_BAUD) opt->baud = 19200; /* force 19200 as default */
+   if (opt->baud != 9600 && opt->baud != 19200) {
+      gpm_report(GPM_PR_ERR, GPM_MESS_GUNZE_WRONG_BAUD, option.progname, type->name);
+      opt->baud = 19200;
    }
-   tcgetattr(fd, &tty);
+   tcgetattr(dev->fd, &tty);
    tty.c_iflag = IGNBRK | IGNPAR;
    tty.c_oflag = 0;
    tty.c_lflag = 0;
    tty.c_line = 0;
    tty.c_cc[VTIME] = 0;
    tty.c_cc[VMIN] = 1;
-   tty.c_cflag = (opt_baud == 9600 ? B9600 : B19200) |CS8|CREAD|CLOCAL|HUPCL;
-   tcsetattr(fd, TCSAFLUSH, &tty);
+   tty.c_cflag = (opt->baud == 9600 ? B9600 : B19200) |CS8|CREAD|CLOCAL|HUPCL;
+   tcsetattr(dev->fd, TCSAFLUSH, &tty);
 
    /* FIXME: try to find some information about the device */
 
@@ -2120,19 +1991,18 @@
       gunze_calib[0] = gunze_calib[1] = 128; /* 1/8 */
       gunze_calib[2] = gunze_calib[3] = 896; /* 7/8 */
    }
-   return type;
+   return 0;
 }
 
 /*  Genius Wizardpad tablet  --  Matt Kimball (mkimball@xmission.com)  */
-static Gpm_Type *I_wp(int fd, unsigned short flags,
-            struct Gpm_Type *type, int argc, char **argv)
+static int I_wp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type)
 {
    struct termios tty;
    char tablet_info[256];
    int count, pos, size;
 
    /* Set speed to 9600bps (copied from I_summa, above :) */
-   tcgetattr(fd, &tty);
+   tcgetattr(dev->fd, &tty);
    tty.c_iflag = IGNBRK | IGNPAR;
    tty.c_oflag = 0;
    tty.c_lflag = 0;
@@ -2140,22 +2010,22 @@
    tty.c_cc[VTIME] = 0;
    tty.c_cc[VMIN] = 1;
    tty.c_cflag = B9600|CS8|CREAD|CLOCAL|HUPCL;
-   tcsetattr(fd, TCSAFLUSH, &tty);
+   tcsetattr(dev->fd, TCSAFLUSH, &tty);
 
    /*  Reset the tablet (':') and put it in remote mode ('S') so that
      it isn't sending anything to us.  */
-   write(fd, ":S", 2);
-   tcsetattr(fd, TCSAFLUSH, &tty);
+   write(dev->fd, ":S", 2);
+   tcsetattr(dev->fd, TCSAFLUSH, &tty);
 
    /*  Query the model of the tablet  */
-   write(fd, "T", 1);
+   write(dev->fd, "T", 1);
    sleep(1);
-   count = read(fd, tablet_info, 255);
+   count = read(dev->fd, tablet_info, 255);
 
    /*  The tablet information should start with "KW" followed by the rest of
      the model number.  If it isn't there, it probably isn't a WizardPad.  */
-   if(count < 2) return NULL;
-   if(tablet_info[0] != 'K' || tablet_info[1] != 'W') return NULL;
+   if(count < 2) return -1;
+   if(tablet_info[0] != 'K' || tablet_info[1] != 'W') return -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
@@ -2177,9 +2047,9 @@
    }
 
    /*  Set the tablet to stream mode with 180 updates per sec.  ('O')  */
-   write(fd, "O", 1);
+   write(dev->fd, "O", 1);
 
-   return type;
+   return 0;
 }
 
 /*========================================================================*/
@@ -2241,7 +2111,7 @@
                                 {0x80, 0x80, 0x80, 0x00}, 6, 6, 0, 0, 0},
 #ifdef HAVE_LINUX_INPUT_H
    {"evdev", "Linux Event Device",
-            "", M_evdev, I_empty, STD_FLG,
+            "", M_evdev, I_evdev, STD_FLG,
                         {0x00, 0x00, 0x00, 0x00} , 16, 16, 0, 0, NULL},
 #endif /* HAVE_LINUX_INPUT_H */
    {"exps2",   "IntelliMouse Explorer (ps2) - 3 buttons, wheel unused",
diff -urN gpm-1.20.1/src/optparser.c gpm/src/optparser.c
--- gpm-1.20.1/src/optparser.c	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/optparser.c	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,155 @@
+/*
+ * optparser.c - GPM mouse options parser
+ *
+ * Copyright (C) 1993        Andrew Haylett <ajh@gec-mrc.co.uk>
+ * 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
+ *   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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "headers/gpmInt.h"
+#include "headers/message.h"
+#include "headers/optparser.h"
+
+int parse_options(const char *proto, const char *opts, char sep, struct option_helper *info)
+{
+   int len, n, n_opts = 0, errors = 0;
+   long l;
+   struct option_helper *p;
+   char *s, *t, *str;
+   int base; /* for strtol */
+
+   for (p = info; p->type != OPT_END; p++)
+      p->present = 0; 
+
+   if (!opts)
+      return 0;
+   
+   if (!(str = strdup(opts)))
+      gpm_report(GPM_PR_OOPS, GPM_MESS_ALLOC_FAILED);
+
+   /* split input string */   
+   for (s = str, n = 1; sep && (s = strchr(s, sep)); s++, n++)
+        *s = '\0';
+   
+   for (s = str; n; s += strlen(s) + 1, n--) {
+      if (strlen(s) == 0)
+         continue;
+      
+      for (p = info; p->type != OPT_END; p++) {
+         len = strlen(p->name);
+         if (!strncmp(p->name, s, len) && !isalnum(s[len]))
+            break;
+      }
+      if (p->type == OPT_END) { /* not found */
+         gpm_report(GPM_PR_ERR, "%s: Uknown option \"%s\" for protocol \"%s\"\n",
+                    option.progname, s, proto);
+         errors++;
+         continue;
+      }
+      if (p->present) {
+         gpm_report(GPM_PR_ERR, "%s: option \"%s\" has already been seen, ignored (\"%s\")\n",
+                    option.progname, s, proto);
+         continue;
+      }
+      p->present = 1;
+      n_opts++;
+      /* Found. Look for trailing stuff, if any */
+      s += len;
+      while (*s && isspace(*s)) s++; /* skip spaces */
+      if (*s == '=') s++; /* skip equal */
+      while (*s && isspace(*s)) s++; /* skip other spaces */
+
+      /* Now parse what s is */
+      base = 0;
+      switch(p->type) {
+         case OPT_BOOL:
+            if (*s) {
+               gpm_report(GPM_PR_ERR, GPM_MESS_OPTION_NO_ARG, option.progname, p->name, s);
+               errors++;
+            }
+            *(p->u.iptr) = p->value;
+            break;
+
+         case OPT_DEC:
+            base = 10; /* and fall through */
+
+         case OPT_INT:
+            if (*s == '\0') {
+               gpm_report(GPM_PR_ERR, GPM_MESS_MISSING_ARG, option.progname, p->name);
+            } else {
+               l = strtol(s, &t, base);
+               if (*t) {
+                  gpm_report(GPM_PR_ERR, GPM_MESS_INVALID_ARG, option.progname, s, p->name);
+                  errors++;
+                  break;
+               }
+               *(p->u.iptr) = (int)l;
+            }
+            break;
+
+         case OPT_STRING:
+            if (*s == '\0')
+               gpm_report(GPM_PR_ERR, GPM_MESS_MISSING_ARG, option.progname, p->name);
+            else
+               *(p->u.sptr) = strdup(s);
+            break;
+
+         case OPT_END: /* let's please "-Wall" */
+            break;
+      }
+   } /* for i in argc */
+   
+   free(str);
+   
+   if (errors) {
+      gpm_report(GPM_PR_ERR,GPM_MESS_CONT_WITH_ERR, option.progname);
+      return -errors;
+   }
+   return n_opts;
+}
+
+int check_no_options(const char *proto, const char *opts, char sep)
+{
+   static struct option_helper info[] = {
+      { "", OPT_END }
+   };
+   
+   return parse_options(proto, opts, sep, info) == 0;
+}
+
+int is_option_present(struct option_helper *info, const char *name)
+{
+   struct option_helper *p;
+   int len;
+   
+   for (p = info; p->type != OPT_END; p++) {
+      len = strlen(p->name);
+      if (!strncmp(p->name, name, len) && !isalnum(name[len]))
+         return p->present;
+   }
+   
+   gpm_report(GPM_PR_ERR, "%s: Uknown option \"%s\"\n", option.progname, name);
+   return 0;
+}
+
diff -urN gpm-1.20.1/src/prog/mouse-test.c gpm/src/prog/mouse-test.c
--- gpm-1.20.1/src/prog/mouse-test.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/prog/mouse-test.c	2003-10-02 01:22:42.000000000 -0500
@@ -50,22 +50,9 @@
 #define max(a,b) ((a)>(b)?(a):(b))
 #endif
 
-
-/* this material is needed to pass options to mice.c */
-struct mouse_features mymouse = {
-   DEF_TYPE, DEF_DEV, DEF_SEQUENCE,
-   DEF_BAUD, DEF_SAMPLE, DEF_DELTA, DEF_ACCEL, DEF_SCALE, DEF_SCALE /*scaley*/,
-   DEF_TIME, DEF_CLUSTER, DEF_THREE, DEF_GLIDEPOINT_TAP,
-   (char *)NULL /* extra */,
-   (Gpm_Type *)NULL,
-   -1 /* fd */
-};
-
 /* and this is a workaroud */
 struct winsize win;
 
-struct mouse_features *which_mouse=&mymouse;
-
 char *progname;
 char *consolename;
 int devcount=0;
@@ -78,9 +65,9 @@
 
 struct device {
    char *name;
-   int fd;
+   struct micedev mdev;
    struct device *next;
-};  
+} *devlist;
 
 static int message(void)
 {
@@ -148,47 +135,48 @@
 /*----------------------------------------------------------------------------- 
    Place the description here.
  -----------------------------------------------------------------------------*/
-struct device **gpm_makedev(struct device **current, char *name)
+void gpm_makedev(char *name)
 {
-   int fd; int modes;
+   struct device *dev;
+   int fd;
+   int modes;
+   
    if ((fd=open(name,O_RDWR|O_NONBLOCK))==-1) {
       perror(name);
-      return current;
-   }
-   modes = fcntl(fd, F_GETFL);
-   if (0 > fcntl(fd, F_SETFL, modes & ~O_NONBLOCK)) {
-      close(fd);
-      perror(name);
-      return current;
+   } else {
+      modes = fcntl(fd, F_GETFL);
+      if (0 > fcntl(fd, F_SETFL, modes & ~O_NONBLOCK)) {
+         close(fd);
+         perror(name);
+      } else {
+         dev = malloc(sizeof(struct device));
+         if (!dev) gpm_report(GPM_PR_OOPS,"malloc()");
+         dev->name=strdup(name);
+         if (!dev->name) gpm_report(GPM_PR_OOPS,"malloc()");
+         dev->mdev.fd=fd;
+         dev->mdev.private = NULL;
+         dev->next=devlist;
+         devlist = dev;
+         devcount++;
+      }
    }
-
-   *current=malloc(sizeof(struct device));
-   if (!*current) gpm_report(GPM_PR_OOPS,"malloc()");
-   (*current)->name=strdup(name);
-   if (!(*current)->name) gpm_report(GPM_PR_OOPS,"malloc()");
-   (*current)->fd=fd;
-   (*current)->next=NULL;
-   devcount++;
-   return &((*current)->next);
 }
 
-Gpm_Type *(*I_serial)(int fd, unsigned short flags, struct Gpm_Type *type,
-		      int argc, char **argv);
+int (*I_serial)(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type);
 
 
 /*----------------------------------------------------------------------------- 
    Place the description here.
  -----------------------------------------------------------------------------*/
-int mousereopen(int oldfd, char *name, Gpm_Type *type)
+int mousereopen(struct micedev *dev, char *name, Gpm_Type *type, struct miceopt *opts)
 {
-   int fd;
    if (!type) type=mice+1; /* ms */
-   close(oldfd);
+   close(dev->fd);
    usleep(100000);
-   fd=open(name,O_RDWR);
-   if (fd < 0) gpm_report(GPM_PR_OOPS,name);
-   (*I_serial)(fd,type->flags,type,1,&type->name); /* ms initialization */
-   return fd;
+   dev->fd=open(name,O_RDWR);
+   if (dev->fd < 0) gpm_report(GPM_PR_OOPS,name);
+   I_serial(dev, opts, type); /* ms initialization */
+   return dev->fd;
 }
 
 int noneofthem(void)
@@ -281,10 +269,9 @@
 {
    struct item *list=NULL;
    struct item **nextitem;
-   struct device *devlist=NULL;
-   struct device **nextdev;
+   struct device *nextdev;
    Gpm_Type *cursor;
-   int i, mousefd;
+   int i;
    char *mousename;
 #define BUFLEN 512
    char buf[BUFLEN];
@@ -294,6 +281,9 @@
    int trial, readamount,packetsize,got;
    int baudtab[4]={1200,9600,4800,2400};
 #define BAUD(i) (baudtab[(i)%4])
+   struct miceopt opt = {0};
+   struct micedev mdev = {0};
+
    consolename = Gpm_get_console();
 
    if (!isatty(fileno(stdin))) {
@@ -306,8 +296,8 @@
 
    /* init the list of possible devices */
 
-   for (nextdev=&devlist, i=1; i<argc; i++)
-      nextdev=gpm_makedev(nextdev,argv[i]);
+   for (i=1; i<argc; i++)
+      gpm_makedev(argv[i]);
 
    if (argc==1) { /* no cmdline, get all devices */
       FILE *f;
@@ -320,7 +310,7 @@
       if (!f) gpm_report(GPM_PR_OOPS,"popen()");
       while (fgets(s,64,f)) {
          s[strlen(s)-1]='\0'; /* trim '\n' */
-         nextdev=gpm_makedev(nextdev,s);
+         gpm_makedev(s);
       }
       pclose(f);
    }
@@ -345,19 +335,18 @@
 
       /* BUG */ /* Logitech initialization is not performed */
 
-      opt_baud=BAUD(trial);
-      printf("\r\nTrying with %i baud\r\n",opt_baud);
+      opt.baud=BAUD(trial);
+      printf("\r\nTrying with %i baud\r\n",opt.baud);
       trial++;
 
       FD_ZERO(&devSet); FD_ZERO(&gotSet);
       FD_SET(fileno(stdin),&devSet); maxfd=fileno(stdin);
       printf("\r\n The possible device nodes are:\r\n");
-      for (nextdev=&devlist; *nextdev; nextdev=&((*nextdev)->next)) {
-         printf("\t%s\r\n", (*nextdev)->name);
-         FD_SET((*nextdev)->fd,&devSet);
-         maxfd=max((*nextdev)->fd,maxfd);
-         (*I_serial)((*nextdev)->fd,(mice+1)->flags,mice+1,
-		  1, &(mice+1)->name); /* try ms mode */
+      for (nextdev=devlist; nextdev; nextdev=nextdev->next) {
+         printf("\t%s\r\n", nextdev->name);
+         FD_SET(nextdev->mdev.fd, &devSet);
+         maxfd=max(nextdev->mdev.fd,maxfd);
+         I_serial(&nextdev->mdev, &opt, mice+1); /* try ms mode */
       }
 
       savSet=devSet;
@@ -379,43 +368,43 @@
             getchar();
             break;
          }
-         for (nextdev=&devlist; *nextdev; nextdev=&((*nextdev)->next))
-	         if (FD_ISSET((*nextdev)->fd,&devSet)) {
+         for (nextdev=devlist; nextdev; nextdev=nextdev->next)
+	         if (FD_ISSET(nextdev->mdev.fd,&devSet)) {
 	            gotthem++;
-	            FD_CLR((*nextdev)->fd,&savSet);
-	            FD_SET((*nextdev)->fd,&gotSet);
+	            FD_CLR(nextdev->mdev.fd,&savSet);
+	            FD_SET(nextdev->mdev.fd,&gotSet);
 	         }
       }
-      if (gotthem) for (nextdev=&devlist; *nextdev; /* nothing */ ) {
-	      cur=*nextdev;
-	      if (!FD_ISSET(cur->fd,&gotSet)) {
+      if (gotthem) for (nextdev=devlist; nextdev; /* nothing */ ) {
+	      cur=nextdev;
+	      if (!FD_ISSET(cur->mdev.fd,&gotSet)) {
 	         printf("removing \"%s\" from the list\r\n",cur->name);
-	         *nextdev=cur->next;
-	         close(cur->fd);
+	         nextdev=cur->next;
+	         close(cur->mdev.fd);
 	         free(cur->name);
 	         free(cur);
 	         devcount--;
 	      } else {
-	         read(cur->fd,buf,80); /* flush */
-	         nextdev=&(cur->next); /* follow list */
+	         read(cur->mdev.fd,buf,80); /* flush */
+	         nextdev=cur->next; /* follow list */
 	      }
 	   }
     
    } /* devcount>1 */
 
-   mousefd=devlist->fd;
+   mdev=devlist->mdev;
    mousename=devlist->name;
    free(devlist);
    printf("\r\nOk, so your mouse device is \"%s\"\r\n",mousename);
 
    /* now close and reopen it, complete with initialization */
-   opt_baud=BAUD(0);
-   mousefd=mousereopen(mousefd,mousename,NULL);
-  
+   opt.baud=BAUD(0);
+   mousereopen(&mdev, mousename, NULL,&opt);
+   
    FD_ZERO(&checkSet);
-   FD_SET(mousefd,&checkSet);
+   FD_SET(mdev.fd,&checkSet);
    FD_SET(fileno(stdin),&checkSet);
-   maxfd=max(mousefd,fileno(stdin));
+   maxfd=max(mdev.fd, fileno(stdin));
 
 /*====================================== Identify mouse type */
   
@@ -440,7 +429,7 @@
    printf("\r\nNow please press and release your left mouse button,\r\n"
 	 "one time only\r\n\r\n");
 
-   i=read(mousefd,buf,1);
+   i=read(mdev.fd, buf, 1);
    if (i==-1 && errno==EINVAL)
       readamount=3;
    else
@@ -466,7 +455,7 @@
       else
          nextitem=&(cur->next);
    }
-   read(mousefd,buf,BUFLEN); /* flush */
+   read(mdev.fd, buf, BUFLEN); /* flush */
 
 /*====================================== Packet size - second step */
 
@@ -484,12 +473,12 @@
    while (packetsize==1) {
       int success3=0,success5=0;
 	
-      opt_baud=BAUD(trial);
-      printf("\tBaud rate is %i\r\n",opt_baud);
-      mousefd=mousereopen(mousefd,mousename,NULL);
+      opt.baud=BAUD(trial);
+      printf("\tBaud rate is %i\r\n",opt.baud);
+      mousereopen(&mdev, mousename,NULL, &opt);
 	
       printf("\r\n==> Detecting the packet size\r\n");
-      got=eventlist(mousefd,buf,BUFLEN,GPM_B_LEFT,readamount);
+      got=eventlist(mdev.fd,buf,BUFLEN,GPM_B_LEFT,readamount);
 	
       /* try three -- look at repeating arrays of 6 bytes */
       for (i=0;i<got-12;i++)
@@ -512,8 +501,7 @@
       trial++;
    }
 
-/*====================================== Use that info to discard protocols */
-  
+/*====================================== Use that info to discard protocols */ 
    for (nextitem=&list; *nextitem; /* nothing */) {
       struct item *cur=*nextitem;
       int packetheads=0;
@@ -530,7 +518,7 @@
          if ( ((buf[i]  &(cur->this->proto)[0]) == (cur->this->proto)[1])
 	      && ((buf[i+1]&(cur->this->proto)[2]) == (cur->this->proto)[3]) ) {
 	         packetheads++;
-	         if ((*(cur->this->fun))(&event,buf+i)==-1) {
+	         if ((*(cur->this->fun))(&mdev, &opt, buf+i, &event)==-1) {
                packetheads--;
                continue;
             }
@@ -594,7 +582,7 @@
  * First trial: remove the "-t ms" extension if spurious buttons come in
  */
 
-   got=eventlist(mousefd,buf,BUFLEN,0,readamount);
+   got=eventlist(mdev.fd,buf,BUFLEN,0,readamount);
    pending=0;
    for (nextitem=&list; *nextitem; /* nothing */) {
       struct item *cur=*nextitem;
@@ -604,7 +592,7 @@
       for (i=0;i<got;i++) {
          if ( ((buf[i]  &(cur->this->proto)[0]) == (cur->this->proto)[1])
             && ((buf[i+1]&(cur->this->proto)[2]) == (cur->this->proto)[3]) ) {
-               if ((*(cur->this->fun))(&event,buf+i)==-1) continue;
+               if ((*(cur->this->fun))(&mdev, &opt, buf+i, &event)==-1) continue;
                i+=packetsize-1;
                if (event.buttons) pending--;
          }
@@ -624,8 +612,8 @@
  */
 
    printf("\r\n==> Looking for '-t mman'and enhanced ms\r\n");
-   mousefd=mousereopen(mousefd,mousename, mice /* mman */);
-   got=eventlist(mousefd,buf,BUFLEN,GPM_B_MIDDLE,readamount);
+   mousereopen(&mdev, mousename, mice /* mman */, &opt);
+   got=eventlist(mdev.fd, buf, BUFLEN, GPM_B_MIDDLE, readamount);
 
    /* if it uses the 4-byte protocol, find it in a rude way */
    for (pending=0,i=0;i<got-16;i++)
@@ -646,7 +634,7 @@
       for (i=0;i<got;i++) {
          if ( ((buf[i]  &(cur->this->proto)[0]) == (cur->this->proto)[1])
             && ((buf[i+1]&(cur->this->proto)[2]) == (cur->this->proto)[3]) ) {
-               if ((*(cur->this->fun))(&event,buf+i)==-1) continue;
+               if ((*(cur->this->fun))(&mdev,&opt,buf+i,&event)==-1) continue;
                i+=packetsize-1;
                if (event.buttons && event.buttons!=GPM_B_MIDDLE) pending--;
 	            if (event.buttons==GPM_B_MIDDLE) pending++;
@@ -677,16 +665,16 @@
       char *Xtognames[3]={"'ClearDTR' and 'ClearRTS'","'ClearDTR'","'ClearRTS'"}; 
       int alllines,lines, index;
 
-      ioctl(mousefd, TIOCMGET, &alllines);
+      ioctl(mdev.fd, TIOCMGET, &alllines);
 
       printf("\r\nSome mice change protocol to three-buttons-aware if some\r\n"
 		   "\r\ncontrol lines are toggled after opening\r\n");
       for (index=0;index<3;index++) {
-         mousereopen(mousefd,mousename,NULL);
+         mousereopen(&mdev, mousename, NULL, &opt);
          lines = alllines & ~toggle[index];
-         ioctl(mousefd, TIOCMSET, &lines);
+         ioctl(mdev.fd, TIOCMSET, &lines);
          printf("\r\n==> Trying with '-o %s'\r\n",tognames[index]);
-         got=eventlist(mousefd,buf,BUFLEN,GPM_B_MIDDLE,readamount);
+         got=eventlist(mdev.fd, buf, BUFLEN, GPM_B_MIDDLE, readamount);
     
          /* if it uses the 5-byte protocol, find it in a rude way */
          for (pending=0,i=0;i<got-20;i++)
@@ -717,7 +705,7 @@
 	
    getchar();
 
-   got=eventlist(mousefd,buf,BUFLEN,GPM_B_MIDDLE,readamount);
+   got=eventlist(mdev.fd,buf,BUFLEN,GPM_B_MIDDLE,readamount);
 
    /* if it uses the 5-byte protocol, find it in a rude way */
    for (pending=0,i=0;i<got-20;i++)
diff -urN gpm-1.20.1/src/report.c gpm/src/report.c
--- gpm-1.20.1/src/report.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/report.c	2003-10-02 01:22:42.000000000 -0500
@@ -31,6 +31,7 @@
 
 #include "headers/gpmInt.h"
 #include "headers/message.h"
+#include "headers/console.h"
 
 /*
  * gpm_report
@@ -70,7 +71,7 @@
 
 void gpm_report(int line, char *file, int stat, char *text, ... )
 {
-   FILE *console = NULL;
+   FILE *f = NULL;
    va_list ap;
 
    va_start(ap,text);
@@ -138,11 +139,11 @@
                syslog(LOG_DAEMON | LOG_WARNING, GPM_STRING_WARN);
                vsyslog(LOG_DAEMON | LOG_WARNING, text, ap);
 #endif               
-               if((console = fopen(GPM_SYS_CONSOLE,"a")) != NULL) {
-                  fprintf(console,GPM_STRING_WARN);
-                  vfprintf(console,text,ap);
-                  fprintf(console,"\n");
-                  fclose(console);
+               if ((f = fopen(GPM_SYS_CONSOLE, "a")) != NULL) {
+                  fprintf(f, GPM_STRING_WARN);
+                  vfprintf(f, text, ap);
+                  fprintf(f, "\n");
+                  fclose(f);
                }   
                break;
  
@@ -151,18 +152,18 @@
                syslog(LOG_DAEMON | LOG_ERR, GPM_STRING_ERR);
                vsyslog(LOG_DAEMON | LOG_ERR, text, ap);
 #endif               
-               if((console = fopen(GPM_SYS_CONSOLE,"a")) != NULL) {
-                  fprintf(console,GPM_STRING_ERR);
-                  vfprintf(console,text,ap);
-                  fprintf(console,"\n");
-                  fclose(console);
+               if ((f = fopen(GPM_SYS_CONSOLE, "a")) != NULL) {
+                  fprintf(f, GPM_STRING_ERR);
+                  vfprintf(f, text, ap);
+                  fprintf(f, "\n");
+                  fclose(f);
                }
 
-               if((console = fopen(option.consolename,"a")) != NULL) {
-                  fprintf(console,GPM_STRING_ERR);
-                  vfprintf(console,text,ap);
-                  fprintf(console,"\n");
-                  fclose(console);
+               if ((f = fopen(console.device, "a")) != NULL) {
+                  fprintf(f, GPM_STRING_ERR);
+                  vfprintf(f, text, ap);
+                  fprintf(f, "\n");
+                  fclose(f);
                }
                break;
 
@@ -184,24 +185,24 @@
       case GPM_RUN_DEBUG:
          switch(stat) {
             case GPM_STAT_INFO:
-               console = stdout;
-               fprintf(console,GPM_STRING_INFO); break;
+               f = stdout;
+               fprintf(f, GPM_STRING_INFO); break;
             case GPM_STAT_WARN:
-               console = stderr;
-               fprintf(console,GPM_STRING_WARN); break;
+               f = stderr;
+               fprintf(f, GPM_STRING_WARN); break;
             case GPM_STAT_ERR:
-               console = stderr;
-               fprintf(console,GPM_STRING_ERR); break;
+               f = stderr;
+               fprintf(f, GPM_STRING_ERR); break;
             case GPM_STAT_DEBUG:
-               console = stderr;
-               fprintf(console,GPM_STRING_DEBUG); break;
+               f = stderr;
+               fprintf(f, GPM_STRING_DEBUG); break;
             case GPM_STAT_OOPS:
-               console = stderr;
-               fprintf(console,GPM_STRING_OOPS); break;
+               f = stderr;
+               fprintf(f, GPM_STRING_OOPS); break;
          }
 
-         vfprintf(console,text,ap);
-         fprintf(console,"\n");
+         vfprintf(f, text, ap);
+         fprintf(f, "\n");
          
          if(stat == GPM_STAT_OOPS) exit(1);
 
diff -urN gpm-1.20.1/src/selection.c gpm/src/selection.c
--- gpm-1.20.1/src/selection.c	1969-12-31 19:00:00.000000000 -0500
+++ gpm/src/selection.c	2003-10-02 01:22:42.000000000 -0500
@@ -0,0 +1,156 @@
+/*
+ * console.c - GPM console and selection/paste handling
+ *
+ * Copyright (C) 1993        Andreq Haylett <ajh@gec-mrc.co.uk>
+ * Copyright (C) 1994-1999   Alessandro Rubini <rubini@linux.it>
+ * Copyright (C) 1998        Ian Zimmerman <itz@rahul.net>
+ * Copyright (c) 2001,2002   Nico Schottelius <nico@schottelius.org>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>        /* strerror(); ?!?  */
+#include <errno.h>
+#include <unistd.h>        /* select(); */
+#include <time.h>          /* time() */
+#include <sys/fcntl.h>     /* O_RDONLY */
+#include <sys/stat.h>      /* mkdir()  */
+#include <asm/types.h>     /* __u32 */
+
+#include <linux/vt.h>      /* VT_GETSTATE */
+#include <sys/kd.h>        /* KDGETMODE */
+#include <termios.h>       /* winsize */
+
+#include "headers/gpmInt.h"
+#include "headers/message.h"
+#include "headers/console.h"
+#include "headers/selection.h"
+
+struct sel_options sel_opts = { 0, 0, DEF_PTRDRAG };
+static time_t last_selection_time;
+
+/*-------------------------------------------------------------------*/
+static void selection_copy(int x1, int y1, int x2, int y2, int mode)
+{
+/*
+ * The approach in "selection" causes a bus error when run under SunOS 4.1
+ * due to alignment problems...
+ */
+   unsigned char buf[6 * sizeof(short)];
+   unsigned short *arg = (unsigned short *)buf + 1;
+   int fd;
+
+   buf[sizeof(short) - 1] = 2;  /* set selection */
+
+   arg[0] = (unsigned short)x1;
+   arg[1] = (unsigned short)y1;
+   arg[2] = (unsigned short)x2;
+   arg[3] = (unsigned short)y2;
+   arg[4] = (unsigned short)mode;
+
+   if ((fd = open_console(O_WRONLY)) < 0)
+      gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN_CON);
+
+   gpm_report(GPM_PR_DEBUG, "ctl %i, mode %i", (int)*buf, arg[4]);
+   if (ioctl(fd, TIOCLINUX, buf + sizeof(short) - 1) < 0)
+      gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_TIOCLINUX);
+   close(fd);
+
+   if (mode < 3) {
+      sel_opts.aged = 0;
+      last_selection_time = time(0);
+   }
+}
+
+/*-------------------------------------------------------------------*/
+static void selection_paste(void)
+{
+   char c = 3;
+   int fd;
+
+   if (!sel_opts.aged && 
+      sel_opts.age_limit != 0 &&
+      last_selection_time + sel_opts.age_limit < time(0)) {
+      sel_opts.aged = 1;
+   }
+
+   if (sel_opts.aged) {
+      gpm_report(GPM_PR_DEBUG, GPM_MESS_SKIP_PASTE);
+   } else {
+      fd = open_console(O_WRONLY);
+      if (ioctl(fd, TIOCLINUX, &c) < 0)
+         gpm_report(GPM_PR_OOPS, GPM_MESS_IOCTL_TIOCLINUX);
+      close(fd);
+   }
+}
+
+/*-------------------------------------------------------------------*/
+void do_selection(Gpm_Event *event, int three_button_mode)
+{
+   static int x1 = 1, y1 = 1;
+   int x2, y2;
+
+   x2 = event->x; y2 = event->y;
+   switch(GPM_BARE_EVENTS(event->type)) {
+      case GPM_MOVE:
+         if (x2 < 1) x2++; else if (x2 > console.max_x) x2--;
+         if (y2 < 1) y2++; else if (y2 > console.max_y) y2--;
+         selection_copy(x2, y2, x2, y2, 3); /* just highlight pointer */
+         break;
+
+      case GPM_DRAG:
+         if (event->buttons == GPM_B_LEFT) {
+            switch(event->margin) { /* fix margins */
+               case GPM_TOP: x2 = 1; y2++; break;
+               case GPM_BOT: x2 = console.max_x; y2--; break;
+               case GPM_RGT: x2--; break;
+               case GPM_LFT: y2 <= y1 ? x2++ : (x2 = console.max_x, y2--); break;
+               default: break;
+            }
+            selection_copy(x1, y1, x2, y2, event->clicks);
+            if (event->clicks >= sel_opts.ptrdrag && !event->margin) /* pointer */
+               selection_copy(x2, y2, x2, y2, 3);
+         } /* if */
+         break;
+
+      case GPM_DOWN:
+         switch (event->buttons) {
+            case GPM_B_LEFT:
+               x1 = x2; y1 = y2;
+               selection_copy(x1, y1, x2, y2, event->clicks); /* start selection */
+               break;
+
+            case GPM_B_MIDDLE:
+               selection_paste();
+               break;
+
+            case GPM_B_RIGHT:
+               if (three_button_mode == 1)
+                  selection_copy(x1, y1, x2, y2, event->clicks);
+               else
+                  selection_paste();
+               break;
+         }
+   } /* switch above */
+}
+
+/*-------------------------------------------------------------------*/
+void selection_disable_paste(void)
+{
+   sel_opts.aged = 1;
+}
diff -urN gpm-1.20.1/src/server_tools.c gpm/src/server_tools.c
--- gpm-1.20.1/src/server_tools.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/server_tools.c	2003-10-02 01:22:42.000000000 -0500
@@ -21,151 +21,80 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  ********/
 
+#include <string.h>
+#include <stdlib.h> /* malloc() */
+#include <sys/fcntl.h>
+
 #include "headers/gpmInt.h"
 #include "headers/message.h"
 
-#include <stdlib.h> /* malloc() */
+struct micetab *micelist;
 
-/* DESCR:   add this to the list of mice. initialization follows later */
-/* RETURN:  - */
+/* DESCR:   allocate a new mouse and to the list of mice. initialization follows later */
+/* RETURN:  new mouse structure */
 /* COMMENT: does error handling and exiting itself */
-void add_mouse(int type, char *value)
+struct micetab *add_mouse(void)
 {
-   struct micetab *tmp = option.micelist;
+   struct micetab *mouse;
 
-   /* PREAMBLE for all work: */
-   /* -m /dev/misc/psaux -t ps2 [ -o options ] */
+   gpm_report(GPM_PR_DEBUG, "adding mouse device");
+   if (!(mouse = malloc(sizeof(struct micetab))))
+      gpm_report(GPM_PR_OOPS, GPM_MESS_NO_MEM);
+
+   memset(mouse, 0, sizeof(struct micetab));
+
+   mouse->dev.timeout = -1;
+
+   mouse->options.sequence = NULL;
+   mouse->options.sample = DEF_SAMPLE;
+   mouse->options.delta = DEF_DELTA;
+   mouse->options.accel = DEF_ACCEL;
+   mouse->options.scalex = DEF_SCALE;
+   mouse->options.scaley = DEF_SCALE;
+   mouse->options.time = DEF_TIME;
+   mouse->options.cluster = DEF_CLUSTER;
+   mouse->options.three_button = DEF_THREE;
+   mouse->options.glidepoint_tap = DEF_GLIDEPOINT_TAP;
+   mouse->options.text = NULL;
 
-   switch(type) {
+   mouse->next = micelist;
+   micelist = mouse;
 
-      /*---------------------------------------------------------------------*/
-      /********************** -m mousedevice *********************************/
-      /*---------------------------------------------------------------------*/
-
-      case GPM_ADD_DEVICE:
-
-         /* first invocation */
-         if(option.micelist == NULL) {
-            gpm_report(GPM_PR_DEBUG,"adding mouse device: %s",value);
-            option.micelist = (struct micetab *) malloc(sizeof(struct micetab));
-            if(!option.micelist) gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM);
-            option.micelist->next      = NULL;
-            option.micelist->device    = value;
-            option.micelist->protocol  = NULL;
-            option.micelist->options   = NULL;
-            return;
-         }
-         
-         /* find actual mouse */
-         while(tmp->device != NULL && tmp->protocol != NULL && tmp->next !=NULL)
-            tmp = tmp->next;
-
-         gpm_report(GPM_PR_DEBUG,"finished searching");
-
-         /* found end of micelist, add new mouse */
-         if(tmp->next == NULL && tmp->protocol != NULL) {
-            gpm_report(GPM_PR_DEBUG,"next mouse making");
-            tmp->next = (struct micetab *) malloc(sizeof(struct micetab));
-            if(!tmp) gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM);
-            tmp->next      = NULL;
-            tmp->device    = value;
-            tmp->protocol  = NULL;
-            tmp->options   = NULL;
-            return;
-         } else gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV);
-         
-         //} else if(tmp->device != NULL && tmp->protocol == NULL)
-         // gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV); /* -m -m */
-
-         
-         break;
-
-      /*---------------------------------------------------------------------*/
-      /************************* -t type / protocol **************************/
-      /*---------------------------------------------------------------------*/
-
-      case GPM_ADD_TYPE:
-         if(option.micelist == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV);
-         
-         /* skip to next mouse, where either device or protocol is missing */
-         while(tmp->device != NULL && tmp->protocol != NULL && tmp->next !=NULL)
-            tmp = tmp->next;
-         
-         /* check whether device (-m) is there, if so, write protocol */
-         if(tmp->device == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV);
-         else {
-            gpm_report(GPM_PR_DEBUG,"adding mouse type: %s",value);
-            tmp->protocol = value;
-            option.no_mice++;          /* finally we got our mouse */
-         }
-
-         break;
-
-      /*---------------------------------------------------------------------*/
-      /*************************** -o options ********************************/
-      /*---------------------------------------------------------------------*/
-
-      case GPM_ADD_OPTIONS:
-         if(option.micelist == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV);
-
-         /* look for the last mouse */
-         tmp = option.micelist;
-         while(tmp->next != NULL) tmp = tmp->next;
-
-         /* if -m or -t are missing exit */
-         if(tmp->device == NULL || tmp->protocol == NULL)
-            gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV);
-         else {
-            gpm_report(GPM_PR_DEBUG,"adding mouse options: %s",value);
-            tmp->options = value;
-         }   
-         break;
-   }
+   return mouse;
 }
 
-/* DESCR:   mice initialization. currently print mice. */
-/* RETURN:  0 - failed to init one or more devices 
-            1 - init was fine */
+/* DESCR:   mice initialization. calls appropriate init functions. */
 /* COMMENT: does error handling and exiting itself */
-int init_mice(struct micetab *micelist)
+void init_mice(void)
 {
-   struct micetab *tmp = micelist;
+   struct micetab *mouse;
+   
+   for (mouse = micelist; mouse; mouse = mouse->next) {
+      if (!strcmp(mouse->device, "-"))
+         mouse->dev.fd = 0; /* use stdin */
+      else if ((mouse->dev.fd = open(mouse->device, O_RDWR | O_NDELAY)) < 0)
+         gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, mouse->device);
    
-   while(tmp != NULL) {           /* there are still mice to init */
-      gpm_report(GPM_PR_DEBUG,"initialize %s with proto %s",tmp->device,tmp->protocol);
-      if(tmp->options != NULL) {
-         gpm_report(GPM_PR_DEBUG,"and options %s",tmp->options);
-      }
-      tmp = tmp->next;
+      /* and then reset the flag */
+      fcntl(mouse->dev.fd, F_SETFL, fcntl(mouse->dev.fd, F_GETFL) & ~O_NDELAY);
+   
+      /* init the device, and use the return value as new mouse type */
+      if (mouse->type->init)
+         if (mouse->type->init(&mouse->dev, &mouse->options, mouse->type))
+            gpm_report(GPM_PR_OOPS, GPM_MESS_MOUSE_INIT);
    }
-
-   gpm_report(GPM_PR_DEBUG,"finished initialization");
-   return 1;
 }
 
 /* DESCR:   when leaving, we should reset mice to their normal state */
-/* RETURN:  0 - failed to reset one or more devices 
-            1 - reset was fine */
 /* COMMENT: does error handling and exiting itself */
-int reset_mice(struct micetab *micelist)
+void cleanup_mice(void)
 {
-   struct micetab *tmp = micelist;
-   struct micetab *end = tmp;
-
-   while(tmp != NULL) { /* FIXME! I never get NULL, as free()d before */
-      end = tmp;
-      while(tmp->next != NULL) {       /* set end to the last mouse */
-         end = tmp;
-         tmp = tmp->next;
-      }
-
-      gpm_report(GPM_PR_DEBUG,"reset: %s with proto %s",end->device,end->protocol);
-      if(tmp->options != NULL) {
-         gpm_report(GPM_PR_DEBUG,"and options %s",end->options);
-      }
-      free(end);                       /* be clean() */
-      tmp = micelist;                  /* reset to the first mice again */
+   struct micetab *tmp;
+   
+   while ((tmp = micelist)) {
+      if (micelist->dev.private)
+         free(micelist->dev.private);
+      micelist = micelist->next;
+      free(tmp);
    }   
-
-   return 1;
 }
diff -urN gpm-1.20.1/src/special.c gpm/src/special.c
--- gpm-1.20.1/src/special.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/special.c	2003-10-02 01:22:42.000000000 -0500
@@ -37,6 +37,7 @@
 #include <sys/param.h>
 
 #include "headers/gpmInt.h"
+#include "headers/console.h"
 
 /*
  * This function is only called at button press, to avoid unnecessary
@@ -78,7 +79,7 @@
     return 1;
 
   /* devfs change */
-  consolef=fopen(option.consolename,"w");
+  consolef = fopen(console.device, "w");
   if (!consolef) consolef=stderr;
   if (event->type & GPM_TRIPLE) /* just triggered: make noise and return */
     {
@@ -153,7 +154,7 @@
     case 0: /* child */
       close(0); close(1); close(2);
       open(GPM_NULL_DEV,O_RDONLY); /* stdin  */
-      open(option.consolename,O_WRONLY); /* stdout */
+      open(console.device, O_WRONLY); /* stdout */
       dup(1);                     /* stderr */
       for (i=3;i<OPEN_MAX; i++) close(i);
       execl("/bin/sh","sh","-c",command,(char *)NULL);
diff -urN gpm-1.20.1/src/startup.c gpm/src/startup.c
--- gpm-1.20.1/src/startup.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/startup.c	2003-10-02 01:22:42.000000000 -0500
@@ -26,6 +26,7 @@
 #include <string.h>     /* strlen() */
 #include <errno.h>      /* errno */
 #include <unistd.h>     /* unlink,geteuid */
+#include <signal.h>
 #include <sys/types.h>  /* geteuid, mknod */
 #include <sys/stat.h>   /* mknod */
 #include <fcntl.h>      /* mknod */
@@ -34,11 +35,13 @@
 
 #include "headers/gpmInt.h"
 #include "headers/message.h"
+#include "headers/console.h"
+#include "headers/selection.h"
 
 /* what todo atexit */
 static void gpm_exited(void)
 {
-   gpm_report(GPM_PR_DEBUG,GPM_MESS_REMOVE_FILES, GPM_NODE_PID, GPM_NODE_CTL);
+   gpm_report(GPM_PR_DEBUG, GPM_MESS_REMOVE_FILES, GPM_NODE_PID, GPM_NODE_CTL);
    unlink(GPM_NODE_PID);
    unlink(GPM_NODE_CTL);
 }
@@ -48,34 +51,12 @@
    extern struct options option;
    extern int errno;
 
-   int i,opt;
-
-   static struct {
-      char *in;
-      char *out;
-   } seq[] = {
-      {"123","01234567"},
-      {"132","02134657"},
-      {"213","01452367"}, /* warning: these must be readable as integers... */
-      {"231","02461357"},
-      {"312","04152637"},
-      {"321","04261537"},
-      {NULL,NULL}
-   };
-   
    /* basic settings */
    option.run_status    = GPM_RUN_STARTUP;      /* 10,9,8,... let's go */
    option.autodetect    = 0;                    /* no mouse autodection */
    option.progname      = argv[0];              /* who we are */
-   option.consolename   = Gpm_get_console();    /* get consolename */
-
-   /* basic2: are not necessary for oops()ing, if not root */
-   option.no_mice       = 0;                    /* counts -m + -t */
-   option.micelist      = NULL;                 /* no mice found yet */
-   option.repeater      = 0;                    /* repeat data */
-   option.repeater_type = NULL;                 /* type of */
-
 
+   get_console_name();
    cmdline(argc, argv);                         /* parse command line */
 
    if (geteuid() != 0) gpm_report(GPM_PR_OOPS,GPM_MESS_ROOT); /* root or exit */
@@ -87,54 +68,18 @@
    /****************** OLD CODE from gpn.c ***********************/
    
    openlog(option.progname, LOG_PID,
-                  option.run_status != GPM_RUN_DEBUG ? LOG_DAEMON : LOG_USER);
-   loadlut(opt_lut);
-
-   if (option.repeater) {
-      if(mkfifo(GPM_NODE_FIFO,0666) && errno!=EEXIST)
-         gpm_report(GPM_PR_OOPS,GPM_MESS_CREATE_FIFO,GPM_NODE_FIFO);
-      if((fifofd=open(GPM_NODE_FIFO, O_RDWR|O_NONBLOCK)) < 0)
-         gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, GPM_NODE_FIFO);
-   }
-
-   /* duplicate initialization */
-   for (i=1; i <= 1+opt_double; i++) {
-      which_mouse=mouse_table+i; /* used to access options */
-      if (opt_accel < 1) exit(usage("acceleration"));
-      if (opt_delta < 2) exit(usage("delta"));
-      if (strlen(opt_sequence) != 3 || atoi(opt_sequence)<100)
-         exit(usage("sequence"));
-      if (opt_glidepoint_tap > 3) exit(usage("glidepoint tap button"));
-      if (opt_glidepoint_tap)
-         opt_glidepoint_tap=GPM_B_LEFT >> (opt_glidepoint_tap-1);
-
-      /* choose the sequence */
-      for (opt=0; seq[opt].in && strcmp(seq[opt].in,opt_sequence); opt++) ;
-      if(!seq[opt].in) exit(usage("button sequence"));
-      opt_sequence=strdup(seq[opt].out); /* I can rewrite on it */
-
-      /* look for the mouse type */
-      m_type = find_mouse_by_name(opt_type);
-      if (!m_type) /* not found */
-         exit(M_listTypes());
-   }
+           option.run_status != GPM_RUN_DEBUG ? LOG_DAEMON : LOG_USER);
 
-   /* Check repeater status */
-   if (option.repeater) {
-      if (strcmp(option.repeater_type,"raw") == 0)
-         opt_rawrep = 1;
-      else {
-         /* look for the type */
-         repeated_type = find_mouse_by_name(option.repeater_type);
+   console_load_lut();
 
-         if(!repeated_type) exit(M_listTypes()); /* not found */
-
-         if (!(repeated_type->repeat_fun)) /* unsupported translation */
-            gpm_report(GPM_PR_OOPS,GPM_MESS_NO_REPEAT,option.repeater_type);
-      }
+   if (repeater.raw || repeater.type) {
+      if (mkfifo(GPM_NODE_FIFO, 0666) && errno != EEXIST)
+         gpm_report(GPM_PR_OOPS, GPM_MESS_CREATE_FIFO, GPM_NODE_FIFO);
+      if ((repeater.fd = open(GPM_NODE_FIFO, O_RDWR|O_NONBLOCK)) < 0)
+         gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, GPM_NODE_FIFO);
    }
 
-   if(option.run_status == GPM_RUN_STARTUP ) { /* else is debugging */
+   if(option.run_status == GPM_RUN_STARTUP) { /* else is debugging */
       /* goto background and become a session leader (Stefan Giessler) */  
       switch(fork()) {
          case -1: gpm_report(GPM_PR_OOPS,GPM_MESS_FORK_FAILED);   /* error  */
@@ -152,13 +97,63 @@
    /* is changing to root needed, because of relative paths ? or can we just
     * remove and ignore it ?? FIXME */
    if (chdir("/") < 0) gpm_report(GPM_PR_OOPS,GPM_MESS_CHDIR_FAILED);
-
    
-   //return mouse_table[1].fd; /* the second is handled in the main() */
+   atexit(gpm_exited);                          /* call gpm_exited at the end */
+}
 
-   /****************** OLD CODE from gpn.c  END ***********************/
+/* itz Sat Sep 12 10:30:05 PDT 1998 this function used to mix two
+   completely different things; opening a socket to a running daemon
+   and checking that a running daemon existed.  Ugly. */
+/* rewritten mostly on 20th of February 2002 - nico */   
+void check_uniqueness(void)
+{
+   FILE *fp    =  0;
+   int old_pid = -1;
 
-   init_mice(option.micelist);                  /* reads option.micelist */
-   atexit(gpm_exited);                          /* call gpm_exited at the end */
+   if ((fp = fopen(GPM_NODE_PID, "r")) != NULL) {
+      fscanf(fp, "%d", &old_pid);
+      if (kill(old_pid, 0) == -1) {
+         gpm_report(GPM_PR_INFO,GPM_MESS_STALE_PID, GPM_NODE_PID);
+         unlink(GPM_NODE_PID);
+      } else /* we are really running, exit asap! */ 
+         gpm_report(GPM_PR_OOPS, GPM_MESS_ALREADY_RUN, old_pid);
+   }
+   /* now try to sign ourself */
+   if ((fp = fopen(GPM_NODE_PID,"w")) != NULL) {
+      fprintf(fp,"%d\n",getpid());
+      fclose(fp);
+   } else {
+      gpm_report(GPM_PR_OOPS,GPM_MESS_NOTWRITE,GPM_NODE_PID);
+   }
+}
 
+/* itz Sat Sep 12 10:55:51 PDT 1998 Added this as replacement for the
+   unwanted functionality in check_uniqueness. */
+void kill_gpm(void)
+{
+   int old_pid;
+   FILE* fp = fopen(GPM_NODE_PID, "r");
+ 
+   /* if we cannot find the old pid file, leave */
+   if (fp == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN, GPM_NODE_PID);
+  
+   /* else read the pid */
+   if (fscanf(fp, "%d", &old_pid) != 1)
+      gpm_report(GPM_PR_OOPS, GPM_MESS_READ_PROB, GPM_NODE_PID);
+   fclose(fp);
+
+   gpm_report(GPM_PR_DEBUG, GPM_MESS_KILLING, old_pid);
+
+   /* first check if we run */
+   if (kill(old_pid,0) == -1) {
+      gpm_report(GPM_PR_INFO, GPM_MESS_STALE_PID, GPM_NODE_PID);
+      unlink(GPM_NODE_PID);
+   }
+   /* then kill us (not directly, but the other instance ... ) */
+   if (kill(old_pid, SIGTERM) == -1)
+      gpm_report(GPM_PR_OOPS, GPM_MESS_CANT_KILL, old_pid);
+ 
+   gpm_report(GPM_PR_INFO, GPM_MESS_KILLED, old_pid);
+   exit(0);
 }
+
diff -urN gpm-1.20.1/src/synaptics.c gpm/src/synaptics.c
--- gpm-1.20.1/src/synaptics.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/synaptics.c	2003-10-02 01:22:42.000000000 -0500
@@ -865,7 +865,7 @@
 static int           scrolling_speed_timer = 0;
 static int           scrolling_amount_left = 0;   /* Tells how much to scroll up or down */
 
-
+static int           mouse_fd;      
 
 
 
@@ -882,6 +882,7 @@
 ** 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) 
@@ -934,7 +935,7 @@
 	      (multi_finger_pressure>4500 && multi_finger_xy>50000? 'f':' '));
 
 }
-
+#endif
 
 /* syn_dump_info
 **
@@ -1158,8 +1159,8 @@
 	status = GPM_B_NOT_SET;
 	break;
       case Reset_Touchpad_Action:
-	syn_ps2_reset(which_mouse->fd);
-	syn_ps2_absolute_mode(which_mouse->fd);
+	syn_ps2_reset(mouse_fd);
+	syn_ps2_absolute_mode(mouse_fd);
 	status = GPM_B_NOT_SET;
 	break;
       case Toggle_Four_Way_Button_Action:
@@ -2950,10 +2951,8 @@
 	     data [0],data [1],data [2],data [3],data [4],data [5]);
 
   if (reset_on_error_enabled) {
-    /* Hack to get the fd: which_mouse is the current mouse,
-       and as the synaptic code is called, it is the current mouse. */
-    syn_ps2_reset(which_mouse->fd);
-    syn_ps2_absolute_mode(which_mouse->fd);
+    syn_ps2_reset(mouse_fd);
+    syn_ps2_absolute_mode(mouse_fd);
   }
   
   report->left        = 0;
@@ -3108,7 +3107,7 @@
 **
 ** Process the touchpad 6 byte report.
 */
-void syn_process_serial_data (Gpm_Event *state,
+void syn_process_serial_data (int fd, Gpm_Event *state,
 			      unsigned char *data) 
 {
   /* initialize the state */
@@ -3116,6 +3115,8 @@
   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);
@@ -3196,7 +3197,7 @@
 **
 ** Process the touchpad 6 byte report.
 */
-void syn_process_ps2_data (Gpm_Event *state,
+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]); */
@@ -3206,6 +3207,7 @@
   state->dx      = 0;
   state->dy      = 0;
 
+  mouse_fd = fd; /* cheat */
 
   if (wmode_enabled) {
     syn_ps2_translate_wmode_data (data, &cur_report);
diff -urN gpm-1.20.1/src/tools.c gpm/src/tools.c
--- gpm-1.20.1/src/tools.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/tools.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,93 +0,0 @@
-/*
- * tools.c - tools which are needed by client and server
- *
- * Copyright (c) 2001 	     Nico Schottelius <nico@schottelius.org>
- *
- *   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 <stdio.h> /* NULL */
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>  /* these three are */
-#include <sys/stat.h>   /* needed for      */
-#include <unistd.h>     /* stat() */
-
-#include "headers/gpmInt.h"   /* only used for some defines */
-#include "headers/message.h"
-
-/*****************************************************************************
- * check, whether devfs is used or not.
- * See /usr/src/linux/Documentation/filesystems/devfs/ for details.
- * Returns: the name of the console (/dev/tty0 or /dev/vc/0)
- *****************************************************************************/
-char *Gpm_get_console( void )
-{
-
-   char *back = NULL, *tmp = NULL;
-   struct stat buf;
-
-   /* first try the devfs device, because in the next time this will be
-    * the preferred one. If that fails, take the old console */
-   
-   /* Check for open new console */
-   if (stat(GPM_DEVFS_CONSOLE,&buf) == 0)
-      tmp = GPM_DEVFS_CONSOLE;
-  
-   /* Failed, try OLD console */
-   else if(stat(GPM_OLD_CONSOLE,&buf) == 0)
-      tmp = GPM_OLD_CONSOLE;
-  
-   if(tmp != NULL)
-      if((back = malloc(strlen(tmp) + sizeof(char)) ) != NULL)
-         strcpy(back,tmp);
-
-   return(back);
-}
-
-/* what's the english name for potenz ? */
-int Gpm_x_high_y(int base, int pot_y)
-{
-   int val = 1;
-   
-   if(pot_y == 0) val = 1;
-   else if(pot_y  < 0) val = 0;     /* ugly hack ;) */
-   else while(pot_y > 0) {
-      val = val * base;
-      pot_y--;
-   }   
-   return val;
-}   
-      
-/* return characters needed to display int */
-int Gpm_cnt_digits(int number)
-{
-   /* 0-9 = 1        10^0 <-> (10^1)-1
-    * 10 - 99 = 2    10^1 <-> (10^2)-1
-    * 100 - 999 = 3  10^2 <-> (10^3)-1
-    * 1000 - 9999 = 4 ...  */
-   
-   int ret = 0, num = 0;
-
-   /* non negative, please */
-   if(number < 0) number *= -1;
-   else if(number == 0) ret = 1;
-   else while(number > num) {
-      ret++;
-      num = (Gpm_x_high_y(10,ret) - 1);
-   }   
-
-   return(ret);
-}      
diff -urN gpm-1.20.1/src/twiddler.c gpm/src/twiddler.c
--- gpm-1.20.1/src/twiddler.c	2002-12-24 17:57:16.000000000 -0500
+++ gpm/src/twiddler.c	2003-10-02 01:22:42.000000000 -0500
@@ -54,6 +54,7 @@
 #include "headers/gpm.h"
 #include "headers/gpmInt.h"
 #include "headers/message.h"
+#include "headers/console.h"
 #include "headers/twiddler.h"
 
 
@@ -134,17 +135,6 @@
    int (*fun)(char *string);
 };
 
-
-/* The same silly function as in gpm.c */
-static inline int open_console(const int mode)
-{
-   int fd;
-   extern struct options option;
-   if ((fd=open(option.consolename, mode)) < 0) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,option.consolename);
-   return fd;
-}
-
-
 /*===================================================================*/
 /*              This part deals with pushing keys                  */
 
@@ -175,7 +165,7 @@
 int twiddler_exec(char *s)
 {
    int pid;
-   extern struct options option;
+   
    switch(pid=fork()) {
       case -1: return -1;
       case 0:
@@ -184,7 +174,7 @@
          close(2); /* very rude! */
       
          open(GPM_NULL_DEV,O_RDONLY);
-         open(option.consolename,O_WRONLY);
+         open(console.device, O_WRONLY);
          dup(1);
          execl("/bin/sh", "sh", "-c", s, NULL);
          exit(1); /* shouldn't happen */