summaryrefslogtreecommitdiffstats
path: root/source/a/gpm/gpm-evdev-cumulative.patch
diff options
context:
space:
mode:
Diffstat (limited to 'source/a/gpm/gpm-evdev-cumulative.patch')
-rw-r--r--source/a/gpm/gpm-evdev-cumulative.patch7023
1 files changed, 7023 insertions, 0 deletions
diff --git a/source/a/gpm/gpm-evdev-cumulative.patch b/source/a/gpm/gpm-evdev-cumulative.patch
new file mode 100644
index 000000000..2fd86d10c
--- /dev/null
+++ b/source/a/gpm/gpm-evdev-cumulative.patch
@@ -0,0 +1,7023 @@
+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 */