Home | History | Annotate | Line # | Download | only in moused
moused.c revision 1.5
      1  1.5   thorpej /* $NetBSD: moused.c,v 1.5 2002/01/01 06:31:49 thorpej Exp $ */
      2  1.1  augustss /**
      3  1.1  augustss  ** Copyright (c) 1995 Michael Smith, All rights reserved.
      4  1.1  augustss  **
      5  1.1  augustss  ** Redistribution and use in source and binary forms, with or without
      6  1.1  augustss  ** modification, are permitted provided that the following conditions
      7  1.1  augustss  ** are met:
      8  1.1  augustss  ** 1. Redistributions of source code must retain the above copyright
      9  1.1  augustss  **    notice, this list of conditions and the following disclaimer as
     10  1.1  augustss  **    the first lines of this file unmodified.
     11  1.1  augustss  ** 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  augustss  **    notice, this list of conditions and the following disclaimer in the
     13  1.1  augustss  **    documentation and/or other materials provided with the distribution.
     14  1.1  augustss  ** 3. All advertising materials mentioning features or use of this software
     15  1.1  augustss  **    must display the following acknowledgment:
     16  1.1  augustss  **      This product includes software developed by Michael Smith.
     17  1.1  augustss  ** 4. The name of the author may not be used to endorse or promote products
     18  1.1  augustss  **    derived from this software without specific prior written permission.
     19  1.1  augustss  **
     20  1.1  augustss  **
     21  1.1  augustss  ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY
     22  1.1  augustss  ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  1.1  augustss  ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  1.1  augustss  ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR
     25  1.1  augustss  ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  1.1  augustss  ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  1.1  augustss  ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     28  1.1  augustss  ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  1.1  augustss  ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     30  1.1  augustss  ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     31  1.1  augustss  ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  1.1  augustss  **
     33  1.1  augustss  **/
     34  1.1  augustss 
     35  1.1  augustss /**
     36  1.1  augustss  ** MOUSED.C
     37  1.1  augustss  **
     38  1.1  augustss  ** Mouse daemon : listens to a serial port, the bus mouse interface, or
     39  1.1  augustss  ** the PS/2 mouse port for mouse data stream, interprets data and passes
     40  1.1  augustss  ** ioctls off to the console driver.
     41  1.1  augustss  **
     42  1.1  augustss  ** The mouse interface functions are derived closely from the mouse
     43  1.1  augustss  ** handler in the XFree86 X server.  Many thanks to the XFree86 people
     44  1.1  augustss  ** for their great work!
     45  1.1  augustss  **
     46  1.1  augustss  **/
     47  1.1  augustss 
     48  1.3  gmcgarry #include <sys/cdefs.h>
     49  1.3  gmcgarry 
     50  1.1  augustss #ifndef lint
     51  1.5   thorpej __RCSID("$NetBSD: moused.c,v 1.5 2002/01/01 06:31:49 thorpej Exp $");
     52  1.1  augustss #endif /* not lint */
     53  1.1  augustss 
     54  1.1  augustss #include <ctype.h>
     55  1.1  augustss #include <err.h>
     56  1.1  augustss #include <errno.h>
     57  1.1  augustss #include <fcntl.h>
     58  1.1  augustss #include <limits.h>
     59  1.1  augustss #include <stdio.h>
     60  1.1  augustss #include <stdlib.h>
     61  1.1  augustss #include <stdarg.h>
     62  1.1  augustss #include <string.h>
     63  1.1  augustss #include <ctype.h>
     64  1.1  augustss #include <signal.h>
     65  1.1  augustss #include <setjmp.h>
     66  1.1  augustss #include <termios.h>
     67  1.1  augustss #include <syslog.h>
     68  1.1  augustss #include "mouse.h"
     69  1.1  augustss #include <sys/ioctl.h>
     70  1.1  augustss #include <dev/wscons/wsconsio.h>
     71  1.1  augustss #include <sys/types.h>
     72  1.1  augustss #include <sys/time.h>
     73  1.1  augustss #include <sys/socket.h>
     74  1.1  augustss #include <sys/un.h>
     75  1.1  augustss #include <unistd.h>
     76  1.1  augustss 
     77  1.1  augustss #define MAX_CLICKTHRESHOLD	2000	/* 2 seconds */
     78  1.1  augustss #define MAX_BUTTON2TIMEOUT	2000	/* 2 seconds */
     79  1.1  augustss #define DFLT_CLICKTHRESHOLD	 500	/* 0.5 second */
     80  1.1  augustss #define DFLT_BUTTON2TIMEOUT	 100	/* 0.1 second */
     81  1.1  augustss 
     82  1.1  augustss /* Abort 3-button emulation delay after this many movement events. */
     83  1.1  augustss #define BUTTON2_MAXMOVE	3
     84  1.1  augustss 
     85  1.1  augustss #define TRUE		1
     86  1.1  augustss #define FALSE		0
     87  1.1  augustss 
     88  1.1  augustss #define MOUSE_XAXIS	(-1)
     89  1.1  augustss #define MOUSE_YAXIS	(-2)
     90  1.1  augustss 
     91  1.1  augustss /* Logitech PS2++ protocol */
     92  1.1  augustss #define MOUSE_PS2PLUS_CHECKBITS(b)	\
     93  1.1  augustss 			((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
     94  1.1  augustss #define MOUSE_PS2PLUS_PACKET_TYPE(b)	\
     95  1.1  augustss 			(((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
     96  1.1  augustss 
     97  1.1  augustss #define	ChordMiddle	0x0001
     98  1.1  augustss #define Emulate3Button	0x0002
     99  1.1  augustss #define ClearDTR	0x0004
    100  1.1  augustss #define ClearRTS	0x0008
    101  1.1  augustss #define NoPnP		0x0010
    102  1.1  augustss 
    103  1.1  augustss #define ID_NONE		0
    104  1.1  augustss #define ID_PORT		1
    105  1.1  augustss #define ID_IF		2
    106  1.1  augustss #define ID_TYPE 	4
    107  1.1  augustss #define ID_MODEL	8
    108  1.1  augustss #define ID_ALL		(ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
    109  1.1  augustss 
    110  1.1  augustss /* structures */
    111  1.1  augustss 
    112  1.1  augustss /* symbol table entry */
    113  1.1  augustss typedef struct {
    114  1.1  augustss     char *name;
    115  1.1  augustss     int val;
    116  1.1  augustss     int val2;
    117  1.1  augustss } symtab_t;
    118  1.1  augustss 
    119  1.1  augustss /* serial PnP ID string */
    120  1.1  augustss typedef struct {
    121  1.1  augustss     int revision;	/* PnP revision, 100 for 1.00 */
    122  1.1  augustss     char *eisaid;	/* EISA ID including mfr ID and product ID */
    123  1.1  augustss     char *serial;	/* serial No, optional */
    124  1.1  augustss     char *class;	/* device class, optional */
    125  1.1  augustss     char *compat;	/* list of compatible drivers, optional */
    126  1.1  augustss     char *description;	/* product description, optional */
    127  1.1  augustss     int neisaid;	/* length of the above fields... */
    128  1.1  augustss     int nserial;
    129  1.1  augustss     int nclass;
    130  1.1  augustss     int ncompat;
    131  1.1  augustss     int ndescription;
    132  1.1  augustss } pnpid_t;
    133  1.1  augustss 
    134  1.1  augustss /* global variables */
    135  1.1  augustss 
    136  1.5   thorpej int	dbg = 0;
    137  1.1  augustss int	nodaemon = FALSE;
    138  1.1  augustss int	background = FALSE;
    139  1.1  augustss int	identify = ID_NONE;
    140  1.1  augustss char	*pidfile = "/var/run/moused.pid";
    141  1.1  augustss 
    142  1.1  augustss /* local variables */
    143  1.1  augustss 
    144  1.1  augustss /* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
    145  1.1  augustss static symtab_t rifs[] = {
    146  1.1  augustss     { "serial",		MOUSE_IF_SERIAL },
    147  1.1  augustss     { "bus",		MOUSE_IF_BUS },
    148  1.1  augustss     { "inport",		MOUSE_IF_INPORT },
    149  1.1  augustss     { "ps/2",		MOUSE_IF_PS2 },
    150  1.1  augustss     { "sysmouse",	MOUSE_IF_SYSMOUSE },
    151  1.1  augustss     { "usb",		MOUSE_IF_USB },
    152  1.1  augustss     { NULL,		MOUSE_IF_UNKNOWN },
    153  1.1  augustss };
    154  1.1  augustss 
    155  1.1  augustss /* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */
    156  1.1  augustss static char *rnames[] = {
    157  1.1  augustss     "microsoft",
    158  1.1  augustss     "mousesystems",
    159  1.1  augustss     "logitech",
    160  1.1  augustss     "mmseries",
    161  1.1  augustss     "mouseman",
    162  1.1  augustss     "busmouse",
    163  1.1  augustss     "inportmouse",
    164  1.1  augustss     "ps/2",
    165  1.1  augustss     "mmhitab",
    166  1.1  augustss     "glidepoint",
    167  1.1  augustss     "intellimouse",
    168  1.1  augustss     "thinkingmouse",
    169  1.1  augustss     "sysmouse",
    170  1.1  augustss     "x10mouseremote",
    171  1.1  augustss     "kidspad",
    172  1.1  augustss #if notyet
    173  1.1  augustss     "mariqua",
    174  1.1  augustss #endif
    175  1.1  augustss     NULL
    176  1.1  augustss };
    177  1.1  augustss 
    178  1.1  augustss /* models */
    179  1.1  augustss static symtab_t	rmodels[] = {
    180  1.1  augustss     { "NetScroll",		MOUSE_MODEL_NETSCROLL },
    181  1.1  augustss     { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET },
    182  1.1  augustss     { "GlidePoint",		MOUSE_MODEL_GLIDEPOINT },
    183  1.1  augustss     { "ThinkingMouse",		MOUSE_MODEL_THINK },
    184  1.1  augustss     { "IntelliMouse",		MOUSE_MODEL_INTELLI },
    185  1.1  augustss     { "EasyScroll/SmartScroll",	MOUSE_MODEL_EASYSCROLL },
    186  1.1  augustss     { "MouseMan+",		MOUSE_MODEL_MOUSEMANPLUS },
    187  1.1  augustss     { "Kidspad",		MOUSE_MODEL_KIDSPAD },
    188  1.1  augustss     { "VersaPad",		MOUSE_MODEL_VERSAPAD },
    189  1.1  augustss     { "IntelliMouse Explorer",	MOUSE_MODEL_EXPLORER },
    190  1.1  augustss     { "4D Mouse",		MOUSE_MODEL_4D },
    191  1.1  augustss     { "4D+ Mouse",		MOUSE_MODEL_4DPLUS },
    192  1.1  augustss     { "generic",		MOUSE_MODEL_GENERIC },
    193  1.1  augustss     { NULL, 			MOUSE_MODEL_UNKNOWN },
    194  1.1  augustss };
    195  1.1  augustss 
    196  1.1  augustss /* PnP EISA/product IDs */
    197  1.1  augustss static symtab_t pnpprod[] = {
    198  1.1  augustss     /* Kensignton ThinkingMouse */
    199  1.1  augustss     { "KML0001",	MOUSE_PROTO_THINK,	MOUSE_MODEL_THINK },
    200  1.1  augustss     /* MS IntelliMouse */
    201  1.1  augustss     { "MSH0001",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
    202  1.1  augustss     /* MS IntelliMouse TrackBall */
    203  1.1  augustss     { "MSH0004",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
    204  1.1  augustss     /* Tremon Wheel Mouse MUSD */
    205  1.1  augustss     { "HTK0001",        MOUSE_PROTO_INTELLI,    MOUSE_MODEL_INTELLI },
    206  1.1  augustss     /* Genius PnP Mouse */
    207  1.1  augustss     { "KYE0001",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
    208  1.1  augustss     /* MouseSystems SmartScroll Mouse (OEM from Genius?) */
    209  1.1  augustss     { "KYE0002",	MOUSE_PROTO_MS,		MOUSE_MODEL_EASYSCROLL },
    210  1.1  augustss     /* Genius NetMouse */
    211  1.1  augustss     { "KYE0003",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_NET },
    212  1.1  augustss     /* Genius Kidspad, Easypad and other tablets */
    213  1.1  augustss     { "KYE0005",	MOUSE_PROTO_KIDSPAD,	MOUSE_MODEL_KIDSPAD },
    214  1.1  augustss     /* Genius EZScroll */
    215  1.1  augustss     { "KYEEZ00",	MOUSE_PROTO_MS,		MOUSE_MODEL_EASYSCROLL },
    216  1.1  augustss     /* Logitech Cordless MouseMan Wheel */
    217  1.1  augustss     { "LGI8033",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
    218  1.1  augustss     /* Logitech MouseMan (new 4 button model) */
    219  1.1  augustss     { "LGI800C",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
    220  1.1  augustss     /* Logitech MouseMan+ */
    221  1.1  augustss     { "LGI8050",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
    222  1.1  augustss     /* Logitech FirstMouse+ */
    223  1.1  augustss     { "LGI8051",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
    224  1.1  augustss     /* Logitech serial */
    225  1.1  augustss     { "LGI8001",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
    226  1.1  augustss     /* A4 Tech 4D/4D+ Mouse */
    227  1.1  augustss     { "A4W0005",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_4D },
    228  1.1  augustss     /* 8D Scroll Mouse */
    229  1.1  augustss     { "PEC9802",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
    230  1.1  augustss     /* Mitsumi Wireless Scroll Mouse */
    231  1.1  augustss     { "MTM6401",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
    232  1.1  augustss 
    233  1.1  augustss     /* MS bus */
    234  1.1  augustss     { "PNP0F00",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
    235  1.1  augustss     /* MS serial */
    236  1.1  augustss     { "PNP0F01",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
    237  1.1  augustss     /* MS InPort */
    238  1.1  augustss     { "PNP0F02",	MOUSE_PROTO_INPORT,	MOUSE_MODEL_GENERIC },
    239  1.1  augustss     /* MS PS/2 */
    240  1.1  augustss     { "PNP0F03",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
    241  1.1  augustss     /*
    242  1.1  augustss      * EzScroll returns PNP0F04 in the compatible device field; but it
    243  1.1  augustss      * doesn't look compatible... XXX
    244  1.1  augustss      */
    245  1.1  augustss     /* MouseSystems */
    246  1.1  augustss     { "PNP0F04",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
    247  1.1  augustss     /* MouseSystems */
    248  1.1  augustss     { "PNP0F05",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
    249  1.1  augustss #if notyet
    250  1.1  augustss     /* Genius Mouse */
    251  1.1  augustss     { "PNP0F06",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    252  1.1  augustss     /* Genius Mouse */
    253  1.1  augustss     { "PNP0F07",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    254  1.1  augustss #endif
    255  1.1  augustss     /* Logitech serial */
    256  1.1  augustss     { "PNP0F08",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
    257  1.1  augustss     /* MS BallPoint serial */
    258  1.1  augustss     { "PNP0F09",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
    259  1.1  augustss     /* MS PnP serial */
    260  1.1  augustss     { "PNP0F0A",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
    261  1.1  augustss     /* MS PnP BallPoint serial */
    262  1.1  augustss     { "PNP0F0B",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
    263  1.1  augustss     /* MS serial comatible */
    264  1.1  augustss     { "PNP0F0C",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
    265  1.1  augustss     /* MS InPort comatible */
    266  1.1  augustss     { "PNP0F0D",	MOUSE_PROTO_INPORT,	MOUSE_MODEL_GENERIC },
    267  1.1  augustss     /* MS PS/2 comatible */
    268  1.1  augustss     { "PNP0F0E",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
    269  1.1  augustss     /* MS BallPoint comatible */
    270  1.1  augustss     { "PNP0F0F",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
    271  1.1  augustss #if notyet
    272  1.1  augustss     /* TI QuickPort */
    273  1.1  augustss     { "PNP0F10",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    274  1.1  augustss #endif
    275  1.1  augustss     /* MS bus comatible */
    276  1.1  augustss     { "PNP0F11",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
    277  1.1  augustss     /* Logitech PS/2 */
    278  1.1  augustss     { "PNP0F12",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
    279  1.1  augustss     /* PS/2 */
    280  1.1  augustss     { "PNP0F13",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
    281  1.1  augustss #if notyet
    282  1.1  augustss     /* MS Kids Mouse */
    283  1.1  augustss     { "PNP0F14",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    284  1.1  augustss #endif
    285  1.1  augustss     /* Logitech bus */
    286  1.1  augustss     { "PNP0F15",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
    287  1.1  augustss #if notyet
    288  1.1  augustss     /* Logitech SWIFT */
    289  1.1  augustss     { "PNP0F16",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    290  1.1  augustss #endif
    291  1.1  augustss     /* Logitech serial compat */
    292  1.1  augustss     { "PNP0F17",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
    293  1.1  augustss     /* Logitech bus compatible */
    294  1.1  augustss     { "PNP0F18",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
    295  1.1  augustss     /* Logitech PS/2 compatible */
    296  1.1  augustss     { "PNP0F19",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
    297  1.1  augustss #if notyet
    298  1.1  augustss     /* Logitech SWIFT compatible */
    299  1.1  augustss     { "PNP0F1A",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    300  1.1  augustss     /* HP Omnibook */
    301  1.1  augustss     { "PNP0F1B",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    302  1.1  augustss     /* Compaq LTE TrackBall PS/2 */
    303  1.1  augustss     { "PNP0F1C",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    304  1.1  augustss     /* Compaq LTE TrackBall serial */
    305  1.1  augustss     { "PNP0F1D",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    306  1.1  augustss     /* MS Kidts Trackball */
    307  1.1  augustss     { "PNP0F1E",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
    308  1.1  augustss #endif
    309  1.1  augustss     /* Interlink VersaPad */
    310  1.1  augustss     { "LNK0001",	MOUSE_PROTO_VERSAPAD,	MOUSE_MODEL_VERSAPAD },
    311  1.1  augustss 
    312  1.1  augustss     { NULL,		MOUSE_PROTO_UNKNOWN,	MOUSE_MODEL_GENERIC },
    313  1.1  augustss };
    314  1.1  augustss 
    315  1.1  augustss /* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */
    316  1.1  augustss static unsigned short rodentcflags[] =
    317  1.1  augustss {
    318  1.1  augustss     (CS7	           | CREAD | CLOCAL | HUPCL ),	/* MicroSoft */
    319  1.1  augustss     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* MouseSystems */
    320  1.1  augustss     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* Logitech */
    321  1.1  augustss     (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ),	/* MMSeries */
    322  1.1  augustss     (CS7		   | CREAD | CLOCAL | HUPCL ),	/* MouseMan */
    323  1.1  augustss     0,							/* Bus */
    324  1.1  augustss     0,							/* InPort */
    325  1.1  augustss     0,							/* PS/2 */
    326  1.1  augustss     (CS8		   | CREAD | CLOCAL | HUPCL ),	/* MM HitTablet */
    327  1.1  augustss     (CS7	           | CREAD | CLOCAL | HUPCL ),	/* GlidePoint */
    328  1.1  augustss     (CS7                   | CREAD | CLOCAL | HUPCL ),	/* IntelliMouse */
    329  1.1  augustss     (CS7                   | CREAD | CLOCAL | HUPCL ),	/* Thinking Mouse */
    330  1.1  augustss     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* sysmouse */
    331  1.1  augustss     (CS7	           | CREAD | CLOCAL | HUPCL ),	/* X10 MouseRemote */
    332  1.1  augustss     (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ),	/* kidspad etc. */
    333  1.1  augustss     (CS8		   | CREAD | CLOCAL | HUPCL ),	/* VersaPad */
    334  1.1  augustss #if notyet
    335  1.1  augustss     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* Mariqua */
    336  1.1  augustss #endif
    337  1.1  augustss };
    338  1.1  augustss 
    339  1.1  augustss static struct rodentparam {
    340  1.1  augustss     int flags;
    341  1.1  augustss     char *portname;		/* /dev/XXX */
    342  1.1  augustss     int rtype;			/* MOUSE_PROTO_XXX */
    343  1.1  augustss     int level;			/* operation level: 0 or greater */
    344  1.1  augustss     int baudrate;
    345  1.1  augustss     int rate;			/* report rate */
    346  1.1  augustss     int resolution;		/* MOUSE_RES_XXX or a positive number */
    347  1.1  augustss     int zmap[4];		/* MOUSE_{X|Y}AXIS or a button number */
    348  1.1  augustss     int wmode;			/* wheel mode button number */
    349  1.1  augustss     int mfd;			/* mouse file descriptor */
    350  1.1  augustss     int cfd;			/* /dev/wsmousectl file descriptor */
    351  1.1  augustss     int mremsfd;		/* mouse remote server file descriptor */
    352  1.1  augustss     int mremcfd;		/* mouse remote client file descriptor */
    353  1.1  augustss     long clickthreshold;	/* double click speed in msec */
    354  1.1  augustss     long button2timeout;	/* 3 button emulation timeout */
    355  1.1  augustss     mousehw_t hw;		/* mouse device hardware information */
    356  1.1  augustss     mousemode_t mode;		/* protocol information */
    357  1.1  augustss     float accelx;		/* Acceleration in the X axis */
    358  1.1  augustss     float accely;		/* Acceleration in the Y axis */
    359  1.1  augustss } rodent = {
    360  1.1  augustss     flags : 0,
    361  1.1  augustss     portname : NULL,
    362  1.1  augustss     rtype : MOUSE_PROTO_UNKNOWN,
    363  1.1  augustss     level : -1,
    364  1.1  augustss     baudrate : 1200,
    365  1.1  augustss     rate : 0,
    366  1.1  augustss     resolution : MOUSE_RES_UNKNOWN,
    367  1.1  augustss     zmap: { 0, 0, 0, 0 },
    368  1.1  augustss     wmode: 0,
    369  1.1  augustss     mfd : -1,
    370  1.1  augustss     cfd : -1,
    371  1.1  augustss     mremsfd : -1,
    372  1.1  augustss     mremcfd : -1,
    373  1.1  augustss     clickthreshold : DFLT_CLICKTHRESHOLD,
    374  1.1  augustss     button2timeout : DFLT_BUTTON2TIMEOUT,
    375  1.1  augustss     accelx : 1.0,
    376  1.1  augustss     accely : 1.0,
    377  1.1  augustss };
    378  1.1  augustss 
    379  1.1  augustss /* button status */
    380  1.1  augustss struct button_state {
    381  1.1  augustss     int count;		/* 0: up, 1: single click, 2: double click,... */
    382  1.1  augustss     struct timeval tv;	/* timestamp on the last button event */
    383  1.1  augustss };
    384  1.1  augustss static struct button_state	bstate[MOUSE_MAXBUTTON]; /* button state */
    385  1.1  augustss static struct button_state	*mstate[MOUSE_MAXBUTTON];/* mapped button st.*/
    386  1.1  augustss static struct button_state	zstate[4];		 /* Z/W axis state */
    387  1.1  augustss 
    388  1.1  augustss /* state machine for 3 button emulation */
    389  1.1  augustss 
    390  1.1  augustss #define S0	0	/* start */
    391  1.1  augustss #define S1	1	/* button 1 delayed down */
    392  1.1  augustss #define S2	2	/* button 3 delayed down */
    393  1.1  augustss #define S3	3	/* both buttons down -> button 2 down */
    394  1.1  augustss #define S4	4	/* button 1 delayed up */
    395  1.1  augustss #define S5	5	/* button 1 down */
    396  1.1  augustss #define S6	6	/* button 3 down */
    397  1.1  augustss #define S7	7	/* both buttons down */
    398  1.1  augustss #define S8	8	/* button 3 delayed up */
    399  1.1  augustss #define S9	9	/* button 1 or 3 up after S3 */
    400  1.1  augustss 
    401  1.1  augustss #define A(b1, b3)	(((b1) ? 2 : 0) | ((b3) ? 1 : 0))
    402  1.1  augustss #define A_TIMEOUT	4
    403  1.1  augustss #define S_DELAYED(st)	(states[st].s[A_TIMEOUT] != (st))
    404  1.1  augustss 
    405  1.1  augustss static struct {
    406  1.1  augustss     int s[A_TIMEOUT + 1];
    407  1.1  augustss     int buttons;
    408  1.1  augustss     int mask;
    409  1.1  augustss     int timeout;
    410  1.1  augustss } states[10] = {
    411  1.1  augustss     /* S0 */
    412  1.1  augustss     { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
    413  1.1  augustss     /* S1 */
    414  1.1  augustss     { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, FALSE },
    415  1.1  augustss     /* S2 */
    416  1.1  augustss     { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, FALSE },
    417  1.1  augustss     /* S3 */
    418  1.1  augustss     { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, FALSE },
    419  1.1  augustss     /* S4 */
    420  1.1  augustss     { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, TRUE },
    421  1.1  augustss     /* S5 */
    422  1.1  augustss     { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, FALSE },
    423  1.1  augustss     /* S6 */
    424  1.1  augustss     { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, FALSE },
    425  1.1  augustss     /* S7 */
    426  1.1  augustss     { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, FALSE },
    427  1.1  augustss     /* S8 */
    428  1.1  augustss     { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, TRUE },
    429  1.1  augustss     /* S9 */
    430  1.1  augustss     { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
    431  1.1  augustss };
    432  1.1  augustss static int		mouse_button_state;
    433  1.1  augustss static struct timeval	mouse_button_state_tv;
    434  1.1  augustss static int		mouse_move_delayed;
    435  1.1  augustss 
    436  1.1  augustss static jmp_buf env;
    437  1.1  augustss 
    438  1.1  augustss /* function prototypes */
    439  1.1  augustss 
    440  1.1  augustss static void	moused(char *);
    441  1.1  augustss static void	hup(int sig);
    442  1.1  augustss static void	cleanup(int sig);
    443  1.1  augustss static void	usage(void);
    444  1.1  augustss 
    445  1.1  augustss static int	r_identify(void);
    446  1.1  augustss static char	*r_if(int type);
    447  1.1  augustss static char	*r_name(int type);
    448  1.1  augustss static char	*r_model(int model);
    449  1.1  augustss static void	r_init(void);
    450  1.1  augustss static int	r_protocol(u_char b, mousestatus_t *act);
    451  1.1  augustss static int	r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans);
    452  1.1  augustss static int	r_installmap(char *arg);
    453  1.1  augustss static void	r_map(mousestatus_t *act1, mousestatus_t *act2);
    454  1.1  augustss static void	r_timestamp(mousestatus_t *act);
    455  1.1  augustss static int	r_timeout(void);
    456  1.1  augustss static void	setmousespeed(int old, int new, unsigned cflag);
    457  1.1  augustss 
    458  1.1  augustss static int	pnpwakeup1(void);
    459  1.1  augustss static int	pnpwakeup2(void);
    460  1.1  augustss static int	pnpgets(char *buf);
    461  1.1  augustss static int	pnpparse(pnpid_t *id, char *buf, int len);
    462  1.1  augustss static symtab_t	*pnpproto(pnpid_t *id);
    463  1.1  augustss 
    464  1.1  augustss static symtab_t	*gettoken(symtab_t *tab, char *s, int len);
    465  1.1  augustss static char	*gettokenname(symtab_t *tab, int val);
    466  1.1  augustss 
    467  1.1  augustss static void wsev(int ty, int val);
    468  1.1  augustss 
    469  1.1  augustss static int kidspad(u_char rxc, mousestatus_t *act);
    470  1.1  augustss 
    471  1.5   thorpej static void
    472  1.5   thorpej debug(const char *fmt, ...)
    473  1.5   thorpej {
    474  1.5   thorpej 	va_list ap;
    475  1.5   thorpej 
    476  1.5   thorpej 	va_start(ap, fmt);
    477  1.5   thorpej 	if (dbg && nodaemon)
    478  1.5   thorpej 		vwarnx(fmt, ap);
    479  1.5   thorpej 	va_end(ap);
    480  1.5   thorpej }
    481  1.5   thorpej 
    482  1.5   thorpej static void
    483  1.5   thorpej logerr(int e, const char *fmt, ...)
    484  1.5   thorpej {
    485  1.5   thorpej 	va_list ap;
    486  1.5   thorpej 
    487  1.5   thorpej 	va_start(ap, fmt);
    488  1.5   thorpej 	if (background) {
    489  1.5   thorpej 		int saveerrno = errno;
    490  1.5   thorpej 		vsyslog(LOG_DAEMON | LOG_ERR, fmt, ap);
    491  1.5   thorpej 		errno = saveerrno;
    492  1.5   thorpej 		syslog(LOG_DAEMON | LOG_ERR, "%m");
    493  1.5   thorpej 		exit(e);
    494  1.5   thorpej 	} else
    495  1.5   thorpej 		verr(e, fmt, ap);
    496  1.5   thorpej 	va_end(ap);
    497  1.5   thorpej }
    498  1.5   thorpej 
    499  1.5   thorpej static void
    500  1.5   thorpej logwarn(const char *fmt, ...)
    501  1.5   thorpej {
    502  1.5   thorpej 	va_list ap;
    503  1.5   thorpej 
    504  1.5   thorpej 	va_start(ap, fmt);
    505  1.5   thorpej 	if (background) {
    506  1.5   thorpej 		int saveerrno = errno;
    507  1.5   thorpej 		vsyslog(LOG_DAEMON | LOG_WARNING, fmt, ap);
    508  1.5   thorpej 		errno = saveerrno;
    509  1.5   thorpej 		syslog(LOG_DAEMON | LOG_WARNING, "%m");
    510  1.5   thorpej 	} else
    511  1.5   thorpej 		vwarn(fmt, ap);
    512  1.5   thorpej 	va_end(ap);
    513  1.5   thorpej }
    514  1.5   thorpej 
    515  1.5   thorpej static void
    516  1.5   thorpej logwarnx(const char *fmt, ...)
    517  1.5   thorpej {
    518  1.5   thorpej 	va_list ap;
    519  1.5   thorpej 
    520  1.5   thorpej 	va_start(ap, fmt);
    521  1.5   thorpej 	if (background)
    522  1.5   thorpej 		vsyslog(LOG_DAEMON | LOG_WARNING, fmt, ap);
    523  1.5   thorpej 	else
    524  1.5   thorpej 		vwarnx(fmt, ap);
    525  1.5   thorpej 	va_end(ap);
    526  1.5   thorpej }
    527  1.5   thorpej 
    528  1.1  augustss int
    529  1.1  augustss main(int argc, char *argv[])
    530  1.1  augustss {
    531  1.1  augustss     int c;
    532  1.1  augustss     int	i;
    533  1.1  augustss     int	j;
    534  1.1  augustss     char *ctldev = "/dev/wsmuxctl0";
    535  1.1  augustss 
    536  1.1  augustss     for (i = 0; i < MOUSE_MAXBUTTON; ++i)
    537  1.1  augustss 	mstate[i] = &bstate[i];
    538  1.1  augustss 
    539  1.1  augustss     while((c = getopt(argc,argv,"3DE:F:I:PRS:W:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
    540  1.1  augustss 	switch(c) {
    541  1.1  augustss 
    542  1.1  augustss 	case 'W':
    543  1.1  augustss 	    ctldev = optarg;
    544  1.1  augustss 	    break;
    545  1.1  augustss 
    546  1.1  augustss 	case '3':
    547  1.1  augustss 	    rodent.flags |= Emulate3Button;
    548  1.1  augustss 	    break;
    549  1.1  augustss 
    550  1.1  augustss 	case 'E':
    551  1.1  augustss 	    rodent.button2timeout = atoi(optarg);
    552  1.1  augustss 	    if ((rodent.button2timeout < 0) ||
    553  1.1  augustss 	        (rodent.button2timeout > MAX_BUTTON2TIMEOUT)) {
    554  1.1  augustss 	        warnx("invalid argument `%s'", optarg);
    555  1.1  augustss 	        usage();
    556  1.1  augustss 	    }
    557  1.1  augustss 	    break;
    558  1.1  augustss 
    559  1.1  augustss 	case 'a':
    560  1.1  augustss 	    i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely);
    561  1.1  augustss 	    if (i == 0) {
    562  1.1  augustss 		warnx("invalid acceleration argument '%s'", optarg);
    563  1.1  augustss 		usage();
    564  1.1  augustss 	    }
    565  1.1  augustss 
    566  1.1  augustss 	    if (i == 1)
    567  1.1  augustss 		rodent.accely = rodent.accelx;
    568  1.1  augustss 
    569  1.1  augustss 	    break;
    570  1.1  augustss 
    571  1.1  augustss 	case 'c':
    572  1.1  augustss 	    rodent.flags |= ChordMiddle;
    573  1.1  augustss 	    break;
    574  1.1  augustss 
    575  1.1  augustss 	case 'd':
    576  1.5   thorpej 	    ++dbg;
    577  1.1  augustss 	    break;
    578  1.1  augustss 
    579  1.1  augustss 	case 'f':
    580  1.1  augustss 	    nodaemon = TRUE;
    581  1.1  augustss 	    break;
    582  1.1  augustss 
    583  1.1  augustss 	case 'i':
    584  1.1  augustss 	    if (strcmp(optarg, "all") == 0)
    585  1.1  augustss 	        identify = ID_ALL;
    586  1.1  augustss 	    else if (strcmp(optarg, "port") == 0)
    587  1.1  augustss 	        identify = ID_PORT;
    588  1.1  augustss 	    else if (strcmp(optarg, "if") == 0)
    589  1.1  augustss 	        identify = ID_IF;
    590  1.1  augustss 	    else if (strcmp(optarg, "type") == 0)
    591  1.1  augustss 	        identify = ID_TYPE;
    592  1.1  augustss 	    else if (strcmp(optarg, "model") == 0)
    593  1.1  augustss 	        identify = ID_MODEL;
    594  1.1  augustss 	    else {
    595  1.1  augustss 	        warnx("invalid argument `%s'", optarg);
    596  1.1  augustss 	        usage();
    597  1.1  augustss 	    }
    598  1.1  augustss 	    nodaemon = TRUE;
    599  1.1  augustss 	    break;
    600  1.1  augustss 
    601  1.1  augustss 	case 'l':
    602  1.1  augustss 	    rodent.level = atoi(optarg);
    603  1.1  augustss 	    if ((rodent.level < 0) || (rodent.level > 4)) {
    604  1.1  augustss 	        warnx("invalid argument `%s'", optarg);
    605  1.1  augustss 	        usage();
    606  1.1  augustss 	    }
    607  1.1  augustss 	    break;
    608  1.1  augustss 
    609  1.1  augustss 	case 'm':
    610  1.1  augustss 	    if (!r_installmap(optarg)) {
    611  1.1  augustss 	        warnx("invalid argument `%s'", optarg);
    612  1.1  augustss 	        usage();
    613  1.1  augustss 	    }
    614  1.1  augustss 	    break;
    615  1.1  augustss 
    616  1.1  augustss 	case 'p':
    617  1.1  augustss 	    rodent.portname = optarg;
    618  1.1  augustss 	    break;
    619  1.1  augustss 
    620  1.1  augustss 	case 'r':
    621  1.1  augustss 	    if (strcmp(optarg, "high") == 0)
    622  1.1  augustss 	        rodent.resolution = MOUSE_RES_HIGH;
    623  1.1  augustss 	    else if (strcmp(optarg, "medium-high") == 0)
    624  1.1  augustss 	        rodent.resolution = MOUSE_RES_HIGH;
    625  1.1  augustss 	    else if (strcmp(optarg, "medium-low") == 0)
    626  1.1  augustss 	        rodent.resolution = MOUSE_RES_MEDIUMLOW;
    627  1.1  augustss 	    else if (strcmp(optarg, "low") == 0)
    628  1.1  augustss 	        rodent.resolution = MOUSE_RES_LOW;
    629  1.1  augustss 	    else if (strcmp(optarg, "default") == 0)
    630  1.1  augustss 	        rodent.resolution = MOUSE_RES_DEFAULT;
    631  1.1  augustss 	    else {
    632  1.1  augustss 	        rodent.resolution = atoi(optarg);
    633  1.1  augustss 	        if (rodent.resolution <= 0) {
    634  1.1  augustss 	            warnx("invalid argument `%s'", optarg);
    635  1.1  augustss 	            usage();
    636  1.1  augustss 	        }
    637  1.1  augustss 	    }
    638  1.1  augustss 	    break;
    639  1.1  augustss 
    640  1.1  augustss 	case 's':
    641  1.1  augustss 	    rodent.baudrate = 9600;
    642  1.1  augustss 	    break;
    643  1.1  augustss 
    644  1.1  augustss 	case 'w':
    645  1.1  augustss 	    i = atoi(optarg);
    646  1.1  augustss 	    if ((i <= 0) || (i > MOUSE_MAXBUTTON)) {
    647  1.1  augustss 		warnx("invalid argument `%s'", optarg);
    648  1.1  augustss 		usage();
    649  1.1  augustss 	    }
    650  1.1  augustss 	    rodent.wmode = 1 << (i - 1);
    651  1.1  augustss 	    break;
    652  1.1  augustss 
    653  1.1  augustss 	case 'z':
    654  1.1  augustss 	    if (strcmp(optarg, "x") == 0)
    655  1.1  augustss 		rodent.zmap[0] = MOUSE_XAXIS;
    656  1.1  augustss 	    else if (strcmp(optarg, "y") == 0)
    657  1.1  augustss 		rodent.zmap[0] = MOUSE_YAXIS;
    658  1.1  augustss             else {
    659  1.1  augustss 		i = atoi(optarg);
    660  1.1  augustss 		/*
    661  1.1  augustss 		 * Use button i for negative Z axis movement and
    662  1.1  augustss 		 * button (i + 1) for positive Z axis movement.
    663  1.1  augustss 		 */
    664  1.1  augustss 		if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
    665  1.1  augustss 	            warnx("invalid argument `%s'", optarg);
    666  1.1  augustss 	            usage();
    667  1.1  augustss 		}
    668  1.1  augustss 		rodent.zmap[0] = i;
    669  1.1  augustss 		rodent.zmap[1] = i + 1;
    670  1.1  augustss 		debug("optind: %d, optarg: '%s'", optind, optarg);
    671  1.1  augustss 		for (j = 1; j < 4; ++j) {
    672  1.1  augustss 		    if ((optind >= argc) || !isdigit(*argv[optind]))
    673  1.1  augustss 			break;
    674  1.1  augustss 		    i = atoi(argv[optind]);
    675  1.1  augustss 		    if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
    676  1.1  augustss 			warnx("invalid argument `%s'", argv[optind]);
    677  1.1  augustss 			usage();
    678  1.1  augustss 		    }
    679  1.1  augustss 		    rodent.zmap[j] = i;
    680  1.1  augustss 		    ++optind;
    681  1.1  augustss 		}
    682  1.1  augustss 		if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0))
    683  1.1  augustss 		    rodent.zmap[3] = rodent.zmap[2] + 1;
    684  1.1  augustss 	    }
    685  1.1  augustss 	    break;
    686  1.1  augustss 
    687  1.1  augustss 	case 'C':
    688  1.1  augustss 	    rodent.clickthreshold = atoi(optarg);
    689  1.1  augustss 	    if ((rodent.clickthreshold < 0) ||
    690  1.1  augustss 	        (rodent.clickthreshold > MAX_CLICKTHRESHOLD)) {
    691  1.1  augustss 	        warnx("invalid argument `%s'", optarg);
    692  1.1  augustss 	        usage();
    693  1.1  augustss 	    }
    694  1.1  augustss 	    break;
    695  1.1  augustss 
    696  1.1  augustss 	case 'D':
    697  1.1  augustss 	    rodent.flags |= ClearDTR;
    698  1.1  augustss 	    break;
    699  1.1  augustss 
    700  1.1  augustss 	case 'F':
    701  1.1  augustss 	    rodent.rate = atoi(optarg);
    702  1.1  augustss 	    if (rodent.rate <= 0) {
    703  1.1  augustss 	        warnx("invalid argument `%s'", optarg);
    704  1.1  augustss 	        usage();
    705  1.1  augustss 	    }
    706  1.1  augustss 	    break;
    707  1.1  augustss 
    708  1.1  augustss 	case 'I':
    709  1.1  augustss 	    pidfile = optarg;
    710  1.1  augustss 	    break;
    711  1.1  augustss 
    712  1.1  augustss 	case 'P':
    713  1.1  augustss 	    rodent.flags |= NoPnP;
    714  1.1  augustss 	    break;
    715  1.1  augustss 
    716  1.1  augustss 	case 'R':
    717  1.1  augustss 	    rodent.flags |= ClearRTS;
    718  1.1  augustss 	    break;
    719  1.1  augustss 
    720  1.1  augustss 	case 'S':
    721  1.1  augustss 	    rodent.baudrate = atoi(optarg);
    722  1.1  augustss 	    if (rodent.baudrate <= 0) {
    723  1.1  augustss 	        warnx("invalid argument `%s'", optarg);
    724  1.1  augustss 	        usage();
    725  1.1  augustss 	    }
    726  1.1  augustss 	    debug("rodent baudrate %d", rodent.baudrate);
    727  1.1  augustss 	    break;
    728  1.1  augustss 
    729  1.1  augustss 	case 't':
    730  1.1  augustss 	    if (strcmp(optarg, "auto") == 0) {
    731  1.1  augustss 		rodent.rtype = MOUSE_PROTO_UNKNOWN;
    732  1.1  augustss 		rodent.flags &= ~NoPnP;
    733  1.1  augustss 		rodent.level = -1;
    734  1.1  augustss 		break;
    735  1.1  augustss 	    }
    736  1.1  augustss 	    for (i = 0; rnames[i]; i++)
    737  1.1  augustss 		if (strcmp(optarg, rnames[i]) == 0) {
    738  1.1  augustss 		    rodent.rtype = i;
    739  1.1  augustss 		    rodent.flags |= NoPnP;
    740  1.1  augustss 		    rodent.level = (i == MOUSE_PROTO_SYSMOUSE) ? 1 : 0;
    741  1.1  augustss 		    break;
    742  1.1  augustss 		}
    743  1.1  augustss 	    if (rnames[i])
    744  1.1  augustss 		break;
    745  1.1  augustss 	    warnx("no such mouse type `%s'", optarg);
    746  1.1  augustss 	    usage();
    747  1.1  augustss 
    748  1.1  augustss 	case 'h':
    749  1.1  augustss 	case '?':
    750  1.1  augustss 	default:
    751  1.1  augustss 	    usage();
    752  1.1  augustss 	}
    753  1.1  augustss 
    754  1.1  augustss     /* fix Z axis mapping */
    755  1.1  augustss     for (i = 0; i < 4; ++i) {
    756  1.1  augustss 	if (rodent.zmap[i] > 0) {
    757  1.1  augustss 	    for (j = 0; j < MOUSE_MAXBUTTON; ++j) {
    758  1.1  augustss 		if (mstate[j] == &bstate[rodent.zmap[i] - 1])
    759  1.1  augustss 		    mstate[j] = &zstate[i];
    760  1.1  augustss 	    }
    761  1.1  augustss 	    rodent.zmap[i] = 1 << (rodent.zmap[i] - 1);
    762  1.1  augustss 	}
    763  1.1  augustss     }
    764  1.1  augustss 
    765  1.1  augustss     /* the default port name */
    766  1.1  augustss     switch(rodent.rtype) {
    767  1.1  augustss 
    768  1.1  augustss     case MOUSE_PROTO_INPORT:
    769  1.1  augustss         /* INPORT and BUS are the same... */
    770  1.1  augustss 	rodent.rtype = MOUSE_PROTO_BUS;
    771  1.1  augustss 	/* FALL THROUGH */
    772  1.1  augustss     case MOUSE_PROTO_BUS:
    773  1.1  augustss 	if (!rodent.portname)
    774  1.1  augustss 	    rodent.portname = "/dev/mse0";
    775  1.1  augustss 	break;
    776  1.1  augustss 
    777  1.1  augustss     case MOUSE_PROTO_PS2:
    778  1.1  augustss 	if (!rodent.portname)
    779  1.1  augustss 	    rodent.portname = "/dev/psm0";
    780  1.1  augustss 	break;
    781  1.1  augustss 
    782  1.1  augustss     default:
    783  1.1  augustss 	if (rodent.portname)
    784  1.1  augustss 	    break;
    785  1.1  augustss 	warnx("no port name specified");
    786  1.1  augustss 	usage();
    787  1.1  augustss     }
    788  1.1  augustss 
    789  1.1  augustss     for (;;) {
    790  1.1  augustss 	if (setjmp(env) == 0) {
    791  1.1  augustss 	    signal(SIGHUP, hup);
    792  1.1  augustss 	    signal(SIGINT , cleanup);
    793  1.1  augustss 	    signal(SIGQUIT, cleanup);
    794  1.1  augustss 	    signal(SIGTERM, cleanup);
    795  1.1  augustss             if ((rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK, 0))
    796  1.1  augustss 		== -1)
    797  1.1  augustss 	        logerr(1, "unable to open %s", rodent.portname);
    798  1.1  augustss             if (r_identify() == MOUSE_PROTO_UNKNOWN) {
    799  1.1  augustss 	        logwarnx("cannot determine mouse type on %s", rodent.portname);
    800  1.1  augustss 	        close(rodent.mfd);
    801  1.1  augustss 	        rodent.mfd = -1;
    802  1.1  augustss             }
    803  1.1  augustss 
    804  1.1  augustss 	    /* print some information */
    805  1.1  augustss             if (identify != ID_NONE) {
    806  1.1  augustss 		if (identify == ID_ALL)
    807  1.1  augustss                     printf("%s %s %s %s\n",
    808  1.1  augustss 		        rodent.portname, r_if(rodent.hw.iftype),
    809  1.1  augustss 		        r_name(rodent.rtype), r_model(rodent.hw.model));
    810  1.1  augustss 		else if (identify & ID_PORT)
    811  1.1  augustss 		    printf("%s\n", rodent.portname);
    812  1.1  augustss 		else if (identify & ID_IF)
    813  1.1  augustss 		    printf("%s\n", r_if(rodent.hw.iftype));
    814  1.1  augustss 		else if (identify & ID_TYPE)
    815  1.1  augustss 		    printf("%s\n", r_name(rodent.rtype));
    816  1.1  augustss 		else if (identify & ID_MODEL)
    817  1.1  augustss 		    printf("%s\n", r_model(rodent.hw.model));
    818  1.1  augustss 		exit(0);
    819  1.1  augustss 	    } else {
    820  1.1  augustss                 debug("port: %s  interface: %s  type: %s  model: %s",
    821  1.1  augustss 		    rodent.portname, r_if(rodent.hw.iftype),
    822  1.1  augustss 		    r_name(rodent.rtype), r_model(rodent.hw.model));
    823  1.1  augustss 	    }
    824  1.1  augustss 
    825  1.1  augustss 	    if (rodent.mfd == -1) {
    826  1.1  augustss 	        /*
    827  1.1  augustss 	         * We cannot continue because of error.  Exit if the
    828  1.1  augustss 		 * program has not become a daemon.  Otherwise, block
    829  1.1  augustss 		 * until the the user corrects the problem and issues SIGHUP.
    830  1.1  augustss 	         */
    831  1.1  augustss 	        if (!background)
    832  1.1  augustss 		    exit(1);
    833  1.1  augustss 	        sigpause(0);
    834  1.1  augustss 	    }
    835  1.1  augustss 
    836  1.1  augustss             r_init();			/* call init function */
    837  1.1  augustss 	    moused(ctldev);
    838  1.1  augustss 	}
    839  1.1  augustss 
    840  1.1  augustss 	if (rodent.mfd != -1)
    841  1.1  augustss 	    close(rodent.mfd);
    842  1.1  augustss 	if (rodent.cfd != -1)
    843  1.1  augustss 	    close(rodent.cfd);
    844  1.1  augustss 	rodent.mfd = rodent.cfd = -1;
    845  1.1  augustss     }
    846  1.1  augustss     /* NOT REACHED */
    847  1.1  augustss 
    848  1.1  augustss     exit(0);
    849  1.1  augustss }
    850  1.1  augustss 
    851  1.1  augustss static void
    852  1.1  augustss wsev(int ty, int val)
    853  1.1  augustss {
    854  1.1  augustss     struct wscons_event ev;
    855  1.1  augustss 
    856  1.1  augustss     ev.type = ty;
    857  1.1  augustss     ev.value = val;
    858  1.5   thorpej     if (dbg)
    859  1.1  augustss 	printf("wsev: type=%d value=%d\n", ty, val);
    860  1.1  augustss     if (ioctl(rodent.cfd, WSMUXIO_INJECTEVENT, &ev) < 0)
    861  1.5   thorpej 	logwarn("muxio inject event");
    862  1.1  augustss }
    863  1.1  augustss 
    864  1.1  augustss static void
    865  1.1  augustss moused(char *wsm)
    866  1.1  augustss {
    867  1.1  augustss     mousestatus_t action0;		/* original mouse action */
    868  1.1  augustss     mousestatus_t action;		/* interrim buffer */
    869  1.1  augustss     mousestatus_t action2;		/* mapped action */
    870  1.1  augustss     int lastbutton = 0;
    871  1.1  augustss     int button;
    872  1.1  augustss     struct timeval timeout;
    873  1.1  augustss     fd_set fds;
    874  1.1  augustss     u_char b;
    875  1.1  augustss     FILE *fp;
    876  1.1  augustss     int flags;
    877  1.1  augustss     int c;
    878  1.1  augustss     int i;
    879  1.1  augustss 
    880  1.1  augustss     if ((rodent.cfd = open(wsm, O_WRONLY, 0)) == -1)
    881  1.1  augustss 	logerr(1, "cannot open %s", wsm);
    882  1.1  augustss 
    883  1.1  augustss     if (!nodaemon && !background) {
    884  1.1  augustss 	if (daemon(0, 0)) {
    885  1.4   thorpej 	    logerr(1, "failed to become a daemon");
    886  1.1  augustss 	} else {
    887  1.1  augustss 	    background = TRUE;
    888  1.1  augustss 	    fp = fopen(pidfile, "w");
    889  1.1  augustss 	    if (fp != NULL) {
    890  1.1  augustss 		fprintf(fp, "%d\n", getpid());
    891  1.1  augustss 		fclose(fp);
    892  1.1  augustss 	    }
    893  1.1  augustss 	}
    894  1.1  augustss     }
    895  1.1  augustss 
    896  1.1  augustss     /* clear mouse data */
    897  1.1  augustss     bzero(&action0, sizeof(action0));
    898  1.1  augustss     bzero(&action, sizeof(action));
    899  1.1  augustss     bzero(&action2, sizeof(action2));
    900  1.1  augustss     mouse_button_state = S0;
    901  1.1  augustss     gettimeofday(&mouse_button_state_tv, NULL);
    902  1.1  augustss     mouse_move_delayed = 0;
    903  1.1  augustss     for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
    904  1.1  augustss 	bstate[i].count = 0;
    905  1.1  augustss 	bstate[i].tv = mouse_button_state_tv;
    906  1.1  augustss     }
    907  1.1  augustss     for (i = 0; i < sizeof(zstate)/sizeof(zstate[0]); ++i) {
    908  1.1  augustss 	zstate[i].count = 0;
    909  1.1  augustss 	zstate[i].tv = mouse_button_state_tv;
    910  1.1  augustss     }
    911  1.1  augustss 
    912  1.1  augustss     /* process mouse data */
    913  1.1  augustss     timeout.tv_sec = 0;
    914  1.1  augustss     timeout.tv_usec = 20000;		/* 20 msec */
    915  1.1  augustss     for (;;) {
    916  1.1  augustss 
    917  1.1  augustss 	FD_ZERO(&fds);
    918  1.1  augustss 	FD_SET(rodent.mfd, &fds);
    919  1.1  augustss 	if (rodent.mremsfd >= 0)
    920  1.1  augustss 	    FD_SET(rodent.mremsfd, &fds);
    921  1.1  augustss 	if (rodent.mremcfd >= 0)
    922  1.1  augustss 	    FD_SET(rodent.mremcfd, &fds);
    923  1.1  augustss 
    924  1.1  augustss 	c = select(FD_SETSIZE, &fds, NULL, NULL,
    925  1.1  augustss 		   (rodent.flags & Emulate3Button) ? &timeout : NULL);
    926  1.1  augustss 	if (c < 0) {                    /* error */
    927  1.4   thorpej 	    logwarn("failed to read from mouse");
    928  1.1  augustss 	    continue;
    929  1.1  augustss 	} else if (c == 0) {            /* timeout */
    930  1.1  augustss 	    /* assert(rodent.flags & Emulate3Button) */
    931  1.1  augustss 	    action0.button = action0.obutton;
    932  1.1  augustss 	    action0.dx = action0.dy = action0.dz = 0;
    933  1.1  augustss 	    action0.flags = flags = 0;
    934  1.1  augustss 	    if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) {
    935  1.5   thorpej 		if (dbg > 2)
    936  1.1  augustss 		    debug("flags:%08x buttons:%08x obuttons:%08x",
    937  1.1  augustss 			  action.flags, action.button, action.obutton);
    938  1.1  augustss 	    } else {
    939  1.1  augustss 		action0.obutton = action0.button;
    940  1.1  augustss 		continue;
    941  1.1  augustss 	    }
    942  1.1  augustss 	} else {
    943  1.2  augustss #if 0
    944  1.1  augustss 	    /*  MouseRemote client connect/disconnect  */
    945  1.1  augustss 	    if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) {
    946  1.1  augustss 		mremote_clientchg(TRUE);
    947  1.1  augustss 		continue;
    948  1.1  augustss 	    }
    949  1.1  augustss 	    if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) {
    950  1.1  augustss 		mremote_clientchg(FALSE);
    951  1.1  augustss 		continue;
    952  1.1  augustss 	    }
    953  1.2  augustss #endif
    954  1.1  augustss 	    /* mouse movement */
    955  1.1  augustss 	    if (read(rodent.mfd, &b, 1) == -1) {
    956  1.1  augustss 		if (errno == EWOULDBLOCK)
    957  1.1  augustss 		    continue;
    958  1.1  augustss 		else
    959  1.1  augustss 		    return;
    960  1.1  augustss 	    }
    961  1.1  augustss 	    if ((flags = r_protocol(b, &action0)) == 0)
    962  1.1  augustss 		continue;
    963  1.1  augustss 	    r_timestamp(&action0);
    964  1.1  augustss 	    r_statetrans(&action0, &action,
    965  1.1  augustss 	    		 A(action0.button & MOUSE_BUTTON1DOWN,
    966  1.1  augustss 	    		   action0.button & MOUSE_BUTTON3DOWN));
    967  1.1  augustss 	    debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
    968  1.1  augustss 		  action.button, action.obutton);
    969  1.1  augustss 	}
    970  1.1  augustss 	action0.obutton = action0.button;
    971  1.1  augustss 	flags &= MOUSE_POSCHANGED;
    972  1.1  augustss 	flags |= action.obutton ^ action.button;
    973  1.1  augustss 	action.flags = flags;
    974  1.1  augustss 
    975  1.1  augustss 	if (flags) {			/* handler detected action */
    976  1.1  augustss 	    r_map(&action, &action2);
    977  1.1  augustss 	    debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
    978  1.1  augustss 		action2.button, action2.dx, action2.dy, action2.dz);
    979  1.1  augustss 
    980  1.5   thorpej             if (dbg > 1)
    981  1.1  augustss 	        printf("buttons=%x x=%d y=%d z=%d\n", action2.button,
    982  1.1  augustss 		    (int)(action2.dx * rodent.accelx),
    983  1.1  augustss 		    (int)(action2.dy * rodent.accely),
    984  1.1  augustss 		    (int)action2.dz);
    985  1.5   thorpej 	    if (action2.dx != 0 && dbg < 2)
    986  1.1  augustss 		wsev(WSCONS_EVENT_MOUSE_DELTA_X, action2.dx * rodent.accelx);
    987  1.5   thorpej 	    if (action2.dy != 0 && dbg < 2)
    988  1.1  augustss 		wsev(WSCONS_EVENT_MOUSE_DELTA_Y, -action2.dy * rodent.accely);
    989  1.5   thorpej 	    if (action2.dz != 0 && dbg < 2)
    990  1.1  augustss 		wsev(WSCONS_EVENT_MOUSE_DELTA_Z, action2.dz);
    991  1.1  augustss 	    button = lastbutton ^ action2.button;
    992  1.1  augustss 	    lastbutton = action2.button;
    993  1.1  augustss 	    printf("diff=%x buts=%x\n", button, lastbutton);
    994  1.1  augustss 	    for (i = 0; i < 3; i ++) {
    995  1.5   thorpej 		if ((button & (1<<i)) && dbg < 2) {
    996  1.1  augustss 		    wsev(lastbutton & (1<<i) ? WSCONS_EVENT_MOUSE_DOWN :
    997  1.1  augustss 			 WSCONS_EVENT_MOUSE_UP, i);
    998  1.1  augustss 		}
    999  1.1  augustss 	    }
   1000  1.1  augustss 
   1001  1.1  augustss             /*
   1002  1.1  augustss 	     * If the Z axis movement is mapped to a imaginary physical
   1003  1.1  augustss 	     * button, we need to cook up a corresponding button `up' event
   1004  1.1  augustss 	     * after sending a button `down' event.
   1005  1.1  augustss 	     */
   1006  1.1  augustss             if ((rodent.zmap[0] > 0) && (action.dz != 0)) {
   1007  1.1  augustss 		action.obutton = action.button;
   1008  1.1  augustss 		action.dx = action.dy = action.dz = 0;
   1009  1.1  augustss 	        r_map(&action, &action2);
   1010  1.1  augustss 	        debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
   1011  1.1  augustss 		    action2.button, action2.dx, action2.dy, action2.dz);
   1012  1.1  augustss 
   1013  1.1  augustss 		/* XXX emplement this */
   1014  1.1  augustss #if 0
   1015  1.1  augustss 	        if (extioctl) {
   1016  1.1  augustss 	            r_click(&action2);
   1017  1.1  augustss 	        } else {
   1018  1.1  augustss 	            mouse.operation = MOUSE_ACTION;
   1019  1.1  augustss 	            mouse.u.data.buttons = action2.button;
   1020  1.1  augustss 		    mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
   1021  1.5   thorpej 		    if (dbg < 2)
   1022  1.1  augustss 	                ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
   1023  1.1  augustss 	        }
   1024  1.1  augustss #endif
   1025  1.1  augustss 	    }
   1026  1.1  augustss 	}
   1027  1.1  augustss     }
   1028  1.1  augustss     /* NOT REACHED */
   1029  1.1  augustss }
   1030  1.1  augustss 
   1031  1.1  augustss static void
   1032  1.1  augustss hup(int sig)
   1033  1.1  augustss {
   1034  1.1  augustss     longjmp(env, 1);
   1035  1.1  augustss }
   1036  1.1  augustss 
   1037  1.1  augustss static void
   1038  1.1  augustss cleanup(int sig)
   1039  1.1  augustss {
   1040  1.1  augustss     if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM)
   1041  1.1  augustss 	unlink(_PATH_MOUSEREMOTE);
   1042  1.1  augustss     exit(0);
   1043  1.1  augustss }
   1044  1.1  augustss 
   1045  1.1  augustss /**
   1046  1.1  augustss  ** usage
   1047  1.1  augustss  **
   1048  1.1  augustss  ** Complain, and free the CPU for more worthy tasks
   1049  1.1  augustss  **/
   1050  1.1  augustss static void
   1051  1.1  augustss usage(void)
   1052  1.1  augustss {
   1053  1.1  augustss     fprintf(stderr, "%s\n%s\n%s\n%s\n",
   1054  1.1  augustss 	"usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
   1055  1.1  augustss 	"              [-a X[,Y]] [-m N=M] [-w N] [-z N]",
   1056  1.1  augustss 	"              [-t <mousetype>] [-3 [-E timeout]] -p <port>",
   1057  1.1  augustss 	"       moused [-d] -i <port|if|type|model|all> -p <port>");
   1058  1.1  augustss     exit(1);
   1059  1.1  augustss }
   1060  1.1  augustss 
   1061  1.1  augustss /**
   1062  1.1  augustss  ** Mouse interface code, courtesy of XFree86 3.1.2.
   1063  1.1  augustss  **
   1064  1.1  augustss  ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
   1065  1.1  augustss  ** to clean, reformat and rationalise naming, it's quite possible that
   1066  1.1  augustss  ** some things in here have been broken.
   1067  1.1  augustss  **
   1068  1.1  augustss  ** I hope not 8)
   1069  1.1  augustss  **
   1070  1.1  augustss  ** The following code is derived from a module marked :
   1071  1.1  augustss  **/
   1072  1.1  augustss 
   1073  1.1  augustss /* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
   1074  1.1  augustss /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
   1075  1.1  augustss  17:03:40 dawes Exp $ */
   1076  1.1  augustss /*
   1077  1.1  augustss  *
   1078  1.1  augustss  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
   1079  1.1  augustss  * Copyright 1993 by David Dawes <dawes (at) physics.su.oz.au>
   1080  1.1  augustss  *
   1081  1.1  augustss  * Permission to use, copy, modify, distribute, and sell this software and its
   1082  1.1  augustss  * documentation for any purpose is hereby granted without fee, provided that
   1083  1.1  augustss  * the above copyright notice appear in all copies and that both that
   1084  1.1  augustss  * copyright notice and this permission notice appear in supporting
   1085  1.1  augustss  * documentation, and that the names of Thomas Roell and David Dawes not be
   1086  1.1  augustss  * used in advertising or publicity pertaining to distribution of the
   1087  1.1  augustss  * software without specific, written prior permission.  Thomas Roell
   1088  1.1  augustss  * and David Dawes makes no representations about the suitability of this
   1089  1.1  augustss  * software for any purpose.  It is provided "as is" without express or
   1090  1.1  augustss  * implied warranty.
   1091  1.1  augustss  *
   1092  1.1  augustss  * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
   1093  1.1  augustss  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
   1094  1.1  augustss  * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
   1095  1.1  augustss  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
   1096  1.1  augustss  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
   1097  1.1  augustss  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   1098  1.1  augustss  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   1099  1.1  augustss  *
   1100  1.1  augustss  */
   1101  1.1  augustss 
   1102  1.1  augustss /**
   1103  1.1  augustss  ** GlidePoint support from XFree86 3.2.
   1104  1.1  augustss  ** Derived from the module:
   1105  1.1  augustss  **/
   1106  1.1  augustss 
   1107  1.1  augustss /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
   1108  1.1  augustss /* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
   1109  1.1  augustss 
   1110  1.1  augustss /* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
   1111  1.1  augustss static unsigned char proto[][7] = {
   1112  1.1  augustss     /*  hd_mask hd_id   dp_mask dp_id   bytes b4_mask b4_id */
   1113  1.1  augustss     { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* MicroSoft */
   1114  1.1  augustss     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* MouseSystems */
   1115  1.1  augustss     {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* Logitech */
   1116  1.1  augustss     {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MMSeries */
   1117  1.1  augustss     { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* MouseMan */
   1118  1.1  augustss     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* Bus */
   1119  1.1  augustss     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* InPort */
   1120  1.1  augustss     {	0xc0,	0x00,	0x00,	0x00,	3,    0x00,  0xff }, /* PS/2 mouse */
   1121  1.1  augustss     {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MM HitTablet */
   1122  1.1  augustss     { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* GlidePoint */
   1123  1.1  augustss     { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x3f,  0x00 }, /* IntelliMouse */
   1124  1.1  augustss     { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* ThinkingMouse */
   1125  1.1  augustss     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* sysmouse */
   1126  1.1  augustss     { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* X10 MouseRem */
   1127  1.1  augustss     {	0x80,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* KIDSPAD */
   1128  1.1  augustss     {	0xc3,	0xc0,	0x00,	0x00,	6,    0x00,  0xff }, /* VersaPad */
   1129  1.1  augustss #if notyet
   1130  1.1  augustss     {	0xf8,	0x80,	0x00,	0x00,	5,   ~0x2f,  0x10 }, /* Mariqua */
   1131  1.1  augustss #endif
   1132  1.1  augustss };
   1133  1.1  augustss static unsigned char cur_proto[7];
   1134  1.1  augustss 
   1135  1.1  augustss static int
   1136  1.1  augustss r_identify(void)
   1137  1.1  augustss {
   1138  1.1  augustss     char pnpbuf[256];	/* PnP identifier string may be up to 256 bytes long */
   1139  1.1  augustss     pnpid_t pnpid;
   1140  1.1  augustss     symtab_t *t;
   1141  1.1  augustss     int len;
   1142  1.1  augustss 
   1143  1.1  augustss     rodent.level = 0;
   1144  1.1  augustss 
   1145  1.1  augustss     if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
   1146  1.1  augustss         bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
   1147  1.1  augustss     rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
   1148  1.1  augustss     rodent.mode.rate = -1;
   1149  1.1  augustss     rodent.mode.resolution = MOUSE_RES_UNKNOWN;
   1150  1.1  augustss     rodent.mode.accelfactor = 0;
   1151  1.1  augustss     rodent.mode.level = 0;
   1152  1.1  augustss 
   1153  1.1  augustss     /* maybe this is an PnP mouse... */
   1154  1.1  augustss     if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) {
   1155  1.1  augustss 
   1156  1.1  augustss         if (rodent.flags & NoPnP)
   1157  1.1  augustss             return rodent.rtype;
   1158  1.1  augustss 	if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len))
   1159  1.1  augustss             return rodent.rtype;
   1160  1.1  augustss 
   1161  1.1  augustss         debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
   1162  1.1  augustss 	    pnpid.neisaid, pnpid.neisaid, pnpid.eisaid,
   1163  1.1  augustss 	    pnpid.ncompat, pnpid.ncompat, pnpid.compat,
   1164  1.1  augustss 	    pnpid.ndescription, pnpid.ndescription, pnpid.description);
   1165  1.1  augustss 
   1166  1.1  augustss 	/* we have a valid PnP serial device ID */
   1167  1.1  augustss         rodent.hw.iftype = MOUSE_IF_SERIAL;
   1168  1.1  augustss 	t = pnpproto(&pnpid);
   1169  1.1  augustss 	if (t != NULL) {
   1170  1.1  augustss             rodent.mode.protocol = t->val;
   1171  1.1  augustss             rodent.hw.model = t->val2;
   1172  1.1  augustss 	} else {
   1173  1.1  augustss             rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
   1174  1.1  augustss 	}
   1175  1.1  augustss 	if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
   1176  1.1  augustss 	    rodent.mode.protocol = MOUSE_PROTO_BUS;
   1177  1.1  augustss 
   1178  1.1  augustss         /* make final adjustment */
   1179  1.1  augustss 	if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) {
   1180  1.1  augustss 	    if (rodent.mode.protocol != rodent.rtype) {
   1181  1.1  augustss 		/* Hmm, the device doesn't agree with the user... */
   1182  1.1  augustss                 if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
   1183  1.1  augustss 	            logwarnx("mouse type mismatch (%s != %s), %s is assumed",
   1184  1.1  augustss 		        r_name(rodent.mode.protocol), r_name(rodent.rtype),
   1185  1.1  augustss 		        r_name(rodent.mode.protocol));
   1186  1.1  augustss 	        rodent.rtype = rodent.mode.protocol;
   1187  1.1  augustss                 bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
   1188  1.1  augustss 	    }
   1189  1.1  augustss 	}
   1190  1.1  augustss     }
   1191  1.1  augustss 
   1192  1.1  augustss     debug("proto params: %02x %02x %02x %02x %d %02x %02x",
   1193  1.1  augustss 	cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3],
   1194  1.1  augustss 	cur_proto[4], cur_proto[5], cur_proto[6]);
   1195  1.1  augustss 
   1196  1.1  augustss     return rodent.rtype;
   1197  1.1  augustss }
   1198  1.1  augustss 
   1199  1.1  augustss static char *
   1200  1.1  augustss r_if(int iftype)
   1201  1.1  augustss {
   1202  1.1  augustss     char *s;
   1203  1.1  augustss 
   1204  1.1  augustss     s = gettokenname(rifs, iftype);
   1205  1.1  augustss     return (s == NULL) ? "unknown" : s;
   1206  1.1  augustss }
   1207  1.1  augustss 
   1208  1.1  augustss static char *
   1209  1.1  augustss r_name(int type)
   1210  1.1  augustss {
   1211  1.1  augustss     return ((type == MOUSE_PROTO_UNKNOWN)
   1212  1.1  augustss 	|| (type > sizeof(rnames)/sizeof(rnames[0]) - 1))
   1213  1.1  augustss 	? "unknown" : rnames[type];
   1214  1.1  augustss }
   1215  1.1  augustss 
   1216  1.1  augustss static char *
   1217  1.1  augustss r_model(int model)
   1218  1.1  augustss {
   1219  1.1  augustss     char *s;
   1220  1.1  augustss 
   1221  1.1  augustss     s = gettokenname(rmodels, model);
   1222  1.1  augustss     return (s == NULL) ? "unknown" : s;
   1223  1.1  augustss }
   1224  1.1  augustss 
   1225  1.1  augustss static void
   1226  1.1  augustss r_init(void)
   1227  1.1  augustss {
   1228  1.1  augustss     unsigned char buf[16];	/* scrach buffer */
   1229  1.1  augustss     fd_set fds;
   1230  1.1  augustss     char *s;
   1231  1.1  augustss     char c;
   1232  1.1  augustss     int i;
   1233  1.1  augustss 
   1234  1.1  augustss     /**
   1235  1.1  augustss      ** This comment is a little out of context here, but it contains
   1236  1.1  augustss      ** some useful information...
   1237  1.1  augustss      ********************************************************************
   1238  1.1  augustss      **
   1239  1.1  augustss      ** The following lines take care of the Logitech MouseMan protocols.
   1240  1.1  augustss      **
   1241  1.1  augustss      ** NOTE: There are different versions of both MouseMan and TrackMan!
   1242  1.1  augustss      **       Hence I add another protocol P_LOGIMAN, which the user can
   1243  1.1  augustss      **       specify as MouseMan in his XF86Config file. This entry was
   1244  1.1  augustss      **       formerly handled as a special case of P_MS. However, people
   1245  1.1  augustss      **       who don't have the middle button problem, can still specify
   1246  1.1  augustss      **       Microsoft and use P_MS.
   1247  1.1  augustss      **
   1248  1.1  augustss      ** By default, these mice should use a 3 byte Microsoft protocol
   1249  1.1  augustss      ** plus a 4th byte for the middle button. However, the mouse might
   1250  1.1  augustss      ** have switched to a different protocol before we use it, so I send
   1251  1.1  augustss      ** the proper sequence just in case.
   1252  1.1  augustss      **
   1253  1.1  augustss      ** NOTE: - all commands to (at least the European) MouseMan have to
   1254  1.1  augustss      **         be sent at 1200 Baud.
   1255  1.1  augustss      **       - each command starts with a '*'.
   1256  1.1  augustss      **       - whenever the MouseMan receives a '*', it will switch back
   1257  1.1  augustss      **	 to 1200 Baud. Hence I have to select the desired protocol
   1258  1.1  augustss      **	 first, then select the baud rate.
   1259  1.1  augustss      **
   1260  1.1  augustss      ** The protocols supported by the (European) MouseMan are:
   1261  1.1  augustss      **   -  5 byte packed binary protocol, as with the Mouse Systems
   1262  1.1  augustss      **      mouse. Selected by sequence "*U".
   1263  1.1  augustss      **   -  2 button 3 byte MicroSoft compatible protocol. Selected
   1264  1.1  augustss      **      by sequence "*V".
   1265  1.1  augustss      **   -  3 button 3+1 byte MicroSoft compatible protocol (default).
   1266  1.1  augustss      **      Selected by sequence "*X".
   1267  1.1  augustss      **
   1268  1.1  augustss      ** The following baud rates are supported:
   1269  1.1  augustss      **   -  1200 Baud (default). Selected by sequence "*n".
   1270  1.1  augustss      **   -  9600 Baud. Selected by sequence "*q".
   1271  1.1  augustss      **
   1272  1.1  augustss      ** Selecting a sample rate is no longer supported with the MouseMan!
   1273  1.1  augustss      ** Some additional lines in xf86Config.c take care of ill configured
   1274  1.1  augustss      ** baud rates and sample rates. (The user will get an error.)
   1275  1.1  augustss      */
   1276  1.1  augustss 
   1277  1.1  augustss     switch (rodent.rtype) {
   1278  1.1  augustss 
   1279  1.1  augustss     case MOUSE_PROTO_LOGI:
   1280  1.1  augustss 	/*
   1281  1.1  augustss 	 * The baud rate selection command must be sent at the current
   1282  1.1  augustss 	 * baud rate; try all likely settings
   1283  1.1  augustss 	 */
   1284  1.1  augustss 	setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
   1285  1.1  augustss 	setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
   1286  1.1  augustss 	setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
   1287  1.1  augustss 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1288  1.1  augustss 	/* select MM series data format */
   1289  1.1  augustss 	write(rodent.mfd, "S", 1);
   1290  1.1  augustss 	setmousespeed(rodent.baudrate, rodent.baudrate,
   1291  1.1  augustss 		      rodentcflags[MOUSE_PROTO_MM]);
   1292  1.1  augustss 	/* select report rate/frequency */
   1293  1.1  augustss 	if      (rodent.rate <= 0)   write(rodent.mfd, "O", 1);
   1294  1.1  augustss 	else if (rodent.rate <= 15)  write(rodent.mfd, "J", 1);
   1295  1.1  augustss 	else if (rodent.rate <= 27)  write(rodent.mfd, "K", 1);
   1296  1.1  augustss 	else if (rodent.rate <= 42)  write(rodent.mfd, "L", 1);
   1297  1.1  augustss 	else if (rodent.rate <= 60)  write(rodent.mfd, "R", 1);
   1298  1.1  augustss 	else if (rodent.rate <= 85)  write(rodent.mfd, "M", 1);
   1299  1.1  augustss 	else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1);
   1300  1.1  augustss 	else			     write(rodent.mfd, "N", 1);
   1301  1.1  augustss 	break;
   1302  1.1  augustss 
   1303  1.1  augustss     case MOUSE_PROTO_LOGIMOUSEMAN:
   1304  1.1  augustss 	/* The command must always be sent at 1200 baud */
   1305  1.1  augustss 	setmousespeed(1200, 1200, rodentcflags[rodent.rtype]);
   1306  1.1  augustss 	write(rodent.mfd, "*X", 2);
   1307  1.1  augustss 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1308  1.1  augustss 	break;
   1309  1.1  augustss 
   1310  1.1  augustss     case MOUSE_PROTO_HITTAB:
   1311  1.1  augustss 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1312  1.1  augustss 
   1313  1.1  augustss 	/*
   1314  1.1  augustss 	 * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
   1315  1.1  augustss 	 * The tablet must be configured to be in MM mode, NO parity,
   1316  1.1  augustss 	 * Binary Format.  xf86Info.sampleRate controls the sensativity
   1317  1.1  augustss 	 * of the tablet.  We only use this tablet for it's 4-button puck
   1318  1.1  augustss 	 * so we don't run in "Absolute Mode"
   1319  1.1  augustss 	 */
   1320  1.1  augustss 	write(rodent.mfd, "z8", 2);	/* Set Parity = "NONE" */
   1321  1.1  augustss 	usleep(50000);
   1322  1.1  augustss 	write(rodent.mfd, "zb", 2);	/* Set Format = "Binary" */
   1323  1.1  augustss 	usleep(50000);
   1324  1.1  augustss 	write(rodent.mfd, "@", 1);	/* Set Report Mode = "Stream" */
   1325  1.1  augustss 	usleep(50000);
   1326  1.1  augustss 	write(rodent.mfd, "R", 1);	/* Set Output Rate = "45 rps" */
   1327  1.1  augustss 	usleep(50000);
   1328  1.1  augustss 	write(rodent.mfd, "I\x20", 2);	/* Set Incrememtal Mode "20" */
   1329  1.1  augustss 	usleep(50000);
   1330  1.1  augustss 	write(rodent.mfd, "E", 1);	/* Set Data Type = "Relative */
   1331  1.1  augustss 	usleep(50000);
   1332  1.1  augustss 
   1333  1.1  augustss 	/* Resolution is in 'lines per inch' on the Hitachi tablet */
   1334  1.1  augustss 	if      (rodent.resolution == MOUSE_RES_LOW) 		c = 'g';
   1335  1.1  augustss 	else if (rodent.resolution == MOUSE_RES_MEDIUMLOW)	c = 'e';
   1336  1.1  augustss 	else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH)	c = 'h';
   1337  1.1  augustss 	else if (rodent.resolution == MOUSE_RES_HIGH)		c = 'd';
   1338  1.1  augustss 	else if (rodent.resolution <=   40) 			c = 'g';
   1339  1.1  augustss 	else if (rodent.resolution <=  100) 			c = 'd';
   1340  1.1  augustss 	else if (rodent.resolution <=  200) 			c = 'e';
   1341  1.1  augustss 	else if (rodent.resolution <=  500) 			c = 'h';
   1342  1.1  augustss 	else if (rodent.resolution <= 1000) 			c = 'j';
   1343  1.1  augustss 	else                                			c = 'd';
   1344  1.1  augustss 	write(rodent.mfd, &c, 1);
   1345  1.1  augustss 	usleep(50000);
   1346  1.1  augustss 
   1347  1.1  augustss 	write(rodent.mfd, "\021", 1);	/* Resume DATA output */
   1348  1.1  augustss 	break;
   1349  1.1  augustss 
   1350  1.1  augustss     case MOUSE_PROTO_THINK:
   1351  1.1  augustss 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1352  1.1  augustss 	/* the PnP ID string may be sent again, discard it */
   1353  1.1  augustss 	usleep(200000);
   1354  1.1  augustss 	i = FREAD;
   1355  1.1  augustss 	ioctl(rodent.mfd, TIOCFLUSH, &i);
   1356  1.1  augustss 	/* send the command to initialize the beast */
   1357  1.1  augustss 	for (s = "E5E5"; *s; ++s) {
   1358  1.1  augustss 	    write(rodent.mfd, s, 1);
   1359  1.1  augustss 	    FD_ZERO(&fds);
   1360  1.1  augustss 	    FD_SET(rodent.mfd, &fds);
   1361  1.1  augustss 	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
   1362  1.1  augustss 		break;
   1363  1.1  augustss 	    read(rodent.mfd, &c, 1);
   1364  1.1  augustss 	    debug("%c", c);
   1365  1.1  augustss 	    if (c != *s)
   1366  1.1  augustss 	        break;
   1367  1.1  augustss 	}
   1368  1.1  augustss 	break;
   1369  1.1  augustss 
   1370  1.1  augustss     case MOUSE_PROTO_MSC:
   1371  1.1  augustss 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1372  1.1  augustss 	if (rodent.flags & ClearDTR) {
   1373  1.1  augustss 	   i = TIOCM_DTR;
   1374  1.1  augustss 	   ioctl(rodent.mfd, TIOCMBIC, &i);
   1375  1.1  augustss         }
   1376  1.1  augustss         if (rodent.flags & ClearRTS) {
   1377  1.1  augustss 	   i = TIOCM_RTS;
   1378  1.1  augustss 	   ioctl(rodent.mfd, TIOCMBIC, &i);
   1379  1.1  augustss         }
   1380  1.1  augustss 	break;
   1381  1.1  augustss 
   1382  1.1  augustss     case MOUSE_PROTO_SYSMOUSE:
   1383  1.1  augustss 	if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE)
   1384  1.1  augustss 	    setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1385  1.1  augustss 	/* fall through */
   1386  1.1  augustss 
   1387  1.1  augustss     case MOUSE_PROTO_BUS:
   1388  1.1  augustss     case MOUSE_PROTO_INPORT:
   1389  1.1  augustss     case MOUSE_PROTO_PS2:
   1390  1.1  augustss 	if (rodent.rate >= 0)
   1391  1.1  augustss 	    rodent.mode.rate = rodent.rate;
   1392  1.1  augustss 	if (rodent.resolution != MOUSE_RES_UNKNOWN)
   1393  1.1  augustss 	    rodent.mode.resolution = rodent.resolution;
   1394  1.1  augustss #if 0
   1395  1.1  augustss 	ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode);
   1396  1.1  augustss #endif
   1397  1.1  augustss 	break;
   1398  1.1  augustss 
   1399  1.1  augustss     case MOUSE_PROTO_X10MOUSEREM:
   1400  1.1  augustss #if 0
   1401  1.1  augustss 	mremote_serversetup();
   1402  1.1  augustss #endif
   1403  1.1  augustss 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1404  1.1  augustss 	break;
   1405  1.1  augustss 
   1406  1.1  augustss 
   1407  1.1  augustss     case MOUSE_PROTO_VERSAPAD:
   1408  1.1  augustss 	tcsendbreak(rodent.mfd, 0);	/* send break for 400 msec */
   1409  1.1  augustss 	i = FREAD;
   1410  1.1  augustss 	ioctl(rodent.mfd, TIOCFLUSH, &i);
   1411  1.1  augustss 	for (i = 0; i < 7; ++i) {
   1412  1.1  augustss 	    FD_ZERO(&fds);
   1413  1.1  augustss 	    FD_SET(rodent.mfd, &fds);
   1414  1.1  augustss 	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
   1415  1.1  augustss 		break;
   1416  1.1  augustss 	    read(rodent.mfd, &c, 1);
   1417  1.1  augustss 	    buf[i] = c;
   1418  1.1  augustss 	}
   1419  1.1  augustss 	debug("%s\n", buf);
   1420  1.1  augustss 	if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r'))
   1421  1.1  augustss 	    break;
   1422  1.1  augustss 	setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
   1423  1.1  augustss 	tcsendbreak(rodent.mfd, 0);	/* send break for 400 msec again */
   1424  1.1  augustss 	for (i = 0; i < 7; ++i) {
   1425  1.1  augustss 	    FD_ZERO(&fds);
   1426  1.1  augustss 	    FD_SET(rodent.mfd, &fds);
   1427  1.1  augustss 	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
   1428  1.1  augustss 		break;
   1429  1.1  augustss 	    read(rodent.mfd, &c, 1);
   1430  1.1  augustss 	    debug("%c", c);
   1431  1.1  augustss 	    if (c != buf[i])
   1432  1.1  augustss 		break;
   1433  1.1  augustss 	}
   1434  1.1  augustss 	i = FREAD;
   1435  1.1  augustss 	ioctl(rodent.mfd, TIOCFLUSH, &i);
   1436  1.1  augustss 	break;
   1437  1.1  augustss 
   1438  1.1  augustss     default:
   1439  1.1  augustss 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
   1440  1.1  augustss 	break;
   1441  1.1  augustss     }
   1442  1.1  augustss }
   1443  1.1  augustss 
   1444  1.1  augustss static int
   1445  1.1  augustss r_protocol(u_char rBuf, mousestatus_t *act)
   1446  1.1  augustss {
   1447  1.1  augustss     /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
   1448  1.1  augustss     static int butmapmss[4] = {	/* Microsoft, MouseMan, GlidePoint,
   1449  1.1  augustss 				   IntelliMouse, Thinking Mouse */
   1450  1.1  augustss 	0,
   1451  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1452  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1453  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
   1454  1.1  augustss     };
   1455  1.1  augustss     static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint,
   1456  1.1  augustss 				    Thinking Mouse */
   1457  1.1  augustss 	0,
   1458  1.1  augustss 	MOUSE_BUTTON4DOWN,
   1459  1.1  augustss 	MOUSE_BUTTON2DOWN,
   1460  1.1  augustss 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
   1461  1.1  augustss     };
   1462  1.1  augustss     /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
   1463  1.1  augustss     static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
   1464  1.1  augustss 				       MouseMan+ */
   1465  1.1  augustss 	0,
   1466  1.1  augustss 	MOUSE_BUTTON2DOWN,
   1467  1.1  augustss 	MOUSE_BUTTON4DOWN,
   1468  1.1  augustss 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
   1469  1.1  augustss     };
   1470  1.1  augustss     /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
   1471  1.1  augustss     static int butmapmsc[8] = {	/* MouseSystems, MMSeries, Logitech,
   1472  1.1  augustss 				   Bus, sysmouse */
   1473  1.1  augustss 	0,
   1474  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1475  1.1  augustss 	MOUSE_BUTTON2DOWN,
   1476  1.1  augustss 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
   1477  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1478  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
   1479  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
   1480  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
   1481  1.1  augustss     };
   1482  1.1  augustss     /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
   1483  1.1  augustss     static int butmapps2[8] = {	/* PS/2 */
   1484  1.1  augustss 	0,
   1485  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1486  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1487  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
   1488  1.1  augustss 	MOUSE_BUTTON2DOWN,
   1489  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
   1490  1.1  augustss 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
   1491  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
   1492  1.1  augustss     };
   1493  1.1  augustss     /* for Hitachi tablet */
   1494  1.1  augustss     static int butmaphit[8] = {	/* MM HitTablet */
   1495  1.1  augustss 	0,
   1496  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1497  1.1  augustss 	MOUSE_BUTTON2DOWN,
   1498  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1499  1.1  augustss 	MOUSE_BUTTON4DOWN,
   1500  1.1  augustss 	MOUSE_BUTTON5DOWN,
   1501  1.1  augustss 	MOUSE_BUTTON6DOWN,
   1502  1.1  augustss 	MOUSE_BUTTON7DOWN,
   1503  1.1  augustss     };
   1504  1.1  augustss     /* for serial VersaPad */
   1505  1.1  augustss     static int butmapversa[8] = { /* VersaPad */
   1506  1.1  augustss 	0,
   1507  1.1  augustss 	0,
   1508  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1509  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1510  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1511  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1512  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
   1513  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
   1514  1.1  augustss     };
   1515  1.1  augustss     /* for PS/2 VersaPad */
   1516  1.1  augustss     static int butmapversaps2[8] = { /* VersaPad */
   1517  1.1  augustss 	0,
   1518  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1519  1.1  augustss 	0,
   1520  1.1  augustss 	MOUSE_BUTTON3DOWN,
   1521  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1522  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
   1523  1.1  augustss 	MOUSE_BUTTON1DOWN,
   1524  1.1  augustss 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
   1525  1.1  augustss     };
   1526  1.1  augustss     static int           pBufP = 0;
   1527  1.1  augustss     static unsigned char pBuf[8];
   1528  1.1  augustss     static int		 prev_x, prev_y;
   1529  1.1  augustss     static int		 on = FALSE;
   1530  1.1  augustss     int			 x, y;
   1531  1.1  augustss 
   1532  1.1  augustss     debug("received char 0x%x",(int)rBuf);
   1533  1.1  augustss     if (rodent.rtype == MOUSE_PROTO_KIDSPAD)
   1534  1.1  augustss 	return kidspad(rBuf, act) ;
   1535  1.1  augustss 
   1536  1.1  augustss     /*
   1537  1.1  augustss      * Hack for resyncing: We check here for a package that is:
   1538  1.1  augustss      *  a) illegal (detected by wrong data-package header)
   1539  1.1  augustss      *  b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
   1540  1.1  augustss      *  c) bad header-package
   1541  1.1  augustss      *
   1542  1.1  augustss      * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
   1543  1.1  augustss      *       -128 are allowed, but since they are very seldom we can easily
   1544  1.1  augustss      *       use them as package-header with no button pressed.
   1545  1.1  augustss      * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
   1546  1.1  augustss      *         0x80 is not valid as a header byte. For a PS/2 mouse we skip
   1547  1.1  augustss      *         checking data bytes.
   1548  1.1  augustss      *         For resyncing a PS/2 mouse we require the two most significant
   1549  1.1  augustss      *         bits in the header byte to be 0. These are the overflow bits,
   1550  1.1  augustss      *         and in case of an overflow we actually lose sync. Overflows
   1551  1.1  augustss      *         are very rare, however, and we quickly gain sync again after
   1552  1.1  augustss      *         an overflow condition. This is the best we can do. (Actually,
   1553  1.1  augustss      *         we could use bit 0x08 in the header byte for resyncing, since
   1554  1.1  augustss      *         that bit is supposed to be always on, but nobody told
   1555  1.1  augustss      *         Microsoft...)
   1556  1.1  augustss      */
   1557  1.1  augustss 
   1558  1.1  augustss     if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 &&
   1559  1.1  augustss 	((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80))
   1560  1.1  augustss     {
   1561  1.1  augustss 	pBufP = 0;		/* skip package */
   1562  1.1  augustss     }
   1563  1.1  augustss 
   1564  1.1  augustss     if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1])
   1565  1.1  augustss 	return 0;
   1566  1.1  augustss 
   1567  1.1  augustss     /* is there an extra data byte? */
   1568  1.1  augustss     if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1])
   1569  1.1  augustss     {
   1570  1.1  augustss 	/*
   1571  1.1  augustss 	 * Hack for Logitech MouseMan Mouse - Middle button
   1572  1.1  augustss 	 *
   1573  1.1  augustss 	 * Unfortunately this mouse has variable length packets: the standard
   1574  1.1  augustss 	 * Microsoft 3 byte packet plus an optional 4th byte whenever the
   1575  1.1  augustss 	 * middle button status changes.
   1576  1.1  augustss 	 *
   1577  1.1  augustss 	 * We have already processed the standard packet with the movement
   1578  1.1  augustss 	 * and button info.  Now post an event message with the old status
   1579  1.1  augustss 	 * of the left and right buttons and the updated middle button.
   1580  1.1  augustss 	 */
   1581  1.1  augustss 
   1582  1.1  augustss 	/*
   1583  1.1  augustss 	 * Even worse, different MouseMen and TrackMen differ in the 4th
   1584  1.1  augustss 	 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
   1585  1.1  augustss 	 * 0x02/0x22, so I have to strip off the lower bits.
   1586  1.1  augustss          *
   1587  1.1  augustss          * [JCH-96/01/21]
   1588  1.1  augustss          * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
   1589  1.1  augustss          * and it is activated by tapping the glidepad with the finger! 8^)
   1590  1.1  augustss          * We map it to bit bit3, and the reverse map in xf86Events just has
   1591  1.1  augustss          * to be extended so that it is identified as Button 4. The lower
   1592  1.1  augustss          * half of the reverse-map may remain unchanged.
   1593  1.1  augustss 	 */
   1594  1.1  augustss 
   1595  1.1  augustss         /*
   1596  1.1  augustss 	 * [KY-97/08/03]
   1597  1.1  augustss 	 * Receive the fourth byte only when preceding three bytes have
   1598  1.1  augustss 	 * been detected (pBufP >= cur_proto[4]).  In the previous
   1599  1.1  augustss 	 * versions, the test was pBufP == 0; thus, we may have mistakingly
   1600  1.1  augustss 	 * received a byte even if we didn't see anything preceding
   1601  1.1  augustss 	 * the byte.
   1602  1.1  augustss 	 */
   1603  1.1  augustss 
   1604  1.1  augustss 	if ((rBuf & cur_proto[5]) != cur_proto[6]) {
   1605  1.1  augustss             pBufP = 0;
   1606  1.1  augustss 	    return 0;
   1607  1.1  augustss 	}
   1608  1.1  augustss 
   1609  1.1  augustss 	switch (rodent.rtype) {
   1610  1.1  augustss #if notyet
   1611  1.1  augustss 	case MOUSE_PROTO_MARIQUA:
   1612  1.1  augustss 	    /*
   1613  1.1  augustss 	     * This mouse has 16! buttons in addition to the standard
   1614  1.1  augustss 	     * three of them.  They return 0x10 though 0x1f in the
   1615  1.1  augustss 	     * so-called `ten key' mode and 0x30 though 0x3f in the
   1616  1.1  augustss 	     * `function key' mode.  As there are only 31 bits for
   1617  1.1  augustss 	     * button state (including the standard three), we ignore
   1618  1.1  augustss 	     * the bit 0x20 and don't distinguish the two modes.
   1619  1.1  augustss 	     */
   1620  1.1  augustss 	    act->dx = act->dy = act->dz = 0;
   1621  1.1  augustss 	    act->obutton = act->button;
   1622  1.1  augustss 	    rBuf &= 0x1f;
   1623  1.1  augustss 	    act->button = (1 << (rBuf - 13))
   1624  1.1  augustss                 | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
   1625  1.1  augustss 	    /*
   1626  1.1  augustss 	     * FIXME: this is a button "down" event. There needs to be
   1627  1.1  augustss 	     * a corresponding button "up" event... XXX
   1628  1.1  augustss 	     */
   1629  1.1  augustss 	    break;
   1630  1.1  augustss #endif /* notyet */
   1631  1.1  augustss 
   1632  1.1  augustss 	/*
   1633  1.1  augustss 	 * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
   1634  1.1  augustss 	 * always send the fourth byte, whereas the fourth byte is
   1635  1.1  augustss 	 * optional for GlidePoint and ThinkingMouse. The fourth byte
   1636  1.1  augustss 	 * is also optional for MouseMan+ and FirstMouse+ in their
   1637  1.1  augustss 	 * native mode. It is always sent if they are in the IntelliMouse
   1638  1.1  augustss 	 * compatible mode.
   1639  1.1  augustss 	 */
   1640  1.1  augustss 	case MOUSE_PROTO_INTELLI:	/* IntelliMouse, NetMouse, Mie Mouse,
   1641  1.1  augustss 					   MouseMan+ */
   1642  1.1  augustss 	    act->dx = act->dy = 0;
   1643  1.1  augustss 	    act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f);
   1644  1.1  augustss 	    if ((act->dz >= 7) || (act->dz <= -7))
   1645  1.1  augustss 		act->dz = 0;
   1646  1.1  augustss 	    act->obutton = act->button;
   1647  1.1  augustss 	    act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
   1648  1.1  augustss 		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
   1649  1.1  augustss 	    break;
   1650  1.1  augustss 
   1651  1.1  augustss 	default:
   1652  1.1  augustss 	    act->dx = act->dy = act->dz = 0;
   1653  1.1  augustss 	    act->obutton = act->button;
   1654  1.1  augustss 	    act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
   1655  1.1  augustss 		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
   1656  1.1  augustss 	    break;
   1657  1.1  augustss 	}
   1658  1.1  augustss 
   1659  1.1  augustss 	act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
   1660  1.1  augustss 	    | (act->obutton ^ act->button);
   1661  1.1  augustss         pBufP = 0;
   1662  1.1  augustss 	return act->flags;
   1663  1.1  augustss     }
   1664  1.1  augustss 
   1665  1.1  augustss     if (pBufP >= cur_proto[4])
   1666  1.1  augustss 	pBufP = 0;
   1667  1.1  augustss     pBuf[pBufP++] = rBuf;
   1668  1.1  augustss     if (pBufP != cur_proto[4])
   1669  1.1  augustss 	return 0;
   1670  1.1  augustss 
   1671  1.1  augustss     /*
   1672  1.1  augustss      * assembly full package
   1673  1.1  augustss      */
   1674  1.1  augustss 
   1675  1.1  augustss     debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
   1676  1.1  augustss 	cur_proto[4],
   1677  1.1  augustss 	pBuf[0], pBuf[1], pBuf[2], pBuf[3],
   1678  1.1  augustss 	pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
   1679  1.1  augustss 
   1680  1.1  augustss     act->dz = 0;
   1681  1.1  augustss     act->obutton = act->button;
   1682  1.1  augustss     switch (rodent.rtype)
   1683  1.1  augustss     {
   1684  1.1  augustss     case MOUSE_PROTO_MS:		/* Microsoft */
   1685  1.1  augustss     case MOUSE_PROTO_LOGIMOUSEMAN:	/* MouseMan/TrackMan */
   1686  1.1  augustss     case MOUSE_PROTO_X10MOUSEREM:	/* X10 MouseRemote */
   1687  1.1  augustss 	act->button = act->obutton & MOUSE_BUTTON4DOWN;
   1688  1.1  augustss 	if (rodent.flags & ChordMiddle)
   1689  1.1  augustss 	    act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS)
   1690  1.1  augustss 		? MOUSE_BUTTON2DOWN
   1691  1.1  augustss 		: butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
   1692  1.1  augustss 	else
   1693  1.1  augustss 	    act->button |= (act->obutton & MOUSE_BUTTON2DOWN)
   1694  1.1  augustss 		| butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
   1695  1.1  augustss 
   1696  1.2  augustss #if 0
   1697  1.1  augustss 	/* Send X10 btn events to remote client (ensure -128-+127 range) */
   1698  1.1  augustss 	if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) &&
   1699  1.1  augustss 	    ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) {
   1700  1.1  augustss 	    if (rodent.mremcfd >= 0) {
   1701  1.1  augustss 		unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) |
   1702  1.1  augustss 						  (pBuf[1] & 0x3F));
   1703  1.1  augustss 		write( rodent.mremcfd, &key, 1 );
   1704  1.1  augustss 	    }
   1705  1.1  augustss 	    return 0;
   1706  1.1  augustss 	}
   1707  1.2  augustss #endif
   1708  1.1  augustss 
   1709  1.1  augustss 	act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
   1710  1.1  augustss 	act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
   1711  1.1  augustss 	break;
   1712  1.1  augustss 
   1713  1.1  augustss     case MOUSE_PROTO_GLIDEPOINT:	/* GlidePoint */
   1714  1.1  augustss     case MOUSE_PROTO_THINK:		/* ThinkingMouse */
   1715  1.1  augustss     case MOUSE_PROTO_INTELLI:		/* IntelliMouse, NetMouse, Mie Mouse,
   1716  1.1  augustss 					   MouseMan+ */
   1717  1.1  augustss 	act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN))
   1718  1.1  augustss             | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
   1719  1.1  augustss 	act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
   1720  1.1  augustss 	act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
   1721  1.1  augustss 	break;
   1722  1.1  augustss 
   1723  1.1  augustss     case MOUSE_PROTO_MSC:		/* MouseSystems Corp */
   1724  1.1  augustss #if notyet
   1725  1.1  augustss     case MOUSE_PROTO_MARIQUA:		/* Mariqua */
   1726  1.1  augustss #endif
   1727  1.1  augustss 	act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
   1728  1.1  augustss 	act->dx =    (char)(pBuf[1]) + (char)(pBuf[3]);
   1729  1.1  augustss 	act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
   1730  1.1  augustss 	break;
   1731  1.1  augustss 
   1732  1.1  augustss     case MOUSE_PROTO_HITTAB:		/* MM HitTablet */
   1733  1.1  augustss 	act->button = butmaphit[pBuf[0] & 0x07];
   1734  1.1  augustss 	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
   1735  1.1  augustss 	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
   1736  1.1  augustss 	break;
   1737  1.1  augustss 
   1738  1.1  augustss     case MOUSE_PROTO_MM:		/* MM Series */
   1739  1.1  augustss     case MOUSE_PROTO_LOGI:		/* Logitech Mice */
   1740  1.1  augustss 	act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS];
   1741  1.1  augustss 	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
   1742  1.1  augustss 	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
   1743  1.1  augustss 	break;
   1744  1.1  augustss 
   1745  1.1  augustss     case MOUSE_PROTO_VERSAPAD:		/* VersaPad */
   1746  1.1  augustss 	act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3];
   1747  1.1  augustss 	act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
   1748  1.1  augustss 	act->dx = act->dy = 0;
   1749  1.1  augustss 	if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) {
   1750  1.1  augustss 	    on = FALSE;
   1751  1.1  augustss 	    break;
   1752  1.1  augustss 	}
   1753  1.1  augustss 	x = (pBuf[2] << 6) | pBuf[1];
   1754  1.1  augustss 	if (x & 0x800)
   1755  1.1  augustss 	    x -= 0x1000;
   1756  1.1  augustss 	y = (pBuf[4] << 6) | pBuf[3];
   1757  1.1  augustss 	if (y & 0x800)
   1758  1.1  augustss 	    y -= 0x1000;
   1759  1.1  augustss 	if (on) {
   1760  1.1  augustss 	    act->dx = prev_x - x;
   1761  1.1  augustss 	    act->dy = prev_y - y;
   1762  1.1  augustss 	} else {
   1763  1.1  augustss 	    on = TRUE;
   1764  1.1  augustss 	}
   1765  1.1  augustss 	prev_x = x;
   1766  1.1  augustss 	prev_y = y;
   1767  1.1  augustss 	break;
   1768  1.1  augustss 
   1769  1.1  augustss     case MOUSE_PROTO_BUS:		/* Bus */
   1770  1.1  augustss     case MOUSE_PROTO_INPORT:		/* InPort */
   1771  1.1  augustss 	act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
   1772  1.1  augustss 	act->dx =   (char)pBuf[1];
   1773  1.1  augustss 	act->dy = - (char)pBuf[2];
   1774  1.1  augustss 	break;
   1775  1.1  augustss 
   1776  1.1  augustss     case MOUSE_PROTO_PS2:		/* PS/2 */
   1777  1.1  augustss 	act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS];
   1778  1.1  augustss 	act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ?    pBuf[1] - 256  :  pBuf[1];
   1779  1.1  augustss 	act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ?  -(pBuf[2] - 256) : -pBuf[2];
   1780  1.1  augustss 	/*
   1781  1.1  augustss 	 * Moused usually operates the psm driver at the operation level 1
   1782  1.1  augustss 	 * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
   1783  1.1  augustss 	 * The following code takes effect only when the user explicitly
   1784  1.1  augustss 	 * requets the level 2 at which wheel movement and additional button
   1785  1.1  augustss 	 * actions are encoded in model-dependent formats. At the level 0
   1786  1.1  augustss 	 * the following code is no-op because the psm driver says the model
   1787  1.1  augustss 	 * is MOUSE_MODEL_GENERIC.
   1788  1.1  augustss 	 */
   1789  1.1  augustss 	switch (rodent.hw.model) {
   1790  1.1  augustss 	case MOUSE_MODEL_EXPLORER:
   1791  1.1  augustss 	    /* wheel and additional button data is in the fourth byte */
   1792  1.1  augustss 	    act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG)
   1793  1.1  augustss 		? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f);
   1794  1.1  augustss 	    act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN)
   1795  1.1  augustss 		? MOUSE_BUTTON4DOWN : 0;
   1796  1.1  augustss 	    act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN)
   1797  1.1  augustss 		? MOUSE_BUTTON5DOWN : 0;
   1798  1.1  augustss 	    break;
   1799  1.1  augustss 	case MOUSE_MODEL_INTELLI:
   1800  1.1  augustss 	case MOUSE_MODEL_NET:
   1801  1.1  augustss 	    /* wheel data is in the fourth byte */
   1802  1.1  augustss 	    act->dz = (char)pBuf[3];
   1803  1.1  augustss 	    if ((act->dz >= 7) || (act->dz <= -7))
   1804  1.1  augustss 		act->dz = 0;
   1805  1.1  augustss 	    /* some compatible mice may have additional buttons */
   1806  1.1  augustss 	    act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN)
   1807  1.1  augustss 		? MOUSE_BUTTON4DOWN : 0;
   1808  1.1  augustss 	    act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN)
   1809  1.1  augustss 		? MOUSE_BUTTON5DOWN : 0;
   1810  1.1  augustss 	    break;
   1811  1.1  augustss 	case MOUSE_MODEL_MOUSEMANPLUS:
   1812  1.1  augustss 	    if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
   1813  1.1  augustss 		    && (abs(act->dx) > 191)
   1814  1.1  augustss 		    && MOUSE_PS2PLUS_CHECKBITS(pBuf)) {
   1815  1.1  augustss 		/* the extended data packet encodes button and wheel events */
   1816  1.1  augustss 		switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) {
   1817  1.1  augustss 		case 1:
   1818  1.1  augustss 		    /* wheel data packet */
   1819  1.1  augustss 		    act->dx = act->dy = 0;
   1820  1.1  augustss 		    if (pBuf[2] & 0x80) {
   1821  1.1  augustss 			/* horizontal roller count - ignore it XXX*/
   1822  1.1  augustss 		    } else {
   1823  1.1  augustss 			/* vertical roller count */
   1824  1.1  augustss 			act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG)
   1825  1.1  augustss 			    ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
   1826  1.1  augustss 		    }
   1827  1.1  augustss 		    act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
   1828  1.1  augustss 			? MOUSE_BUTTON4DOWN : 0;
   1829  1.1  augustss 		    act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
   1830  1.1  augustss 			? MOUSE_BUTTON5DOWN : 0;
   1831  1.1  augustss 		    break;
   1832  1.1  augustss 		case 2:
   1833  1.1  augustss 		    /* this packet type is reserved by Logitech */
   1834  1.1  augustss 		    /*
   1835  1.1  augustss 		     * IBM ScrollPoint Mouse uses this packet type to
   1836  1.1  augustss 		     * encode both vertical and horizontal scroll movement.
   1837  1.1  augustss 		     */
   1838  1.1  augustss 		    act->dx = act->dy = 0;
   1839  1.1  augustss 		    /* horizontal roller count */
   1840  1.1  augustss 		    if (pBuf[2] & 0x0f)
   1841  1.1  augustss 			act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
   1842  1.1  augustss 		    /* vertical roller count */
   1843  1.1  augustss 		    if (pBuf[2] & 0xf0)
   1844  1.1  augustss 			act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
   1845  1.1  augustss #if 0
   1846  1.1  augustss 		    /* vertical roller count */
   1847  1.1  augustss 		    act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG)
   1848  1.1  augustss 			? ((pBuf[2] >> 4) & 0x0f) - 16
   1849  1.1  augustss 			: ((pBuf[2] >> 4) & 0x0f);
   1850  1.1  augustss 		    /* horizontal roller count */
   1851  1.1  augustss 		    act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG)
   1852  1.1  augustss 			? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
   1853  1.1  augustss #endif
   1854  1.1  augustss 		    break;
   1855  1.1  augustss 		case 0:
   1856  1.1  augustss 		    /* device type packet - shouldn't happen */
   1857  1.1  augustss 		    /* FALL THROUGH */
   1858  1.1  augustss 		default:
   1859  1.1  augustss 		    act->dx = act->dy = 0;
   1860  1.1  augustss 		    act->button = act->obutton;
   1861  1.1  augustss             	    debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n",
   1862  1.1  augustss 			  MOUSE_PS2PLUS_PACKET_TYPE(pBuf),
   1863  1.1  augustss 			  pBuf[0], pBuf[1], pBuf[2]);
   1864  1.1  augustss 		    break;
   1865  1.1  augustss 		}
   1866  1.1  augustss 	    } else {
   1867  1.1  augustss 		/* preserve button states */
   1868  1.1  augustss 		act->button |= act->obutton & MOUSE_EXTBUTTONS;
   1869  1.1  augustss 	    }
   1870  1.1  augustss 	    break;
   1871  1.1  augustss 	case MOUSE_MODEL_GLIDEPOINT:
   1872  1.1  augustss 	    /* `tapping' action */
   1873  1.1  augustss 	    act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
   1874  1.1  augustss 	    break;
   1875  1.1  augustss 	case MOUSE_MODEL_NETSCROLL:
   1876  1.1  augustss 	    /* three addtional bytes encode buttons and wheel events */
   1877  1.1  augustss 	    act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN)
   1878  1.1  augustss 		? MOUSE_BUTTON4DOWN : 0;
   1879  1.1  augustss 	    act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN)
   1880  1.1  augustss 		? MOUSE_BUTTON5DOWN : 0;
   1881  1.1  augustss 	    act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4];
   1882  1.1  augustss 	    break;
   1883  1.1  augustss 	case MOUSE_MODEL_THINK:
   1884  1.1  augustss 	    /* the fourth button state in the first byte */
   1885  1.1  augustss 	    act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
   1886  1.1  augustss 	    break;
   1887  1.1  augustss 	case MOUSE_MODEL_VERSAPAD:
   1888  1.1  augustss 	    act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS];
   1889  1.1  augustss 	    act->button |=
   1890  1.1  augustss 		(pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
   1891  1.1  augustss 	    act->dx = act->dy = 0;
   1892  1.1  augustss 	    if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) {
   1893  1.1  augustss 		on = FALSE;
   1894  1.1  augustss 		break;
   1895  1.1  augustss 	    }
   1896  1.1  augustss 	    x = ((pBuf[4] << 8) & 0xf00) | pBuf[1];
   1897  1.1  augustss 	    if (x & 0x800)
   1898  1.1  augustss 		x -= 0x1000;
   1899  1.1  augustss 	    y = ((pBuf[4] << 4) & 0xf00) | pBuf[2];
   1900  1.1  augustss 	    if (y & 0x800)
   1901  1.1  augustss 		y -= 0x1000;
   1902  1.1  augustss 	    if (on) {
   1903  1.1  augustss 		act->dx = prev_x - x;
   1904  1.1  augustss 		act->dy = prev_y - y;
   1905  1.1  augustss 	    } else {
   1906  1.1  augustss 		on = TRUE;
   1907  1.1  augustss 	    }
   1908  1.1  augustss 	    prev_x = x;
   1909  1.1  augustss 	    prev_y = y;
   1910  1.1  augustss 	    break;
   1911  1.1  augustss 	case MOUSE_MODEL_4D:
   1912  1.1  augustss 	    act->dx = (pBuf[1] & 0x80) ?    pBuf[1] - 256  :  pBuf[1];
   1913  1.1  augustss 	    act->dy = (pBuf[2] & 0x80) ?  -(pBuf[2] - 256) : -pBuf[2];
   1914  1.1  augustss 	    switch (pBuf[0] & MOUSE_4D_WHEELBITS) {
   1915  1.1  augustss 	    case 0x10:
   1916  1.1  augustss 		act->dz = 1;
   1917  1.1  augustss 		break;
   1918  1.1  augustss 	    case 0x30:
   1919  1.1  augustss 		act->dz = -1;
   1920  1.1  augustss 		break;
   1921  1.1  augustss 	    case 0x40:	/* 2nd wheel rolling right XXX */
   1922  1.1  augustss 		act->dz = 2;
   1923  1.1  augustss 		break;
   1924  1.1  augustss 	    case 0xc0:	/* 2nd wheel rolling left XXX */
   1925  1.1  augustss 		act->dz = -2;
   1926  1.1  augustss 		break;
   1927  1.1  augustss 	    }
   1928  1.1  augustss 	    break;
   1929  1.1  augustss 	case MOUSE_MODEL_4DPLUS:
   1930  1.1  augustss 	    if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) {
   1931  1.1  augustss 		act->dx = act->dy = 0;
   1932  1.1  augustss 		if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN)
   1933  1.1  augustss 		    act->button |= MOUSE_BUTTON4DOWN;
   1934  1.1  augustss 		act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG)
   1935  1.1  augustss 			      ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07);
   1936  1.1  augustss 	    } else {
   1937  1.1  augustss 		/* preserve previous button states */
   1938  1.1  augustss 		act->button |= act->obutton & MOUSE_EXTBUTTONS;
   1939  1.1  augustss 	    }
   1940  1.1  augustss 	    break;
   1941  1.1  augustss 	case MOUSE_MODEL_GENERIC:
   1942  1.1  augustss 	default:
   1943  1.1  augustss 	    break;
   1944  1.1  augustss 	}
   1945  1.1  augustss 	break;
   1946  1.1  augustss 
   1947  1.1  augustss     case MOUSE_PROTO_SYSMOUSE:		/* sysmouse */
   1948  1.1  augustss 	act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
   1949  1.1  augustss 	act->dx =    (char)(pBuf[1]) + (char)(pBuf[3]);
   1950  1.1  augustss 	act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
   1951  1.1  augustss 	if (rodent.level == 1) {
   1952  1.1  augustss 	    act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1))/2;
   1953  1.1  augustss 	    act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
   1954  1.1  augustss 	}
   1955  1.1  augustss 	break;
   1956  1.1  augustss 
   1957  1.1  augustss     default:
   1958  1.1  augustss 	return 0;
   1959  1.1  augustss     }
   1960  1.1  augustss     /*
   1961  1.1  augustss      * We don't reset pBufP here yet, as there may be an additional data
   1962  1.1  augustss      * byte in some protocols. See above.
   1963  1.1  augustss      */
   1964  1.1  augustss 
   1965  1.1  augustss     /* has something changed? */
   1966  1.1  augustss     act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
   1967  1.1  augustss 	| (act->obutton ^ act->button);
   1968  1.1  augustss 
   1969  1.1  augustss     return act->flags;
   1970  1.1  augustss }
   1971  1.1  augustss 
   1972  1.1  augustss static int
   1973  1.1  augustss r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans)
   1974  1.1  augustss {
   1975  1.1  augustss     int changed;
   1976  1.1  augustss     int flags;
   1977  1.1  augustss 
   1978  1.1  augustss     a2->dx = a1->dx;
   1979  1.1  augustss     a2->dy = a1->dy;
   1980  1.1  augustss     a2->dz = a1->dz;
   1981  1.1  augustss     a2->obutton = a2->button;
   1982  1.1  augustss     a2->button = a1->button;
   1983  1.1  augustss     a2->flags = a1->flags;
   1984  1.1  augustss     changed = FALSE;
   1985  1.1  augustss 
   1986  1.1  augustss     if (rodent.flags & Emulate3Button) {
   1987  1.5   thorpej 	if (dbg > 2)
   1988  1.1  augustss 	    debug("state:%d, trans:%d -> state:%d",
   1989  1.1  augustss 		  mouse_button_state, trans,
   1990  1.1  augustss 		  states[mouse_button_state].s[trans]);
   1991  1.1  augustss 	/*
   1992  1.1  augustss 	 * Avoid re-ordering button and movement events. While a button
   1993  1.1  augustss 	 * event is deferred, throw away up to BUTTON2_MAXMOVE movement
   1994  1.1  augustss 	 * events to allow for mouse jitter. If more movement events
   1995  1.1  augustss 	 * occur, then complete the deferred button events immediately.
   1996  1.1  augustss 	 */
   1997  1.1  augustss 	if ((a2->dx != 0 || a2->dy != 0) &&
   1998  1.1  augustss 	    S_DELAYED(states[mouse_button_state].s[trans])) {
   1999  1.1  augustss 		if (++mouse_move_delayed > BUTTON2_MAXMOVE) {
   2000  1.1  augustss 			mouse_move_delayed = 0;
   2001  1.1  augustss 			mouse_button_state =
   2002  1.1  augustss 			    states[mouse_button_state].s[A_TIMEOUT];
   2003  1.1  augustss 			changed = TRUE;
   2004  1.1  augustss 		} else
   2005  1.1  augustss 			a2->dx = a2->dy = 0;
   2006  1.1  augustss 	} else
   2007  1.1  augustss 		mouse_move_delayed = 0;
   2008  1.1  augustss 	if (mouse_button_state != states[mouse_button_state].s[trans])
   2009  1.1  augustss 		changed = TRUE;
   2010  1.1  augustss 	if (changed)
   2011  1.1  augustss 		gettimeofday(&mouse_button_state_tv, NULL);
   2012  1.1  augustss 	mouse_button_state = states[mouse_button_state].s[trans];
   2013  1.1  augustss 	a2->button &=
   2014  1.1  augustss 	    ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN);
   2015  1.1  augustss 	a2->button &= states[mouse_button_state].mask;
   2016  1.1  augustss 	a2->button |= states[mouse_button_state].buttons;
   2017  1.1  augustss 	flags = a2->flags & MOUSE_POSCHANGED;
   2018  1.1  augustss 	flags |= a2->obutton ^ a2->button;
   2019  1.1  augustss 	if (flags & MOUSE_BUTTON2DOWN) {
   2020  1.1  augustss 	    a2->flags = flags & MOUSE_BUTTON2DOWN;
   2021  1.1  augustss 	    r_timestamp(a2);
   2022  1.1  augustss 	}
   2023  1.1  augustss 	a2->flags = flags;
   2024  1.1  augustss     }
   2025  1.1  augustss     return changed;
   2026  1.1  augustss }
   2027  1.1  augustss 
   2028  1.1  augustss /* phisical to logical button mapping */
   2029  1.1  augustss static int p2l[MOUSE_MAXBUTTON] = {
   2030  1.1  augustss     MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
   2031  1.1  augustss     MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
   2032  1.1  augustss     0x00000100,        0x00000200,        0x00000400,        0x00000800,
   2033  1.1  augustss     0x00001000,        0x00002000,        0x00004000,        0x00008000,
   2034  1.1  augustss     0x00010000,        0x00020000,        0x00040000,        0x00080000,
   2035  1.1  augustss     0x00100000,        0x00200000,        0x00400000,        0x00800000,
   2036  1.1  augustss     0x01000000,        0x02000000,        0x04000000,        0x08000000,
   2037  1.1  augustss     0x10000000,        0x20000000,        0x40000000,
   2038  1.1  augustss };
   2039  1.1  augustss 
   2040  1.1  augustss static char *
   2041  1.1  augustss skipspace(char *s)
   2042  1.1  augustss {
   2043  1.1  augustss     while(isspace(*s))
   2044  1.1  augustss 	++s;
   2045  1.1  augustss     return s;
   2046  1.1  augustss }
   2047  1.1  augustss 
   2048  1.1  augustss static int
   2049  1.1  augustss r_installmap(char *arg)
   2050  1.1  augustss {
   2051  1.1  augustss     int pbutton;
   2052  1.1  augustss     int lbutton;
   2053  1.1  augustss     char *s;
   2054  1.1  augustss 
   2055  1.1  augustss     while (*arg) {
   2056  1.1  augustss 	arg = skipspace(arg);
   2057  1.1  augustss 	s = arg;
   2058  1.1  augustss 	while (isdigit(*arg))
   2059  1.1  augustss 	    ++arg;
   2060  1.1  augustss 	arg = skipspace(arg);
   2061  1.1  augustss 	if ((arg <= s) || (*arg != '='))
   2062  1.1  augustss 	    return FALSE;
   2063  1.1  augustss 	lbutton = atoi(s);
   2064  1.1  augustss 
   2065  1.1  augustss 	arg = skipspace(++arg);
   2066  1.1  augustss 	s = arg;
   2067  1.1  augustss 	while (isdigit(*arg))
   2068  1.1  augustss 	    ++arg;
   2069  1.1  augustss 	if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
   2070  1.1  augustss 	    return FALSE;
   2071  1.1  augustss 	pbutton = atoi(s);
   2072  1.1  augustss 
   2073  1.1  augustss 	if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
   2074  1.1  augustss 	    return FALSE;
   2075  1.1  augustss 	if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
   2076  1.1  augustss 	    return FALSE;
   2077  1.1  augustss 	p2l[pbutton - 1] = 1 << (lbutton - 1);
   2078  1.1  augustss 	mstate[lbutton - 1] = &bstate[pbutton - 1];
   2079  1.1  augustss     }
   2080  1.1  augustss 
   2081  1.1  augustss     return TRUE;
   2082  1.1  augustss }
   2083  1.1  augustss 
   2084  1.1  augustss static void
   2085  1.1  augustss r_map(mousestatus_t *act1, mousestatus_t *act2)
   2086  1.1  augustss {
   2087  1.1  augustss     register int pb;
   2088  1.1  augustss     register int pbuttons;
   2089  1.1  augustss     int lbuttons;
   2090  1.1  augustss 
   2091  1.1  augustss     pbuttons = act1->button;
   2092  1.1  augustss     lbuttons = 0;
   2093  1.1  augustss 
   2094  1.1  augustss     act2->obutton = act2->button;
   2095  1.1  augustss     if (pbuttons & rodent.wmode) {
   2096  1.1  augustss 	pbuttons &= ~rodent.wmode;
   2097  1.1  augustss 	act1->dz = act1->dy;
   2098  1.1  augustss 	act1->dx = 0;
   2099  1.1  augustss 	act1->dy = 0;
   2100  1.1  augustss     }
   2101  1.1  augustss     act2->dx = act1->dx;
   2102  1.1  augustss     act2->dy = act1->dy;
   2103  1.1  augustss     act2->dz = act1->dz;
   2104  1.1  augustss 
   2105  1.1  augustss     switch (rodent.zmap[0]) {
   2106  1.1  augustss     case 0:	/* do nothing */
   2107  1.1  augustss 	break;
   2108  1.1  augustss     case MOUSE_XAXIS:
   2109  1.1  augustss 	if (act1->dz != 0) {
   2110  1.1  augustss 	    act2->dx = act1->dz;
   2111  1.1  augustss 	    act2->dz = 0;
   2112  1.1  augustss 	}
   2113  1.1  augustss 	break;
   2114  1.1  augustss     case MOUSE_YAXIS:
   2115  1.1  augustss 	if (act1->dz != 0) {
   2116  1.1  augustss 	    act2->dy = act1->dz;
   2117  1.1  augustss 	    act2->dz = 0;
   2118  1.1  augustss 	}
   2119  1.1  augustss 	break;
   2120  1.1  augustss     default:	/* buttons */
   2121  1.1  augustss 	pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1]
   2122  1.1  augustss 		    | rodent.zmap[2] | rodent.zmap[3]);
   2123  1.1  augustss 	if ((act1->dz < -1) && rodent.zmap[2]) {
   2124  1.1  augustss 	    pbuttons |= rodent.zmap[2];
   2125  1.1  augustss 	    zstate[2].count = 1;
   2126  1.1  augustss 	} else if (act1->dz < 0) {
   2127  1.1  augustss 	    pbuttons |= rodent.zmap[0];
   2128  1.1  augustss 	    zstate[0].count = 1;
   2129  1.1  augustss 	} else if ((act1->dz > 1) && rodent.zmap[3]) {
   2130  1.1  augustss 	    pbuttons |= rodent.zmap[3];
   2131  1.1  augustss 	    zstate[3].count = 1;
   2132  1.1  augustss 	} else if (act1->dz > 0) {
   2133  1.1  augustss 	    pbuttons |= rodent.zmap[1];
   2134  1.1  augustss 	    zstate[1].count = 1;
   2135  1.1  augustss 	}
   2136  1.1  augustss 	act2->dz = 0;
   2137  1.1  augustss 	break;
   2138  1.1  augustss     }
   2139  1.1  augustss 
   2140  1.1  augustss     for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
   2141  1.1  augustss 	lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
   2142  1.1  augustss 	pbuttons >>= 1;
   2143  1.1  augustss     }
   2144  1.1  augustss     act2->button = lbuttons;
   2145  1.1  augustss 
   2146  1.1  augustss     act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
   2147  1.1  augustss 	| (act2->obutton ^ act2->button);
   2148  1.1  augustss }
   2149  1.1  augustss 
   2150  1.1  augustss static void
   2151  1.1  augustss r_timestamp(mousestatus_t *act)
   2152  1.1  augustss {
   2153  1.1  augustss     struct timeval tv;
   2154  1.1  augustss     struct timeval tv1;
   2155  1.1  augustss     struct timeval tv2;
   2156  1.1  augustss     struct timeval tv3;
   2157  1.1  augustss     int button;
   2158  1.1  augustss     int mask;
   2159  1.1  augustss     int i;
   2160  1.1  augustss 
   2161  1.1  augustss     mask = act->flags & MOUSE_BUTTONS;
   2162  1.1  augustss #if 0
   2163  1.1  augustss     if (mask == 0)
   2164  1.1  augustss 	return;
   2165  1.1  augustss #endif
   2166  1.1  augustss 
   2167  1.1  augustss     gettimeofday(&tv1, NULL);
   2168  1.1  augustss 
   2169  1.1  augustss     /* double click threshold */
   2170  1.1  augustss     tv2.tv_sec = rodent.clickthreshold/1000;
   2171  1.1  augustss     tv2.tv_usec = (rodent.clickthreshold%1000)*1000;
   2172  1.1  augustss     timersub(&tv1, &tv2, &tv);
   2173  1.1  augustss     debug("tv:  %ld %ld", tv.tv_sec, tv.tv_usec);
   2174  1.1  augustss 
   2175  1.1  augustss     /* 3 button emulation timeout */
   2176  1.1  augustss     tv2.tv_sec = rodent.button2timeout/1000;
   2177  1.1  augustss     tv2.tv_usec = (rodent.button2timeout%1000)*1000;
   2178  1.1  augustss     timersub(&tv1, &tv2, &tv3);
   2179  1.1  augustss 
   2180  1.1  augustss     button = MOUSE_BUTTON1DOWN;
   2181  1.1  augustss     for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
   2182  1.1  augustss         if (mask & 1) {
   2183  1.1  augustss             if (act->button & button) {
   2184  1.1  augustss                 /* the button is down */
   2185  1.1  augustss     		debug("  :  %ld %ld",
   2186  1.1  augustss 		    bstate[i].tv.tv_sec, bstate[i].tv.tv_usec);
   2187  1.1  augustss 		if (timercmp(&tv, &bstate[i].tv, >)) {
   2188  1.1  augustss                     bstate[i].count = 1;
   2189  1.1  augustss                 } else {
   2190  1.1  augustss                     ++bstate[i].count;
   2191  1.1  augustss                 }
   2192  1.1  augustss 		bstate[i].tv = tv1;
   2193  1.1  augustss             } else {
   2194  1.1  augustss                 /* the button is up */
   2195  1.1  augustss                 bstate[i].tv = tv1;
   2196  1.1  augustss             }
   2197  1.1  augustss         } else {
   2198  1.1  augustss 	    if (act->button & button) {
   2199  1.1  augustss 		/* the button has been down */
   2200  1.1  augustss 		if (timercmp(&tv3, &bstate[i].tv, >)) {
   2201  1.1  augustss 		    bstate[i].count = 1;
   2202  1.1  augustss 		    bstate[i].tv = tv1;
   2203  1.1  augustss 		    act->flags |= button;
   2204  1.1  augustss 		    debug("button %d timeout", i + 1);
   2205  1.1  augustss 		}
   2206  1.1  augustss 	    } else {
   2207  1.1  augustss 		/* the button has been up */
   2208  1.1  augustss 	    }
   2209  1.1  augustss 	}
   2210  1.1  augustss 	button <<= 1;
   2211  1.1  augustss 	mask >>= 1;
   2212  1.1  augustss     }
   2213  1.1  augustss }
   2214  1.1  augustss 
   2215  1.1  augustss static int
   2216  1.1  augustss r_timeout(void)
   2217  1.1  augustss {
   2218  1.1  augustss     struct timeval tv;
   2219  1.1  augustss     struct timeval tv1;
   2220  1.1  augustss     struct timeval tv2;
   2221  1.1  augustss 
   2222  1.1  augustss     if (states[mouse_button_state].timeout)
   2223  1.1  augustss 	return TRUE;
   2224  1.1  augustss     gettimeofday(&tv1, NULL);
   2225  1.1  augustss     tv2.tv_sec = rodent.button2timeout/1000;
   2226  1.1  augustss     tv2.tv_usec = (rodent.button2timeout%1000)*1000;
   2227  1.1  augustss     timersub(&tv1, &tv2, &tv);
   2228  1.1  augustss     return timercmp(&tv, &mouse_button_state_tv, >);
   2229  1.1  augustss }
   2230  1.1  augustss 
   2231  1.1  augustss /* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
   2232  1.1  augustss /* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
   2233  1.1  augustss /*
   2234  1.1  augustss  * Copyright 1993 by David Dawes <dawes (at) physics.su.oz.au>
   2235  1.1  augustss  *
   2236  1.1  augustss  * Permission to use, copy, modify, distribute, and sell this software and its
   2237  1.1  augustss  * documentation for any purpose is hereby granted without fee, provided that
   2238  1.1  augustss  * the above copyright notice appear in all copies and that both that
   2239  1.1  augustss  * copyright notice and this permission notice appear in supporting
   2240  1.1  augustss  * documentation, and that the name of David Dawes
   2241  1.1  augustss  * not be used in advertising or publicity pertaining to distribution of
   2242  1.1  augustss  * the software without specific, written prior permission.
   2243  1.1  augustss  * David Dawes makes no representations about the suitability of this
   2244  1.1  augustss  * software for any purpose.  It is provided "as is" without express or
   2245  1.1  augustss  * implied warranty.
   2246  1.1  augustss  *
   2247  1.1  augustss  * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
   2248  1.1  augustss  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
   2249  1.1  augustss  * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
   2250  1.1  augustss  * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
   2251  1.1  augustss  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
   2252  1.1  augustss  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   2253  1.1  augustss  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   2254  1.1  augustss  *
   2255  1.1  augustss  */
   2256  1.1  augustss 
   2257  1.1  augustss 
   2258  1.1  augustss static void
   2259  1.1  augustss setmousespeed(int old, int new, unsigned cflag)
   2260  1.1  augustss {
   2261  1.1  augustss 	struct termios tty;
   2262  1.1  augustss 	char *c;
   2263  1.1  augustss 
   2264  1.1  augustss 	if (tcgetattr(rodent.mfd, &tty) < 0)
   2265  1.1  augustss 	{
   2266  1.4   thorpej 		logwarn("unable to get status of mouse fd");
   2267  1.1  augustss 		return;
   2268  1.1  augustss 	}
   2269  1.1  augustss 
   2270  1.1  augustss 	tty.c_iflag = IGNBRK | IGNPAR;
   2271  1.1  augustss 	tty.c_oflag = 0;
   2272  1.1  augustss 	tty.c_lflag = 0;
   2273  1.1  augustss 	tty.c_cflag = (tcflag_t)cflag;
   2274  1.1  augustss 	tty.c_cc[VTIME] = 0;
   2275  1.1  augustss 	tty.c_cc[VMIN] = 1;
   2276  1.1  augustss 
   2277  1.1  augustss 	switch (old)
   2278  1.1  augustss 	{
   2279  1.1  augustss 	case 9600:
   2280  1.1  augustss 		cfsetispeed(&tty, B9600);
   2281  1.1  augustss 		cfsetospeed(&tty, B9600);
   2282  1.1  augustss 		break;
   2283  1.1  augustss 	case 4800:
   2284  1.1  augustss 		cfsetispeed(&tty, B4800);
   2285  1.1  augustss 		cfsetospeed(&tty, B4800);
   2286  1.1  augustss 		break;
   2287  1.1  augustss 	case 2400:
   2288  1.1  augustss 		cfsetispeed(&tty, B2400);
   2289  1.1  augustss 		cfsetospeed(&tty, B2400);
   2290  1.1  augustss 		break;
   2291  1.1  augustss 	case 1200:
   2292  1.1  augustss 	default:
   2293  1.1  augustss 		cfsetispeed(&tty, B1200);
   2294  1.1  augustss 		cfsetospeed(&tty, B1200);
   2295  1.1  augustss 	}
   2296  1.1  augustss 
   2297  1.1  augustss 	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
   2298  1.1  augustss 	{
   2299  1.4   thorpej 		logwarn("unable to set status of mouse fd");
   2300  1.1  augustss 		return;
   2301  1.1  augustss 	}
   2302  1.1  augustss 
   2303  1.1  augustss 	switch (new)
   2304  1.1  augustss 	{
   2305  1.1  augustss 	case 9600:
   2306  1.1  augustss 		c = "*q";
   2307  1.1  augustss 		cfsetispeed(&tty, B9600);
   2308  1.1  augustss 		cfsetospeed(&tty, B9600);
   2309  1.1  augustss 		break;
   2310  1.1  augustss 	case 4800:
   2311  1.1  augustss 		c = "*p";
   2312  1.1  augustss 		cfsetispeed(&tty, B4800);
   2313  1.1  augustss 		cfsetospeed(&tty, B4800);
   2314  1.1  augustss 		break;
   2315  1.1  augustss 	case 2400:
   2316  1.1  augustss 		c = "*o";
   2317  1.1  augustss 		cfsetispeed(&tty, B2400);
   2318  1.1  augustss 		cfsetospeed(&tty, B2400);
   2319  1.1  augustss 		break;
   2320  1.1  augustss 	case 1200:
   2321  1.1  augustss 	default:
   2322  1.1  augustss 		c = "*n";
   2323  1.1  augustss 		cfsetispeed(&tty, B1200);
   2324  1.1  augustss 		cfsetospeed(&tty, B1200);
   2325  1.1  augustss 	}
   2326  1.1  augustss 
   2327  1.1  augustss 	if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN
   2328  1.1  augustss 	    || rodent.rtype == MOUSE_PROTO_LOGI)
   2329  1.1  augustss 	{
   2330  1.1  augustss 		if (write(rodent.mfd, c, 2) != 2)
   2331  1.1  augustss 		{
   2332  1.4   thorpej 			logwarn("unable to write to mouse fd");
   2333  1.1  augustss 			return;
   2334  1.1  augustss 		}
   2335  1.1  augustss 	}
   2336  1.1  augustss 	usleep(100000);
   2337  1.1  augustss 
   2338  1.1  augustss 	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
   2339  1.4   thorpej 		logwarn("unable to set status of mouse fd");
   2340  1.1  augustss }
   2341  1.1  augustss 
   2342  1.1  augustss /*
   2343  1.1  augustss  * PnP COM device support
   2344  1.1  augustss  *
   2345  1.1  augustss  * It's a simplistic implementation, but it works :-)
   2346  1.1  augustss  * KY, 31/7/97.
   2347  1.1  augustss  */
   2348  1.1  augustss 
   2349  1.1  augustss /*
   2350  1.1  augustss  * Try to elicit a PnP ID as described in
   2351  1.1  augustss  * Microsoft, Hayes: "Plug and Play External COM Device Specification,
   2352  1.1  augustss  * rev 1.00", 1995.
   2353  1.1  augustss  *
   2354  1.1  augustss  * The routine does not fully implement the COM Enumerator as par Section
   2355  1.1  augustss  * 2.1 of the document.  In particular, we don't have idle state in which
   2356  1.1  augustss  * the driver software monitors the com port for dynamic connection or
   2357  1.1  augustss  * removal of a device at the port, because `moused' simply quits if no
   2358  1.1  augustss  * device is found.
   2359  1.1  augustss  *
   2360  1.1  augustss  * In addition, as PnP COM device enumeration procedure slightly has
   2361  1.1  augustss  * changed since its first publication, devices which follow earlier
   2362  1.1  augustss  * revisions of the above spec. may fail to respond if the rev 1.0
   2363  1.1  augustss  * procedure is used. XXX
   2364  1.1  augustss  */
   2365  1.1  augustss static int
   2366  1.1  augustss pnpwakeup1(void)
   2367  1.1  augustss {
   2368  1.1  augustss     struct timeval timeout;
   2369  1.1  augustss     fd_set fds;
   2370  1.1  augustss     int i;
   2371  1.1  augustss 
   2372  1.1  augustss     /*
   2373  1.1  augustss      * This is the procedure described in rev 1.0 of PnP COM device spec.
   2374  1.1  augustss      * Unfortunately, some devices which comform to earlier revisions of
   2375  1.1  augustss      * the spec gets confused and do not return the ID string...
   2376  1.1  augustss      */
   2377  1.1  augustss     debug("PnP COM device rev 1.0 probe...");
   2378  1.1  augustss 
   2379  1.1  augustss     /* port initialization (2.1.2) */
   2380  1.1  augustss     ioctl(rodent.mfd, TIOCMGET, &i);
   2381  1.1  augustss     i |= TIOCM_DTR;		/* DTR = 1 */
   2382  1.1  augustss     i &= ~TIOCM_RTS;		/* RTS = 0 */
   2383  1.1  augustss     ioctl(rodent.mfd, TIOCMSET, &i);
   2384  1.1  augustss     usleep(240000);
   2385  1.1  augustss 
   2386  1.1  augustss     /*
   2387  1.1  augustss      * The PnP COM device spec. dictates that the mouse must set DSR
   2388  1.1  augustss      * in response to DTR (by hardware or by software) and that if DSR is
   2389  1.1  augustss      * not asserted, the host computer should think that there is no device
   2390  1.1  augustss      * at this serial port.  But some mice just don't do that...
   2391  1.1  augustss      */
   2392  1.1  augustss     ioctl(rodent.mfd, TIOCMGET, &i);
   2393  1.1  augustss     debug("modem status 0%o", i);
   2394  1.1  augustss     if ((i & TIOCM_DSR) == 0)
   2395  1.1  augustss 	return FALSE;
   2396  1.1  augustss 
   2397  1.1  augustss     /* port setup, 1st phase (2.1.3) */
   2398  1.1  augustss     setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
   2399  1.1  augustss     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
   2400  1.1  augustss     ioctl(rodent.mfd, TIOCMBIC, &i);
   2401  1.1  augustss     usleep(240000);
   2402  1.1  augustss     i = TIOCM_DTR;		/* DTR = 1, RTS = 0 */
   2403  1.1  augustss     ioctl(rodent.mfd, TIOCMBIS, &i);
   2404  1.1  augustss     usleep(240000);
   2405  1.1  augustss 
   2406  1.1  augustss     /* wait for response, 1st phase (2.1.4) */
   2407  1.1  augustss     i = FREAD;
   2408  1.1  augustss     ioctl(rodent.mfd, TIOCFLUSH, &i);
   2409  1.1  augustss     i = TIOCM_RTS;		/* DTR = 1, RTS = 1 */
   2410  1.1  augustss     ioctl(rodent.mfd, TIOCMBIS, &i);
   2411  1.1  augustss 
   2412  1.1  augustss     /* try to read something */
   2413  1.1  augustss     FD_ZERO(&fds);
   2414  1.1  augustss     FD_SET(rodent.mfd, &fds);
   2415  1.1  augustss     timeout.tv_sec = 0;
   2416  1.1  augustss     timeout.tv_usec = 240000;
   2417  1.1  augustss     if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
   2418  1.1  augustss 	debug("pnpwakeup1(): valid response in first phase.");
   2419  1.1  augustss 	return TRUE;
   2420  1.1  augustss     }
   2421  1.1  augustss 
   2422  1.1  augustss     /* port setup, 2nd phase (2.1.5) */
   2423  1.1  augustss     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
   2424  1.1  augustss     ioctl(rodent.mfd, TIOCMBIC, &i);
   2425  1.1  augustss     usleep(240000);
   2426  1.1  augustss 
   2427  1.1  augustss     /* wait for respose, 2nd phase (2.1.6) */
   2428  1.1  augustss     i = FREAD;
   2429  1.1  augustss     ioctl(rodent.mfd, TIOCFLUSH, &i);
   2430  1.1  augustss     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
   2431  1.1  augustss     ioctl(rodent.mfd, TIOCMBIS, &i);
   2432  1.1  augustss 
   2433  1.1  augustss     /* try to read something */
   2434  1.1  augustss     FD_ZERO(&fds);
   2435  1.1  augustss     FD_SET(rodent.mfd, &fds);
   2436  1.1  augustss     timeout.tv_sec = 0;
   2437  1.1  augustss     timeout.tv_usec = 240000;
   2438  1.1  augustss     if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
   2439  1.1  augustss 	debug("pnpwakeup1(): valid response in second phase.");
   2440  1.1  augustss 	return TRUE;
   2441  1.1  augustss     }
   2442  1.1  augustss 
   2443  1.1  augustss     return FALSE;
   2444  1.1  augustss }
   2445  1.1  augustss 
   2446  1.1  augustss static int
   2447  1.1  augustss pnpwakeup2(void)
   2448  1.1  augustss {
   2449  1.1  augustss     struct timeval timeout;
   2450  1.1  augustss     fd_set fds;
   2451  1.1  augustss     int i;
   2452  1.1  augustss 
   2453  1.1  augustss     /*
   2454  1.1  augustss      * This is a simplified procedure; it simply toggles RTS.
   2455  1.1  augustss      */
   2456  1.1  augustss     debug("alternate probe...");
   2457  1.1  augustss 
   2458  1.1  augustss     ioctl(rodent.mfd, TIOCMGET, &i);
   2459  1.1  augustss     i |= TIOCM_DTR;		/* DTR = 1 */
   2460  1.1  augustss     i &= ~TIOCM_RTS;		/* RTS = 0 */
   2461  1.1  augustss     ioctl(rodent.mfd, TIOCMSET, &i);
   2462  1.1  augustss     usleep(240000);
   2463  1.1  augustss 
   2464  1.1  augustss     setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
   2465  1.1  augustss 
   2466  1.1  augustss     /* wait for respose */
   2467  1.1  augustss     i = FREAD;
   2468  1.1  augustss     ioctl(rodent.mfd, TIOCFLUSH, &i);
   2469  1.1  augustss     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
   2470  1.1  augustss     ioctl(rodent.mfd, TIOCMBIS, &i);
   2471  1.1  augustss 
   2472  1.1  augustss     /* try to read something */
   2473  1.1  augustss     FD_ZERO(&fds);
   2474  1.1  augustss     FD_SET(rodent.mfd, &fds);
   2475  1.1  augustss     timeout.tv_sec = 0;
   2476  1.1  augustss     timeout.tv_usec = 240000;
   2477  1.1  augustss     if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
   2478  1.1  augustss 	debug("pnpwakeup2(): valid response.");
   2479  1.1  augustss 	return TRUE;
   2480  1.1  augustss     }
   2481  1.1  augustss 
   2482  1.1  augustss     return FALSE;
   2483  1.1  augustss }
   2484  1.1  augustss 
   2485  1.1  augustss static int
   2486  1.1  augustss pnpgets(char *buf)
   2487  1.1  augustss {
   2488  1.1  augustss     struct timeval timeout;
   2489  1.1  augustss     fd_set fds;
   2490  1.1  augustss     int begin;
   2491  1.1  augustss     int i;
   2492  1.1  augustss     char c;
   2493  1.1  augustss 
   2494  1.1  augustss     if (!pnpwakeup1() && !pnpwakeup2()) {
   2495  1.1  augustss 	/*
   2496  1.1  augustss 	 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
   2497  1.1  augustss 	 * in idle state.  But, `moused' shall set DTR = RTS = 1 and proceed,
   2498  1.1  augustss 	 * assuming there is something at the port even if it didn't
   2499  1.1  augustss 	 * respond to the PnP enumeration procedure.
   2500  1.1  augustss 	 */
   2501  1.1  augustss 	i = TIOCM_DTR | TIOCM_RTS;		/* DTR = 1, RTS = 1 */
   2502  1.1  augustss 	ioctl(rodent.mfd, TIOCMBIS, &i);
   2503  1.1  augustss 	return 0;
   2504  1.1  augustss     }
   2505  1.1  augustss 
   2506  1.1  augustss     /* collect PnP COM device ID (2.1.7) */
   2507  1.1  augustss     begin = -1;
   2508  1.1  augustss     i = 0;
   2509  1.1  augustss     usleep(240000);	/* the mouse must send `Begin ID' within 200msec */
   2510  1.1  augustss     while (read(rodent.mfd, &c, 1) == 1) {
   2511  1.1  augustss 	/* we may see "M", or "M3..." before `Begin ID' */
   2512  1.1  augustss 	buf[i++] = c;
   2513  1.1  augustss         if ((c == 0x08) || (c == 0x28)) {	/* Begin ID */
   2514  1.1  augustss 	    debug("begin-id %02x", c);
   2515  1.1  augustss 	    begin = i - 1;
   2516  1.1  augustss 	    break;
   2517  1.1  augustss         }
   2518  1.1  augustss         debug("%c %02x", c, c);
   2519  1.1  augustss 	if (i >= 256)
   2520  1.1  augustss 	    break;
   2521  1.1  augustss     }
   2522  1.1  augustss     if (begin < 0) {
   2523  1.1  augustss 	/* we haven't seen `Begin ID' in time... */
   2524  1.1  augustss 	goto connect_idle;
   2525  1.1  augustss     }
   2526  1.1  augustss 
   2527  1.1  augustss     ++c;			/* make it `End ID' */
   2528  1.1  augustss     for (;;) {
   2529  1.1  augustss         FD_ZERO(&fds);
   2530  1.1  augustss         FD_SET(rodent.mfd, &fds);
   2531  1.1  augustss         timeout.tv_sec = 0;
   2532  1.1  augustss         timeout.tv_usec = 240000;
   2533  1.1  augustss         if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
   2534  1.1  augustss 	    break;
   2535  1.1  augustss 
   2536  1.1  augustss 	read(rodent.mfd, &buf[i], 1);
   2537  1.1  augustss         if (buf[i++] == c)	/* End ID */
   2538  1.1  augustss 	    break;
   2539  1.1  augustss 	if (i >= 256)
   2540  1.1  augustss 	    break;
   2541  1.1  augustss     }
   2542  1.1  augustss     if (begin > 0) {
   2543  1.1  augustss 	i -= begin;
   2544  1.1  augustss 	bcopy(&buf[begin], &buf[0], i);
   2545  1.1  augustss     }
   2546  1.1  augustss     /* string may not be human readable... */
   2547  1.1  augustss     debug("len:%d, '%-*.*s'", i, i, i, buf);
   2548  1.1  augustss 
   2549  1.1  augustss     if (buf[i - 1] == c)
   2550  1.1  augustss 	return i;		/* a valid PnP string */
   2551  1.1  augustss 
   2552  1.1  augustss     /*
   2553  1.1  augustss      * According to PnP spec, we should set DTR = 1 and RTS = 0 while
   2554  1.1  augustss      * in idle state.  But, `moused' shall leave the modem control lines
   2555  1.1  augustss      * as they are. See above.
   2556  1.1  augustss      */
   2557  1.1  augustss connect_idle:
   2558  1.1  augustss 
   2559  1.1  augustss     /* we may still have something in the buffer */
   2560  1.1  augustss     return ((i > 0) ? i : 0);
   2561  1.1  augustss }
   2562  1.1  augustss 
   2563  1.1  augustss static int
   2564  1.1  augustss pnpparse(pnpid_t *id, char *buf, int len)
   2565  1.1  augustss {
   2566  1.1  augustss     char s[3];
   2567  1.1  augustss     int offset;
   2568  1.1  augustss     int sum = 0;
   2569  1.1  augustss     int i, j;
   2570  1.1  augustss 
   2571  1.1  augustss     id->revision = 0;
   2572  1.1  augustss     id->eisaid = NULL;
   2573  1.1  augustss     id->serial = NULL;
   2574  1.1  augustss     id->class = NULL;
   2575  1.1  augustss     id->compat = NULL;
   2576  1.1  augustss     id->description = NULL;
   2577  1.1  augustss     id->neisaid = 0;
   2578  1.1  augustss     id->nserial = 0;
   2579  1.1  augustss     id->nclass = 0;
   2580  1.1  augustss     id->ncompat = 0;
   2581  1.1  augustss     id->ndescription = 0;
   2582  1.1  augustss 
   2583  1.1  augustss     if ((buf[0] != 0x28) && (buf[0] != 0x08)) {
   2584  1.1  augustss 	/* non-PnP mice */
   2585  1.1  augustss 	switch(buf[0]) {
   2586  1.1  augustss 	default:
   2587  1.1  augustss 	    return FALSE;
   2588  1.1  augustss 	case 'M': /* Microsoft */
   2589  1.1  augustss 	    id->eisaid = "PNP0F01";
   2590  1.1  augustss 	    break;
   2591  1.1  augustss 	case 'H': /* MouseSystems */
   2592  1.1  augustss 	    id->eisaid = "PNP0F04";
   2593  1.1  augustss 	    break;
   2594  1.1  augustss 	}
   2595  1.1  augustss 	id->neisaid = strlen(id->eisaid);
   2596  1.1  augustss 	id->class = "MOUSE";
   2597  1.1  augustss 	id->nclass = strlen(id->class);
   2598  1.1  augustss 	debug("non-PnP mouse '%c'", buf[0]);
   2599  1.1  augustss 	return TRUE;
   2600  1.1  augustss     }
   2601  1.1  augustss 
   2602  1.1  augustss     /* PnP mice */
   2603  1.1  augustss     offset = 0x28 - buf[0];
   2604  1.1  augustss 
   2605  1.1  augustss     /* calculate checksum */
   2606  1.1  augustss     for (i = 0; i < len - 3; ++i) {
   2607  1.1  augustss 	sum += buf[i];
   2608  1.1  augustss 	buf[i] += offset;
   2609  1.1  augustss     }
   2610  1.1  augustss     sum += buf[len - 1];
   2611  1.1  augustss     for (; i < len; ++i)
   2612  1.1  augustss 	buf[i] += offset;
   2613  1.1  augustss     debug("PnP ID string: '%*.*s'", len, len, buf);
   2614  1.1  augustss 
   2615  1.1  augustss     /* revision */
   2616  1.1  augustss     buf[1] -= offset;
   2617  1.1  augustss     buf[2] -= offset;
   2618  1.1  augustss     id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
   2619  1.1  augustss     debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100);
   2620  1.1  augustss 
   2621  1.1  augustss     /* EISA vender and product ID */
   2622  1.1  augustss     id->eisaid = &buf[3];
   2623  1.1  augustss     id->neisaid = 7;
   2624  1.1  augustss 
   2625  1.1  augustss     /* option strings */
   2626  1.1  augustss     i = 10;
   2627  1.1  augustss     if (buf[i] == '\\') {
   2628  1.1  augustss         /* device serial # */
   2629  1.1  augustss         for (j = ++i; i < len; ++i) {
   2630  1.1  augustss             if (buf[i] == '\\')
   2631  1.1  augustss 		break;
   2632  1.1  augustss         }
   2633  1.1  augustss 	if (i >= len)
   2634  1.1  augustss 	    i -= 3;
   2635  1.1  augustss 	if (i - j == 8) {
   2636  1.1  augustss             id->serial = &buf[j];
   2637  1.1  augustss             id->nserial = 8;
   2638  1.1  augustss 	}
   2639  1.1  augustss     }
   2640  1.1  augustss     if (buf[i] == '\\') {
   2641  1.1  augustss         /* PnP class */
   2642  1.1  augustss         for (j = ++i; i < len; ++i) {
   2643  1.1  augustss             if (buf[i] == '\\')
   2644  1.1  augustss 		break;
   2645  1.1  augustss         }
   2646  1.1  augustss 	if (i >= len)
   2647  1.1  augustss 	    i -= 3;
   2648  1.1  augustss 	if (i > j + 1) {
   2649  1.1  augustss             id->class = &buf[j];
   2650  1.1  augustss             id->nclass = i - j;
   2651  1.1  augustss         }
   2652  1.1  augustss     }
   2653  1.1  augustss     if (buf[i] == '\\') {
   2654  1.1  augustss 	/* compatible driver */
   2655  1.1  augustss         for (j = ++i; i < len; ++i) {
   2656  1.1  augustss             if (buf[i] == '\\')
   2657  1.1  augustss 		break;
   2658  1.1  augustss         }
   2659  1.1  augustss 	/*
   2660  1.1  augustss 	 * PnP COM spec prior to v0.96 allowed '*' in this field,
   2661  1.1  augustss 	 * it's not allowed now; just igore it.
   2662  1.1  augustss 	 */
   2663  1.1  augustss 	if (buf[j] == '*')
   2664  1.1  augustss 	    ++j;
   2665  1.1  augustss 	if (i >= len)
   2666  1.1  augustss 	    i -= 3;
   2667  1.1  augustss 	if (i > j + 1) {
   2668  1.1  augustss             id->compat = &buf[j];
   2669  1.1  augustss             id->ncompat = i - j;
   2670  1.1  augustss         }
   2671  1.1  augustss     }
   2672  1.1  augustss     if (buf[i] == '\\') {
   2673  1.1  augustss 	/* product description */
   2674  1.1  augustss         for (j = ++i; i < len; ++i) {
   2675  1.1  augustss             if (buf[i] == ';')
   2676  1.1  augustss 		break;
   2677  1.1  augustss         }
   2678  1.1  augustss 	if (i >= len)
   2679  1.1  augustss 	    i -= 3;
   2680  1.1  augustss 	if (i > j + 1) {
   2681  1.1  augustss             id->description = &buf[j];
   2682  1.1  augustss             id->ndescription = i - j;
   2683  1.1  augustss         }
   2684  1.1  augustss     }
   2685  1.1  augustss 
   2686  1.1  augustss     /* checksum exists if there are any optional fields */
   2687  1.1  augustss     if ((id->nserial > 0) || (id->nclass > 0)
   2688  1.1  augustss 	|| (id->ncompat > 0) || (id->ndescription > 0)) {
   2689  1.1  augustss         debug("PnP checksum: 0x%X", sum);
   2690  1.1  augustss         sprintf(s, "%02X", sum & 0x0ff);
   2691  1.1  augustss         if (strncmp(s, &buf[len - 3], 2) != 0) {
   2692  1.1  augustss #if 0
   2693  1.1  augustss             /*
   2694  1.1  augustss 	     * I found some mice do not comply with the PnP COM device
   2695  1.1  augustss 	     * spec regarding checksum... XXX
   2696  1.1  augustss 	     */
   2697  1.1  augustss             logwarnx("PnP checksum error", 0);
   2698  1.1  augustss 	    return FALSE;
   2699  1.1  augustss #endif
   2700  1.1  augustss         }
   2701  1.1  augustss     }
   2702  1.1  augustss 
   2703  1.1  augustss     return TRUE;
   2704  1.1  augustss }
   2705  1.1  augustss 
   2706  1.1  augustss static symtab_t *
   2707  1.1  augustss pnpproto(pnpid_t *id)
   2708  1.1  augustss {
   2709  1.1  augustss     symtab_t *t;
   2710  1.1  augustss     int i, j;
   2711  1.1  augustss 
   2712  1.1  augustss     if (id->nclass > 0)
   2713  1.1  augustss 	if ( strncmp(id->class, "MOUSE", id->nclass) != 0 &&
   2714  1.1  augustss 	     strncmp(id->class, "TABLET", id->nclass) != 0)
   2715  1.1  augustss 	    /* this is not a mouse! */
   2716  1.1  augustss 	    return NULL;
   2717  1.1  augustss 
   2718  1.1  augustss     if (id->neisaid > 0) {
   2719  1.1  augustss         t = gettoken(pnpprod, id->eisaid, id->neisaid);
   2720  1.1  augustss 	if (t->val != MOUSE_PROTO_UNKNOWN)
   2721  1.1  augustss             return t;
   2722  1.1  augustss     }
   2723  1.1  augustss 
   2724  1.1  augustss     /*
   2725  1.1  augustss      * The 'Compatible drivers' field may contain more than one
   2726  1.1  augustss      * ID separated by ','.
   2727  1.1  augustss      */
   2728  1.1  augustss     if (id->ncompat <= 0)
   2729  1.1  augustss 	return NULL;
   2730  1.1  augustss     for (i = 0; i < id->ncompat; ++i) {
   2731  1.1  augustss         for (j = i; id->compat[i] != ','; ++i)
   2732  1.1  augustss             if (i >= id->ncompat)
   2733  1.1  augustss 		break;
   2734  1.1  augustss         if (i > j) {
   2735  1.1  augustss             t = gettoken(pnpprod, id->compat + j, i - j);
   2736  1.1  augustss 	    if (t->val != MOUSE_PROTO_UNKNOWN)
   2737  1.1  augustss                 return t;
   2738  1.1  augustss 	}
   2739  1.1  augustss     }
   2740  1.1  augustss 
   2741  1.1  augustss     return NULL;
   2742  1.1  augustss }
   2743  1.1  augustss 
   2744  1.1  augustss /* name/val mapping */
   2745  1.1  augustss 
   2746  1.1  augustss static symtab_t *
   2747  1.1  augustss gettoken(symtab_t *tab, char *s, int len)
   2748  1.1  augustss {
   2749  1.1  augustss     int i;
   2750  1.1  augustss 
   2751  1.1  augustss     for (i = 0; tab[i].name != NULL; ++i) {
   2752  1.1  augustss 	if (strncmp(tab[i].name, s, len) == 0)
   2753  1.1  augustss 	    break;
   2754  1.1  augustss     }
   2755  1.1  augustss     return &tab[i];
   2756  1.1  augustss }
   2757  1.1  augustss 
   2758  1.1  augustss static char *
   2759  1.1  augustss gettokenname(symtab_t *tab, int val)
   2760  1.1  augustss {
   2761  1.1  augustss     int i;
   2762  1.1  augustss 
   2763  1.1  augustss     for (i = 0; tab[i].name != NULL; ++i) {
   2764  1.1  augustss 	if (tab[i].val == val)
   2765  1.1  augustss 	    return tab[i].name;
   2766  1.1  augustss     }
   2767  1.1  augustss     return NULL;
   2768  1.1  augustss }
   2769  1.1  augustss 
   2770  1.1  augustss 
   2771  1.1  augustss /*
   2772  1.1  augustss  * code to read from the Genius Kidspad tablet.
   2773  1.1  augustss 
   2774  1.1  augustss The tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005,
   2775  1.1  augustss and to pre-pnp probes (RTS toggle) with 'T' (tablet ?)
   2776  1.1  augustss 9600, 8 bit, parity odd.
   2777  1.1  augustss 
   2778  1.1  augustss The tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains
   2779  1.1  augustss the proximity, tip and button info:
   2780  1.1  augustss    (byte0 & 0x1)	true = tip pressed
   2781  1.1  augustss    (byte0 & 0x2)	true = button pressed
   2782  1.1  augustss    (byte0 & 0x40)	false = pen in proximity of tablet.
   2783  1.1  augustss 
   2784  1.1  augustss The next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid).
   2785  1.1  augustss 
   2786  1.1  augustss Only absolute coordinates are returned, so we use the following approach:
   2787  1.1  augustss we store the last coordinates sent when the pen went out of the tablet,
   2788  1.1  augustss 
   2789  1.1  augustss 
   2790  1.1  augustss  *
   2791  1.1  augustss  */
   2792  1.1  augustss 
   2793  1.1  augustss typedef enum {
   2794  1.1  augustss     S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP
   2795  1.1  augustss } k_status ;
   2796  1.1  augustss 
   2797  1.1  augustss static int
   2798  1.1  augustss kidspad(u_char rxc, mousestatus_t *act)
   2799  1.1  augustss {
   2800  1.1  augustss     static int buf[5];
   2801  1.1  augustss     static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1 ;
   2802  1.1  augustss     static k_status status = S_IDLE ;
   2803  1.1  augustss     static struct timeval old, now ;
   2804  1.1  augustss 
   2805  1.1  augustss     int x, y ;
   2806  1.1  augustss 
   2807  1.1  augustss     if (buflen > 0 && (rxc & 0x80) ) {
   2808  1.1  augustss 	fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc);
   2809  1.1  augustss 	buflen = 0 ;
   2810  1.1  augustss     }
   2811  1.1  augustss     if (buflen == 0 && (rxc & 0xb8) != 0xb8 ) {
   2812  1.1  augustss 	fprintf(stderr, "invalid code 0 0x%x\n", rxc);
   2813  1.1  augustss 	return 0 ; /* invalid code, no action */
   2814  1.1  augustss     }
   2815  1.1  augustss     buf[buflen++] = rxc ;
   2816  1.1  augustss     if (buflen < 5)
   2817  1.1  augustss 	return 0 ;
   2818  1.1  augustss 
   2819  1.1  augustss     buflen = 0 ; /* for next time... */
   2820  1.1  augustss 
   2821  1.1  augustss     x = buf[1]+128*(buf[2] - 7) ;
   2822  1.1  augustss     if (x < 0) x = 0 ;
   2823  1.1  augustss     y = 28*128 - (buf[3] + 128* (buf[4] - 7)) ;
   2824  1.1  augustss     if (y < 0) y = 0 ;
   2825  1.1  augustss 
   2826  1.1  augustss     x /= 8 ;
   2827  1.1  augustss     y /= 8 ;
   2828  1.1  augustss 
   2829  1.1  augustss     act->flags = 0 ;
   2830  1.1  augustss     act->obutton = act->button ;
   2831  1.1  augustss     act->dx = act->dy = act->dz = 0 ;
   2832  1.1  augustss     gettimeofday(&now, NULL);
   2833  1.1  augustss     if ( buf[0] & 0x40 ) /* pen went out of reach */
   2834  1.1  augustss 	status = S_IDLE ;
   2835  1.1  augustss     else if (status == S_IDLE) { /* pen is newly near the tablet */
   2836  1.1  augustss 	act->flags |= MOUSE_POSCHANGED ; /* force update */
   2837  1.1  augustss 	status = S_PROXY ;
   2838  1.1  augustss 	x_prev = x ;
   2839  1.1  augustss 	y_prev = y ;
   2840  1.1  augustss     }
   2841  1.1  augustss     old = now ;
   2842  1.1  augustss     act->dx = x - x_prev ;
   2843  1.1  augustss     act->dy = y - y_prev ;
   2844  1.1  augustss     if (act->dx || act->dy)
   2845  1.1  augustss 	act->flags |= MOUSE_POSCHANGED ;
   2846  1.1  augustss     x_prev = x ;
   2847  1.1  augustss     y_prev = y ;
   2848  1.1  augustss     if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */
   2849  1.1  augustss 	act->button = 0 ;
   2850  1.1  augustss 	if ( buf[0] & 0x01 ) /* tip pressed */
   2851  1.1  augustss 	    act->button |= MOUSE_BUTTON1DOWN ;
   2852  1.1  augustss 	if ( buf[0] & 0x02 ) /* button pressed */
   2853  1.1  augustss 	    act->button |= MOUSE_BUTTON2DOWN ;
   2854  1.1  augustss 	act->flags |= MOUSE_BUTTONSCHANGED ;
   2855  1.1  augustss     }
   2856  1.1  augustss     b_prev = buf[0] ;
   2857  1.1  augustss     return act->flags ;
   2858  1.1  augustss }
   2859