moused.c revision 153070
116566Ssos/**
216566Ssos ** Copyright (c) 1995 Michael Smith, All rights reserved.
316566Ssos **
416566Ssos ** Redistribution and use in source and binary forms, with or without
516566Ssos ** modification, are permitted provided that the following conditions
616566Ssos ** are met:
716566Ssos ** 1. Redistributions of source code must retain the above copyright
816566Ssos **    notice, this list of conditions and the following disclaimer as
916566Ssos **    the first lines of this file unmodified.
1016566Ssos ** 2. Redistributions in binary form must reproduce the above copyright
1116566Ssos **    notice, this list of conditions and the following disclaimer in the
1216566Ssos **    documentation and/or other materials provided with the distribution.
1316566Ssos ** 3. All advertising materials mentioning features or use of this software
1416566Ssos **    must display the following acknowledgment:
1516566Ssos **      This product includes software developed by Michael Smith.
1616566Ssos ** 4. The name of the author may not be used to endorse or promote products
1716566Ssos **    derived from this software without specific prior written permission.
1816566Ssos **
1916566Ssos **
2016566Ssos ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY
2116566Ssos ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2216566Ssos ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2316566Ssos ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR
2416566Ssos ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2516566Ssos ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2616566Ssos ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2716566Ssos ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2816566Ssos ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
2916566Ssos ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
3016566Ssos ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3116566Ssos **
3216566Ssos **/
3316566Ssos
3416566Ssos/**
3516566Ssos ** MOUSED.C
3616566Ssos **
3731604Syokota ** Mouse daemon : listens to a serial port, the bus mouse interface, or
38122605Sdes ** the PS/2 mouse port for mouse data stream, interprets data and passes
3931604Syokota ** ioctls off to the console driver.
4016566Ssos **
4116566Ssos ** The mouse interface functions are derived closely from the mouse
4216566Ssos ** handler in the XFree86 X server.  Many thanks to the XFree86 people
4316566Ssos ** for their great work!
44122605Sdes **
4516566Ssos **/
4616566Ssos
47122854Sdes#include <sys/cdefs.h>
48122854Sdes__FBSDID("$FreeBSD: head/usr.sbin/moused/moused.c 153070 2005-12-04 00:28:40Z philip $");
4929849Scharnier
50122853Sdes#include <sys/param.h>
51122853Sdes#include <sys/consio.h>
52122853Sdes#include <sys/linker.h>
53122853Sdes#include <sys/module.h>
54122853Sdes#include <sys/mouse.h>
55122853Sdes#include <sys/socket.h>
56122853Sdes#include <sys/stat.h>
57122853Sdes#include <sys/time.h>
58122853Sdes#include <sys/un.h>
59122853Sdes
6058231Syokota#include <ctype.h>
6129849Scharnier#include <err.h>
6229849Scharnier#include <errno.h>
6329849Scharnier#include <fcntl.h>
64149426Spjd#include <libutil.h>
6529849Scharnier#include <limits.h>
66122853Sdes#include <setjmp.h>
67122853Sdes#include <signal.h>
68122853Sdes#include <stdarg.h>
6916566Ssos#include <stdio.h>
7016566Ssos#include <stdlib.h>
7116566Ssos#include <string.h>
72122853Sdes#include <syslog.h>
7316566Ssos#include <termios.h>
7421885Ssos#include <unistd.h>
7516566Ssos
7631604Syokota#define MAX_CLICKTHRESHOLD	2000	/* 2 seconds */
7758344Syokota#define MAX_BUTTON2TIMEOUT	2000	/* 2 seconds */
7858344Syokota#define DFLT_CLICKTHRESHOLD	 500	/* 0.5 second */
7959465Syokota#define DFLT_BUTTON2TIMEOUT	 100	/* 0.1 second */
80136372Sphilip#define DFLT_SCROLLTHRESHOLD	   3	/* 3 pixels */
8131604Syokota
8279430Siedowse/* Abort 3-button emulation delay after this many movement events. */
8379430Siedowse#define BUTTON2_MAXMOVE	3
8479430Siedowse
8531604Syokota#define TRUE		1
8631604Syokota#define FALSE		0
8731604Syokota
8831604Syokota#define MOUSE_XAXIS	(-1)
8931604Syokota#define MOUSE_YAXIS	(-2)
9031604Syokota
9148778Syokota/* Logitech PS2++ protocol */
9248778Syokota#define MOUSE_PS2PLUS_CHECKBITS(b)	\
9348778Syokota			((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
9448778Syokota#define MOUSE_PS2PLUS_PACKET_TYPE(b)	\
9548778Syokota			(((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
9648778Syokota
9731604Syokota#define	ChordMiddle	0x0001
9831604Syokota#define Emulate3Button	0x0002
9931604Syokota#define ClearDTR	0x0004
10031604Syokota#define ClearRTS	0x0008
10131604Syokota#define NoPnP		0x0010
102136372Sphilip#define VirtualScroll	0x0020
103148161Sphilip#define HVirtualScroll	0x0040
104122605Sdes
10531604Syokota#define ID_NONE		0
10631604Syokota#define ID_PORT		1
10731604Syokota#define ID_IF		2
108136372Sphilip#define ID_TYPE		4
10931604Syokota#define ID_MODEL	8
11031604Syokota#define ID_ALL		(ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
11131604Syokota
11295629Siedowse#define debug(fmt, args...) do {				\
11395629Siedowse	if (debug && nodaemon)					\
11495629Siedowse		warnx(fmt, ##args);				\
11595629Siedowse} while (0)
11616566Ssos
11795629Siedowse#define logerr(e, fmt, args...) do {				\
11895629Siedowse	log_or_warn(LOG_DAEMON | LOG_ERR, errno, fmt, ##args);	\
11995629Siedowse	exit(e);						\
12095629Siedowse} while (0)
12131604Syokota
12295629Siedowse#define logerrx(e, fmt, args...) do {				\
12395629Siedowse	log_or_warn(LOG_DAEMON | LOG_ERR, 0, fmt, ##args);	\
12495629Siedowse	exit(e);						\
12595629Siedowse} while (0)
12631604Syokota
12795629Siedowse#define logwarn(fmt, args...)					\
12895629Siedowse	log_or_warn(LOG_DAEMON | LOG_WARNING, errno, fmt, ##args)
12931604Syokota
13095629Siedowse#define logwarnx(fmt, args...)					\
13195629Siedowse	log_or_warn(LOG_DAEMON | LOG_WARNING, 0, fmt, ##args)
13231604Syokota
13331604Syokota/* structures */
13431604Syokota
13531604Syokota/* symbol table entry */
13631604Syokotatypedef struct {
13731604Syokota    char *name;
13831604Syokota    int val;
13931604Syokota    int val2;
14031604Syokota} symtab_t;
14131604Syokota
14231604Syokota/* serial PnP ID string */
14331604Syokotatypedef struct {
14431604Syokota    int revision;	/* PnP revision, 100 for 1.00 */
14531604Syokota    char *eisaid;	/* EISA ID including mfr ID and product ID */
14631604Syokota    char *serial;	/* serial No, optional */
14731604Syokota    char *class;	/* device class, optional */
14831604Syokota    char *compat;	/* list of compatible drivers, optional */
14931604Syokota    char *description;	/* product description, optional */
15031604Syokota    int neisaid;	/* length of the above fields... */
15131604Syokota    int nserial;
15231604Syokota    int nclass;
15331604Syokota    int ncompat;
15431604Syokota    int ndescription;
15531604Syokota} pnpid_t;
15631604Syokota
15731604Syokota/* global variables */
15831604Syokota
15916566Ssosint	debug = 0;
16031604Syokotaint	nodaemon = FALSE;
16131604Syokotaint	background = FALSE;
162153070Sphilipint	paused = FALSE;
16331604Syokotaint	identify = ID_NONE;
16431604Syokotaint	extioctl = FALSE;
16534152Sjkhchar	*pidfile = "/var/run/moused.pid";
166149426Spjdstruct pidfh *pfh;
16716566Ssos
168136372Sphilip#define SCROLL_NOTSCROLLING	0
169136372Sphilip#define SCROLL_PREPARE		1
170136372Sphilip#define SCROLL_SCROLLING	2
171136372Sphilip
172136372Sphilipstatic int	scroll_state;
173136372Sphilipstatic int	scroll_movement;
174148161Sphilipstatic int	hscroll_movement;
175136372Sphilip
17631604Syokota/* local variables */
17716566Ssos
17831604Syokota/* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
17931604Syokotastatic symtab_t rifs[] = {
18031604Syokota    { "serial",		MOUSE_IF_SERIAL },
18131604Syokota    { "bus",		MOUSE_IF_BUS },
18231604Syokota    { "inport",		MOUSE_IF_INPORT },
18331604Syokota    { "ps/2",		MOUSE_IF_PS2 },
18431604Syokota    { "sysmouse",	MOUSE_IF_SYSMOUSE },
18544326Syokota    { "usb",		MOUSE_IF_USB },
18631604Syokota    { NULL,		MOUSE_IF_UNKNOWN },
18731604Syokota};
18816566Ssos
18931604Syokota/* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */
19031604Syokotastatic char *rnames[] = {
19116566Ssos    "microsoft",
19216566Ssos    "mousesystems",
19331604Syokota    "logitech",
19416566Ssos    "mmseries",
19531604Syokota    "mouseman",
19616566Ssos    "busmouse",
19731604Syokota    "inportmouse",
19816566Ssos    "ps/2",
19918222Speter    "mmhitab",
20031604Syokota    "glidepoint",
20131604Syokota    "intellimouse",
20231604Syokota    "thinkingmouse",
20331604Syokota    "sysmouse",
20436991Sahasty    "x10mouseremote",
20541271Syokota    "kidspad",
20693071Swill    "versapad",
20793071Swill    "jogdial",
20831604Syokota#if notyet
20931604Syokota    "mariqua",
21031604Syokota#endif
211145001Smdodd    "gtco_digipad",
21216566Ssos    NULL
21316566Ssos};
21416566Ssos
21531604Syokota/* models */
21631604Syokotastatic symtab_t	rmodels[] = {
21758231Syokota    { "NetScroll",		MOUSE_MODEL_NETSCROLL },
21858231Syokota    { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET },
21958231Syokota    { "GlidePoint",		MOUSE_MODEL_GLIDEPOINT },
22058231Syokota    { "ThinkingMouse",		MOUSE_MODEL_THINK },
22158231Syokota    { "IntelliMouse",		MOUSE_MODEL_INTELLI },
22258231Syokota    { "EasyScroll/SmartScroll",	MOUSE_MODEL_EASYSCROLL },
22358231Syokota    { "MouseMan+",		MOUSE_MODEL_MOUSEMANPLUS },
22458231Syokota    { "Kidspad",		MOUSE_MODEL_KIDSPAD },
22558231Syokota    { "VersaPad",		MOUSE_MODEL_VERSAPAD },
22658231Syokota    { "IntelliMouse Explorer",	MOUSE_MODEL_EXPLORER },
22758231Syokota    { "4D Mouse",		MOUSE_MODEL_4D },
22858231Syokota    { "4D+ Mouse",		MOUSE_MODEL_4DPLUS },
229133083Sphilip    { "Synaptics Touchpad",	MOUSE_MODEL_SYNAPTICS },
23058231Syokota    { "generic",		MOUSE_MODEL_GENERIC },
231122605Sdes    { NULL,			MOUSE_MODEL_UNKNOWN },
23231604Syokota};
23331604Syokota
23431604Syokota/* PnP EISA/product IDs */
23531604Syokotastatic symtab_t pnpprod[] = {
23631604Syokota    /* Kensignton ThinkingMouse */
23731604Syokota    { "KML0001",	MOUSE_PROTO_THINK,	MOUSE_MODEL_THINK },
23831604Syokota    /* MS IntelliMouse */
23931604Syokota    { "MSH0001",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
24031604Syokota    /* MS IntelliMouse TrackBall */
24131604Syokota    { "MSH0004",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
24258099Sache    /* Tremon Wheel Mouse MUSD */
24358099Sache    { "HTK0001",        MOUSE_PROTO_INTELLI,    MOUSE_MODEL_INTELLI },
24433074Sache    /* Genius PnP Mouse */
24533074Sache    { "KYE0001",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
24656524Syokota    /* MouseSystems SmartScroll Mouse (OEM from Genius?) */
24756524Syokota    { "KYE0002",	MOUSE_PROTO_MS,		MOUSE_MODEL_EASYSCROLL },
24833074Sache    /* Genius NetMouse */
24933074Sache    { "KYE0003",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_NET },
25041271Syokota    /* Genius Kidspad, Easypad and other tablets */
25141271Syokota    { "KYE0005",	MOUSE_PROTO_KIDSPAD,	MOUSE_MODEL_KIDSPAD },
25231604Syokota    /* Genius EZScroll */
253122605Sdes    { "KYEEZ00",	MOUSE_PROTO_MS,		MOUSE_MODEL_EASYSCROLL },
25456335Syokota    /* Logitech Cordless MouseMan Wheel */
25556335Syokota    { "LGI8033",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
25631949Syokota    /* Logitech MouseMan (new 4 button model) */
25731949Syokota    { "LGI800C",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
25831604Syokota    /* Logitech MouseMan+ */
25931604Syokota    { "LGI8050",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
26031604Syokota    /* Logitech FirstMouse+ */
26131604Syokota    { "LGI8051",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
26232634Syokota    /* Logitech serial */
26332634Syokota    { "LGI8001",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
26458231Syokota    /* A4 Tech 4D/4D+ Mouse */
26558231Syokota    { "A4W0005",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_4D },
26658231Syokota    /* 8D Scroll Mouse */
26758231Syokota    { "PEC9802",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
26858328Syokota    /* Mitsumi Wireless Scroll Mouse */
26958328Syokota    { "MTM6401",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
27031604Syokota
27131604Syokota    /* MS bus */
27231604Syokota    { "PNP0F00",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
27331604Syokota    /* MS serial */
274122605Sdes    { "PNP0F01",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
27531604Syokota    /* MS InPort */
276122605Sdes    { "PNP0F02",	MOUSE_PROTO_INPORT,	MOUSE_MODEL_GENERIC },
27731604Syokota    /* MS PS/2 */
278122605Sdes    { "PNP0F03",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
27931604Syokota    /*
28031604Syokota     * EzScroll returns PNP0F04 in the compatible device field; but it
28131604Syokota     * doesn't look compatible... XXX
28231604Syokota     */
283122605Sdes    /* MouseSystems */
284122605Sdes    { "PNP0F04",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
285122605Sdes    /* MouseSystems */
286122605Sdes    { "PNP0F05",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
28731604Syokota#if notyet
288122605Sdes    /* Genius Mouse */
289122854Sdes    { "PNP0F06",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
290122605Sdes    /* Genius Mouse */
291122854Sdes    { "PNP0F07",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
29231604Syokota#endif
29331604Syokota    /* Logitech serial */
29431604Syokota    { "PNP0F08",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
29531604Syokota    /* MS BallPoint serial */
296122605Sdes    { "PNP0F09",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
29731604Syokota    /* MS PnP serial */
298122605Sdes    { "PNP0F0A",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
29931604Syokota    /* MS PnP BallPoint serial */
300122605Sdes    { "PNP0F0B",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
30131604Syokota    /* MS serial comatible */
302122605Sdes    { "PNP0F0C",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
30331604Syokota    /* MS InPort comatible */
304122605Sdes    { "PNP0F0D",	MOUSE_PROTO_INPORT,	MOUSE_MODEL_GENERIC },
30531604Syokota    /* MS PS/2 comatible */
306122605Sdes    { "PNP0F0E",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
30731604Syokota    /* MS BallPoint comatible */
308122605Sdes    { "PNP0F0F",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
30931604Syokota#if notyet
31031604Syokota    /* TI QuickPort */
311122854Sdes    { "PNP0F10",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
31231604Syokota#endif
31331604Syokota    /* MS bus comatible */
314122605Sdes    { "PNP0F11",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
31531604Syokota    /* Logitech PS/2 */
31631604Syokota    { "PNP0F12",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
31731604Syokota    /* PS/2 */
31831604Syokota    { "PNP0F13",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
31931604Syokota#if notyet
32031604Syokota    /* MS Kids Mouse */
321122854Sdes    { "PNP0F14",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
32231604Syokota#endif
323122605Sdes    /* Logitech bus */
32431604Syokota    { "PNP0F15",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
32531604Syokota#if notyet
32631604Syokota    /* Logitech SWIFT */
327122854Sdes    { "PNP0F16",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
32831604Syokota#endif
32931604Syokota    /* Logitech serial compat */
33031604Syokota    { "PNP0F17",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
33131604Syokota    /* Logitech bus compatible */
33231604Syokota    { "PNP0F18",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
33331604Syokota    /* Logitech PS/2 compatible */
33431604Syokota    { "PNP0F19",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
33531604Syokota#if notyet
33631604Syokota    /* Logitech SWIFT compatible */
337122854Sdes    { "PNP0F1A",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
33831604Syokota    /* HP Omnibook */
339122854Sdes    { "PNP0F1B",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
34031604Syokota    /* Compaq LTE TrackBall PS/2 */
341122854Sdes    { "PNP0F1C",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
34231604Syokota    /* Compaq LTE TrackBall serial */
343122854Sdes    { "PNP0F1D",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
34431604Syokota    /* MS Kidts Trackball */
345122854Sdes    { "PNP0F1E",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
34631604Syokota#endif
34749967Syokota    /* Interlink VersaPad */
34849967Syokota    { "LNK0001",	MOUSE_PROTO_VERSAPAD,	MOUSE_MODEL_VERSAPAD },
34931604Syokota
35031604Syokota    { NULL,		MOUSE_PROTO_UNKNOWN,	MOUSE_MODEL_GENERIC },
35131604Syokota};
35231604Syokota
35331604Syokota/* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */
35431604Syokotastatic unsigned short rodentcflags[] =
35516566Ssos{
356122854Sdes    (CS7	           | CREAD | CLOCAL | HUPCL),	/* MicroSoft */
357122854Sdes    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* MouseSystems */
358122854Sdes    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* Logitech */
359122854Sdes    (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL),	/* MMSeries */
360122854Sdes    (CS7		   | CREAD | CLOCAL | HUPCL),	/* MouseMan */
36131604Syokota    0,							/* Bus */
36231604Syokota    0,							/* InPort */
36318222Speter    0,							/* PS/2 */
364122854Sdes    (CS8		   | CREAD | CLOCAL | HUPCL),	/* MM HitTablet */
365122854Sdes    (CS7	           | CREAD | CLOCAL | HUPCL),	/* GlidePoint */
366122854Sdes    (CS7                   | CREAD | CLOCAL | HUPCL),	/* IntelliMouse */
367122854Sdes    (CS7                   | CREAD | CLOCAL | HUPCL),	/* Thinking Mouse */
368122854Sdes    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* sysmouse */
369122854Sdes    (CS7	           | CREAD | CLOCAL | HUPCL),	/* X10 MouseRemote */
370122854Sdes    (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL),	/* kidspad etc. */
371122854Sdes    (CS8		   | CREAD | CLOCAL | HUPCL),	/* VersaPad */
37293071Swill    0,							/* JogDial */
37331604Syokota#if notyet
374122854Sdes    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* Mariqua */
37531604Syokota#endif
376145001Smdodd    (CS8		   | CREAD |	      HUPCL ),	/* GTCO Digi-Pad */
37716566Ssos};
37816566Ssos
37931604Syokotastatic struct rodentparam {
38031604Syokota    int flags;
38131604Syokota    char *portname;		/* /dev/XXX */
38231604Syokota    int rtype;			/* MOUSE_PROTO_XXX */
38331604Syokota    int level;			/* operation level: 0 or greater */
38431604Syokota    int baudrate;
38531604Syokota    int rate;			/* report rate */
38631604Syokota    int resolution;		/* MOUSE_RES_XXX or a positive number */
38758231Syokota    int zmap[4];		/* MOUSE_{X|Y}AXIS or a button number */
38841270Syokota    int wmode;			/* wheel mode button number */
38931604Syokota    int mfd;			/* mouse file descriptor */
39031604Syokota    int cfd;			/* /dev/consolectl file descriptor */
39136991Sahasty    int mremsfd;		/* mouse remote server file descriptor */
39236991Sahasty    int mremcfd;		/* mouse remote client file descriptor */
39331604Syokota    long clickthreshold;	/* double click speed in msec */
39458344Syokota    long button2timeout;	/* 3 button emulation timeout */
39531604Syokota    mousehw_t hw;		/* mouse device hardware information */
39631604Syokota    mousemode_t mode;		/* protocol information */
39778770Sgreid    float accelx;		/* Acceleration in the X axis */
39878770Sgreid    float accely;		/* Acceleration in the Y axis */
399136372Sphilip    int scrollthreshold;	/* Movement distance before virtual scrolling */
400122605Sdes} rodent = {
401131525Sstefanf    .flags = 0,
402131525Sstefanf    .portname = NULL,
403131525Sstefanf    .rtype = MOUSE_PROTO_UNKNOWN,
404131525Sstefanf    .level = -1,
405131525Sstefanf    .baudrate = 1200,
406131525Sstefanf    .rate = 0,
407131525Sstefanf    .resolution = MOUSE_RES_UNKNOWN,
408131525Sstefanf    .zmap = { 0, 0, 0, 0 },
409131525Sstefanf    .wmode = 0,
410131525Sstefanf    .mfd = -1,
411131525Sstefanf    .cfd = -1,
412131525Sstefanf    .mremsfd = -1,
413131525Sstefanf    .mremcfd = -1,
414131525Sstefanf    .clickthreshold = DFLT_CLICKTHRESHOLD,
415131525Sstefanf    .button2timeout = DFLT_BUTTON2TIMEOUT,
416131525Sstefanf    .accelx = 1.0,
417131525Sstefanf    .accely = 1.0,
418136372Sphilip    .scrollthreshold = DFLT_SCROLLTHRESHOLD,
41931604Syokota};
42016566Ssos
42131604Syokota/* button status */
42258344Syokotastruct button_state {
42331604Syokota    int count;		/* 0: up, 1: single click, 2: double click,... */
42458344Syokota    struct timeval tv;	/* timestamp on the last button event */
42558344Syokota};
42658344Syokotastatic struct button_state	bstate[MOUSE_MAXBUTTON]; /* button state */
42758344Syokotastatic struct button_state	*mstate[MOUSE_MAXBUTTON];/* mapped button st.*/
42858344Syokotastatic struct button_state	zstate[4];		 /* Z/W axis state */
42916566Ssos
43058344Syokota/* state machine for 3 button emulation */
43158344Syokota
43258344Syokota#define S0	0	/* start */
43358344Syokota#define S1	1	/* button 1 delayed down */
43458344Syokota#define S2	2	/* button 3 delayed down */
43558344Syokota#define S3	3	/* both buttons down -> button 2 down */
43658344Syokota#define S4	4	/* button 1 delayed up */
43758344Syokota#define S5	5	/* button 1 down */
43858344Syokota#define S6	6	/* button 3 down */
43958344Syokota#define S7	7	/* both buttons down */
44058344Syokota#define S8	8	/* button 3 delayed up */
44158344Syokota#define S9	9	/* button 1 or 3 up after S3 */
44258344Syokota
44358344Syokota#define A(b1, b3)	(((b1) ? 2 : 0) | ((b3) ? 1 : 0))
44458344Syokota#define A_TIMEOUT	4
44579430Siedowse#define S_DELAYED(st)	(states[st].s[A_TIMEOUT] != (st))
44658344Syokota
44758344Syokotastatic struct {
44858344Syokota    int s[A_TIMEOUT + 1];
44958344Syokota    int buttons;
45058344Syokota    int mask;
45159090Syokota    int timeout;
45258344Syokota} states[10] = {
45358344Syokota    /* S0 */
45459090Syokota    { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
45558344Syokota    /* S1 */
45659090Syokota    { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, FALSE },
45758344Syokota    /* S2 */
45859090Syokota    { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, FALSE },
45958344Syokota    /* S3 */
46059090Syokota    { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, FALSE },
46158344Syokota    /* S4 */
46259090Syokota    { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, TRUE },
46358344Syokota    /* S5 */
46459090Syokota    { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, FALSE },
46558344Syokota    /* S6 */
46659090Syokota    { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, FALSE },
46758344Syokota    /* S7 */
46859090Syokota    { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, FALSE },
46958344Syokota    /* S8 */
47059090Syokota    { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, TRUE },
47158344Syokota    /* S9 */
47259090Syokota    { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
47358344Syokota};
47458344Syokotastatic int		mouse_button_state;
47558344Syokotastatic struct timeval	mouse_button_state_tv;
47679430Siedowsestatic int		mouse_move_delayed;
47758344Syokota
47831604Syokotastatic jmp_buf env;
47916566Ssos
480150310Sphilipstatic int		drift_distance = 4;   /* max steps X+Y */
481150310Sphilipstatic int		drift_time = 500;   /* in 0.5 sec */
482150310Sphilipstatic struct timeval	drift_time_tv;
483150310Sphilipstatic struct timeval	drift_2time_tv;   /* 2*drift_time */
484150310Sphilipstatic int		drift_after = 4000;   /* 4 sec */
485150310Sphilipstatic struct timeval	drift_after_tv;
486150310Sphilipstatic int		drift_terminate = FALSE;
487150310Sphilipstatic struct timeval	drift_current_tv;
488150310Sphilipstatic struct timeval	drift_tmp;
489150310Sphilipstatic struct timeval	drift_last_activity = {0,0};
490150310Sphilipstatic struct drift_xy {
491150310Sphilip	int x; int y; }	drift_last = {0,0};   /* steps in last drift_time */
492150310Sphilipstatic struct timeval	drift_since = {0,0};
493150310Sphilipstatic struct drift_xy  drift_previous={0,0}; /* steps in previous drift_time */
494150310Sphilip
49531604Syokota/* function prototypes */
49616566Ssos
49731604Syokotastatic void	moused(void);
49831604Syokotastatic void	hup(int sig);
49936991Sahastystatic void	cleanup(int sig);
500153070Sphilipstatic void	pause_mouse(int sig);
50131604Syokotastatic void	usage(void);
50295629Siedowsestatic void	log_or_warn(int log_pri, int errnum, const char *fmt, ...)
50395629Siedowse		    __printflike(3, 4);
50431604Syokota
50531604Syokotastatic int	r_identify(void);
50631604Syokotastatic char	*r_if(int type);
50731604Syokotastatic char	*r_name(int type);
50831604Syokotastatic char	*r_model(int model);
50931604Syokotastatic void	r_init(void);
51031604Syokotastatic int	r_protocol(u_char b, mousestatus_t *act);
51158344Syokotastatic int	r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans);
51231604Syokotastatic int	r_installmap(char *arg);
51331604Syokotastatic void	r_map(mousestatus_t *act1, mousestatus_t *act2);
51458344Syokotastatic void	r_timestamp(mousestatus_t *act);
51558344Syokotastatic int	r_timeout(void);
51631604Syokotastatic void	r_click(mousestatus_t *act);
51731604Syokotastatic void	setmousespeed(int old, int new, unsigned cflag);
51831604Syokota
51940255Syokotastatic int	pnpwakeup1(void);
52040255Syokotastatic int	pnpwakeup2(void);
52131604Syokotastatic int	pnpgets(char *buf);
52231604Syokotastatic int	pnpparse(pnpid_t *id, char *buf, int len);
52331604Syokotastatic symtab_t	*pnpproto(pnpid_t *id);
52431604Syokota
52531604Syokotastatic symtab_t	*gettoken(symtab_t *tab, char *s, int len);
52631604Syokotastatic char	*gettokenname(symtab_t *tab, int val);
52731604Syokota
52836991Sahastystatic void	mremote_serversetup();
52936991Sahastystatic void	mremote_clientchg(int add);
53036991Sahasty
531122854Sdesstatic int	kidspad(u_char rxc, mousestatus_t *act);
532145001Smdoddstatic int	gtco_digipad(u_char, mousestatus_t *);
53341271Syokota
534122854Sdesstatic int	usbmodule(void);
535122852Sdes
53651287Speterint
53716566Ssosmain(int argc, char *argv[])
53816566Ssos{
53931604Syokota    int c;
54031604Syokota    int	i;
54158231Syokota    int	j;
542122630Sdes    int retry;
54316566Ssos
54458344Syokota    for (i = 0; i < MOUSE_MAXBUTTON; ++i)
54558344Syokota	mstate[i] = &bstate[i];
54658344Syokota
547150310Sphilip    while ((c = getopt(argc, argv, "3C:DE:F:HI:PRS:T:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
54831604Syokota	switch(c) {
54931604Syokota
55031604Syokota	case '3':
55131604Syokota	    rodent.flags |= Emulate3Button;
55231604Syokota	    break;
55331604Syokota
55458344Syokota	case 'E':
55558344Syokota	    rodent.button2timeout = atoi(optarg);
556122605Sdes	    if ((rodent.button2timeout < 0) ||
557122605Sdes		(rodent.button2timeout > MAX_BUTTON2TIMEOUT)) {
558122605Sdes		warnx("invalid argument `%s'", optarg);
559122605Sdes		usage();
56058344Syokota	    }
56158344Syokota	    break;
56258344Syokota
56378770Sgreid	case 'a':
56478770Sgreid	    i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely);
56578770Sgreid	    if (i == 0) {
56678770Sgreid		warnx("invalid acceleration argument '%s'", optarg);
56778770Sgreid		usage();
56878770Sgreid	    }
569122605Sdes
57078770Sgreid	    if (i == 1)
57178770Sgreid		rodent.accely = rodent.accelx;
572122605Sdes
57378770Sgreid	    break;
574122605Sdes
57516566Ssos	case 'c':
57616566Ssos	    rodent.flags |= ChordMiddle;
57716566Ssos	    break;
57816566Ssos
57916566Ssos	case 'd':
58031604Syokota	    ++debug;
58116566Ssos	    break;
58216566Ssos
58316566Ssos	case 'f':
58431604Syokota	    nodaemon = TRUE;
58516566Ssos	    break;
58616566Ssos
58731604Syokota	case 'i':
58831604Syokota	    if (strcmp(optarg, "all") == 0)
589122605Sdes		identify = ID_ALL;
59031604Syokota	    else if (strcmp(optarg, "port") == 0)
591122605Sdes		identify = ID_PORT;
59231604Syokota	    else if (strcmp(optarg, "if") == 0)
593122605Sdes		identify = ID_IF;
59431604Syokota	    else if (strcmp(optarg, "type") == 0)
595122605Sdes		identify = ID_TYPE;
59631604Syokota	    else if (strcmp(optarg, "model") == 0)
597122605Sdes		identify = ID_MODEL;
59831604Syokota	    else {
599122605Sdes		warnx("invalid argument `%s'", optarg);
600122605Sdes		usage();
60131604Syokota	    }
60231604Syokota	    nodaemon = TRUE;
60331604Syokota	    break;
60431604Syokota
60531604Syokota	case 'l':
60631604Syokota	    rodent.level = atoi(optarg);
60731604Syokota	    if ((rodent.level < 0) || (rodent.level > 4)) {
608122605Sdes		warnx("invalid argument `%s'", optarg);
609122605Sdes		usage();
61031604Syokota	    }
61131604Syokota	    break;
61231604Syokota
61331604Syokota	case 'm':
61431604Syokota	    if (!r_installmap(optarg)) {
615122605Sdes		warnx("invalid argument `%s'", optarg);
616122605Sdes		usage();
61731604Syokota	    }
61831604Syokota	    break;
61931604Syokota
62016566Ssos	case 'p':
62116566Ssos	    rodent.portname = optarg;
62216566Ssos	    break;
62316566Ssos
62424377Speter	case 'r':
62531604Syokota	    if (strcmp(optarg, "high") == 0)
626122605Sdes		rodent.resolution = MOUSE_RES_HIGH;
62731604Syokota	    else if (strcmp(optarg, "medium-high") == 0)
628122605Sdes		rodent.resolution = MOUSE_RES_HIGH;
62931604Syokota	    else if (strcmp(optarg, "medium-low") == 0)
630122605Sdes		rodent.resolution = MOUSE_RES_MEDIUMLOW;
63131604Syokota	    else if (strcmp(optarg, "low") == 0)
632122605Sdes		rodent.resolution = MOUSE_RES_LOW;
63331604Syokota	    else if (strcmp(optarg, "default") == 0)
634122605Sdes		rodent.resolution = MOUSE_RES_DEFAULT;
63531604Syokota	    else {
636122605Sdes		rodent.resolution = atoi(optarg);
637122605Sdes		if (rodent.resolution <= 0) {
638122605Sdes		    warnx("invalid argument `%s'", optarg);
639122605Sdes		    usage();
640122605Sdes		}
64131604Syokota	    }
64224377Speter	    break;
64324377Speter
64416566Ssos	case 's':
64516566Ssos	    rodent.baudrate = 9600;
64618222Speter	    break;
64716566Ssos
64841270Syokota	case 'w':
64941270Syokota	    i = atoi(optarg);
65041270Syokota	    if ((i <= 0) || (i > MOUSE_MAXBUTTON)) {
65141270Syokota		warnx("invalid argument `%s'", optarg);
65241270Syokota		usage();
65341270Syokota	    }
65441270Syokota	    rodent.wmode = 1 << (i - 1);
65541270Syokota	    break;
65641270Syokota
65731604Syokota	case 'z':
65831604Syokota	    if (strcmp(optarg, "x") == 0)
65958231Syokota		rodent.zmap[0] = MOUSE_XAXIS;
66031604Syokota	    else if (strcmp(optarg, "y") == 0)
66158231Syokota		rodent.zmap[0] = MOUSE_YAXIS;
662122605Sdes	    else {
66331604Syokota		i = atoi(optarg);
664122605Sdes		/*
665122605Sdes		 * Use button i for negative Z axis movement and
66631604Syokota		 * button (i + 1) for positive Z axis movement.
66731604Syokota		 */
66831604Syokota		if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
669122605Sdes		    warnx("invalid argument `%s'", optarg);
670122605Sdes		    usage();
67131604Syokota		}
67258344Syokota		rodent.zmap[0] = i;
67358344Syokota		rodent.zmap[1] = i + 1;
67458861Syokota		debug("optind: %d, optarg: '%s'", optind, optarg);
67558231Syokota		for (j = 1; j < 4; ++j) {
67658231Syokota		    if ((optind >= argc) || !isdigit(*argv[optind]))
67758231Syokota			break;
67858231Syokota		    i = atoi(argv[optind]);
67958231Syokota		    if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
68058231Syokota			warnx("invalid argument `%s'", argv[optind]);
68158231Syokota			usage();
68258231Syokota		    }
68358344Syokota		    rodent.zmap[j] = i;
68458231Syokota		    ++optind;
68558231Syokota		}
68659090Syokota		if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0))
68758344Syokota		    rodent.zmap[3] = rodent.zmap[2] + 1;
68831604Syokota	    }
68918222Speter	    break;
69018222Speter
69131604Syokota	case 'C':
69231604Syokota	    rodent.clickthreshold = atoi(optarg);
693122605Sdes	    if ((rodent.clickthreshold < 0) ||
694122605Sdes		(rodent.clickthreshold > MAX_CLICKTHRESHOLD)) {
695122605Sdes		warnx("invalid argument `%s'", optarg);
696122605Sdes		usage();
69731604Syokota	    }
69831604Syokota	    break;
69931604Syokota
70018222Speter	case 'D':
70131604Syokota	    rodent.flags |= ClearDTR;
70218222Speter	    break;
70318222Speter
70431604Syokota	case 'F':
70531604Syokota	    rodent.rate = atoi(optarg);
70631604Syokota	    if (rodent.rate <= 0) {
707122605Sdes		warnx("invalid argument `%s'", optarg);
708122605Sdes		usage();
70931604Syokota	    }
71031604Syokota	    break;
71131604Syokota
712148161Sphilip	case 'H':
713148161Sphilip	    rodent.flags |= HVirtualScroll;
714148161Sphilip	    break;
715148161Sphilip
71634152Sjkh	case 'I':
71734152Sjkh	    pidfile = optarg;
71834152Sjkh	    break;
71934152Sjkh
72031604Syokota	case 'P':
72131604Syokota	    rodent.flags |= NoPnP;
72231604Syokota	    break;
72331604Syokota
72431604Syokota	case 'R':
72531604Syokota	    rodent.flags |= ClearRTS;
72631604Syokota	    break;
72731604Syokota
72818222Speter	case 'S':
72918222Speter	    rodent.baudrate = atoi(optarg);
73031604Syokota	    if (rodent.baudrate <= 0) {
731122605Sdes		warnx("invalid argument `%s'", optarg);
732122605Sdes		usage();
73331604Syokota	    }
73418222Speter	    debug("rodent baudrate %d", rodent.baudrate);
73518222Speter	    break;
73618222Speter
737150310Sphilip	case 'T':
738150310Sphilip	    drift_terminate = TRUE;
739150310Sphilip	    sscanf(optarg, "%d,%d,%d", &drift_distance, &drift_time,
740150310Sphilip		&drift_after);
741150310Sphilip	    if (drift_distance <= 0 || drift_time <= 0 || drift_after <= 0) {
742150310Sphilip		warnx("invalid argument `%s'", optarg);
743150310Sphilip		usage();
744150310Sphilip	    }
745150310Sphilip	    debug("terminate drift: distance %d, time %d, after %d",
746150310Sphilip		drift_distance, drift_time, drift_after);
747150310Sphilip	    drift_time_tv.tv_sec = drift_time/1000;
748150310Sphilip	    drift_time_tv.tv_usec = (drift_time%1000)*1000;
749150310Sphilip 	    drift_2time_tv.tv_sec = (drift_time*=2)/1000;
750150310Sphilip	    drift_2time_tv.tv_usec = (drift_time%1000)*1000;
751150310Sphilip	    drift_after_tv.tv_sec = drift_after/1000;
752150310Sphilip	    drift_after_tv.tv_usec = (drift_after%1000)*1000;
753150310Sphilip	    break;
754150310Sphilip
75516566Ssos	case 't':
75631949Syokota	    if (strcmp(optarg, "auto") == 0) {
75731949Syokota		rodent.rtype = MOUSE_PROTO_UNKNOWN;
75831949Syokota		rodent.flags &= ~NoPnP;
75931949Syokota		rodent.level = -1;
76031949Syokota		break;
76131949Syokota	    }
76216566Ssos	    for (i = 0; rnames[i]; i++)
76331949Syokota		if (strcmp(optarg, rnames[i]) == 0) {
76416566Ssos		    rodent.rtype = i;
76531949Syokota		    rodent.flags |= NoPnP;
76631949Syokota		    rodent.level = (i == MOUSE_PROTO_SYSMOUSE) ? 1 : 0;
76716566Ssos		    break;
76816566Ssos		}
76916566Ssos	    if (rnames[i])
77016566Ssos		break;
77131604Syokota	    warnx("no such mouse type `%s'", optarg);
77216566Ssos	    usage();
77316566Ssos
774136372Sphilip	case 'V':
775136372Sphilip	    rodent.flags |= VirtualScroll;
776136372Sphilip	    break;
777136372Sphilip	case 'U':
778136372Sphilip	    rodent.scrollthreshold = atoi(optarg);
779136372Sphilip	    if (rodent.scrollthreshold < 0) {
780136372Sphilip		warnx("invalid argument `%s'", optarg);
781136372Sphilip		usage();
782136372Sphilip	    }
783136372Sphilip	    break;
784136372Sphilip
78516566Ssos	case 'h':
78616566Ssos	case '?':
78716566Ssos	default:
78816566Ssos	    usage();
78916566Ssos	}
79016566Ssos
79159090Syokota    /* fix Z axis mapping */
79259090Syokota    for (i = 0; i < 4; ++i) {
79359090Syokota	if (rodent.zmap[i] > 0) {
79459090Syokota	    for (j = 0; j < MOUSE_MAXBUTTON; ++j) {
79559090Syokota		if (mstate[j] == &bstate[rodent.zmap[i] - 1])
79659090Syokota		    mstate[j] = &zstate[i];
79759090Syokota	    }
79859090Syokota	    rodent.zmap[i] = 1 << (rodent.zmap[i] - 1);
79959090Syokota	}
80059090Syokota    }
80159090Syokota
80231604Syokota    /* the default port name */
80331604Syokota    switch(rodent.rtype) {
80431604Syokota
80531604Syokota    case MOUSE_PROTO_INPORT:
806122605Sdes	/* INPORT and BUS are the same... */
80731604Syokota	rodent.rtype = MOUSE_PROTO_BUS;
808102413Scharnier	/* FALLTHROUGH */
80931604Syokota    case MOUSE_PROTO_BUS:
81016566Ssos	if (!rodent.portname)
81116566Ssos	    rodent.portname = "/dev/mse0";
81216566Ssos	break;
81331604Syokota
81431604Syokota    case MOUSE_PROTO_PS2:
81516566Ssos	if (!rodent.portname)
81616566Ssos	    rodent.portname = "/dev/psm0";
81716566Ssos	break;
81831604Syokota
81916566Ssos    default:
82016566Ssos	if (rodent.portname)
82116566Ssos	    break;
82229849Scharnier	warnx("no port name specified");
82316566Ssos	usage();
82416566Ssos    }
82516566Ssos
826122630Sdes    retry = 1;
827122630Sdes    if (strncmp(rodent.portname, "/dev/ums", 8) == 0) {
828124339Ssobomax	if (usbmodule() != 0)
829124339Ssobomax	    retry = 5;
830122630Sdes    }
831122630Sdes
83231604Syokota    for (;;) {
83331604Syokota	if (setjmp(env) == 0) {
83431604Syokota	    signal(SIGHUP, hup);
83536991Sahasty	    signal(SIGINT , cleanup);
83636991Sahasty	    signal(SIGQUIT, cleanup);
83736991Sahasty	    signal(SIGTERM, cleanup);
838153070Sphilip	    signal(SIGUSR1, pause_mouse);
839122630Sdes	    for (i = 0; i < retry; ++i) {
840124339Ssobomax		if (i > 0)
841124339Ssobomax		    sleep(2);
842122630Sdes		rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK);
843122630Sdes		if (rodent.mfd != -1 || errno != ENOENT)
844122630Sdes		    break;
845122630Sdes	    }
846122630Sdes	    if (rodent.mfd == -1)
847122605Sdes		logerr(1, "unable to open %s", rodent.portname);
848122605Sdes	    if (r_identify() == MOUSE_PROTO_UNKNOWN) {
849122605Sdes		logwarnx("cannot determine mouse type on %s", rodent.portname);
850122605Sdes		close(rodent.mfd);
851122605Sdes		rodent.mfd = -1;
852122605Sdes	    }
85331604Syokota
85431604Syokota	    /* print some information */
855122605Sdes	    if (identify != ID_NONE) {
85631604Syokota		if (identify == ID_ALL)
857122605Sdes		    printf("%s %s %s %s\n",
858122605Sdes			rodent.portname, r_if(rodent.hw.iftype),
859122605Sdes			r_name(rodent.rtype), r_model(rodent.hw.model));
86031604Syokota		else if (identify & ID_PORT)
86131604Syokota		    printf("%s\n", rodent.portname);
86231604Syokota		else if (identify & ID_IF)
86331604Syokota		    printf("%s\n", r_if(rodent.hw.iftype));
86431604Syokota		else if (identify & ID_TYPE)
86531604Syokota		    printf("%s\n", r_name(rodent.rtype));
86631604Syokota		else if (identify & ID_MODEL)
86731604Syokota		    printf("%s\n", r_model(rodent.hw.model));
86831604Syokota		exit(0);
86931604Syokota	    } else {
870122605Sdes		debug("port: %s  interface: %s  type: %s  model: %s",
87131604Syokota		    rodent.portname, r_if(rodent.hw.iftype),
87231604Syokota		    r_name(rodent.rtype), r_model(rodent.hw.model));
87331604Syokota	    }
87431604Syokota
87531604Syokota	    if (rodent.mfd == -1) {
876122605Sdes		/*
877122605Sdes		 * We cannot continue because of error.  Exit if the
878122605Sdes		 * program has not become a daemon.  Otherwise, block
879122605Sdes		 * until the the user corrects the problem and issues SIGHUP.
880122605Sdes		 */
881122605Sdes		if (!background)
88231604Syokota		    exit(1);
883122605Sdes		sigpause(0);
88431604Syokota	    }
88531604Syokota
886122605Sdes	    r_init();			/* call init function */
88731604Syokota	    moused();
88831604Syokota	}
88931604Syokota
89031604Syokota	if (rodent.mfd != -1)
89131604Syokota	    close(rodent.mfd);
89231604Syokota	if (rodent.cfd != -1)
89331604Syokota	    close(rodent.cfd);
89431604Syokota	rodent.mfd = rodent.cfd = -1;
89516566Ssos    }
89631604Syokota    /* NOT REACHED */
89716566Ssos
89831604Syokota    exit(0);
89931604Syokota}
90016566Ssos
901122852Sdesstatic int
902122852Sdesusbmodule(void)
903122852Sdes{
904122852Sdes    struct kld_file_stat fstat;
905122852Sdes    struct module_stat mstat;
906122852Sdes    int fileid, modid;
907122852Sdes    int loaded;
908122852Sdes
909122852Sdes    for (loaded = 0, fileid = kldnext(0); !loaded && fileid > 0;
910122852Sdes	 fileid = kldnext(fileid)) {
911122852Sdes	fstat.version = sizeof(fstat);
912122852Sdes	if (kldstat(fileid, &fstat) < 0)
913122852Sdes	    continue;
914122852Sdes	if (strncmp(fstat.name, "uhub/ums", 8) == 0) {
915122852Sdes	    loaded = 1;
916122852Sdes	    break;
917122852Sdes	}
918122852Sdes	for (modid = kldfirstmod(fileid); modid > 0;
919122852Sdes	     modid = modfnext(modid)) {
920122852Sdes	    mstat.version = sizeof(mstat);
921122852Sdes	    if (modstat(modid, &mstat) < 0)
922122852Sdes		continue;
923122852Sdes	    if (strncmp(mstat.name, "uhub/ums", 8) == 0) {
924122852Sdes		loaded = 1;
925122852Sdes		break;
926122852Sdes	    }
927122852Sdes	}
928122852Sdes    }
929124339Ssobomax    if (!loaded) {
930124339Ssobomax	if (kldload("ums") != -1)
931124339Ssobomax	    return 1;
932124339Ssobomax	if (errno != EEXIST)
933124339Ssobomax	    logerr(1, "unable to load USB mouse driver");
934124339Ssobomax    }
935124339Ssobomax    return 0;
936122852Sdes}
937122852Sdes
93831604Syokotastatic void
93931604Syokotamoused(void)
94031604Syokota{
94131604Syokota    struct mouse_info mouse;
94258344Syokota    mousestatus_t action0;		/* original mouse action */
94358344Syokota    mousestatus_t action;		/* interrim buffer */
94431604Syokota    mousestatus_t action2;		/* mapped action */
94558344Syokota    struct timeval timeout;
94631604Syokota    fd_set fds;
94731604Syokota    u_char b;
948149426Spjd    pid_t mpid;
94958344Syokota    int flags;
95058344Syokota    int c;
95158344Syokota    int i;
95231604Syokota
95331604Syokota    if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
95495629Siedowse	logerr(1, "cannot open /dev/consolectl");
95531604Syokota
95695629Siedowse    if (!nodaemon && !background) {
957150214Spjd	pfh = pidfile_open(pidfile, 0600, &mpid);
958149426Spjd	if (pfh == NULL) {
959149426Spjd	    if (errno == EEXIST)
960149426Spjd		logerrx(1, "moused already running, pid: %d", mpid);
961149426Spjd	    logwarn("cannot open pid file");
962149426Spjd	}
96331604Syokota	if (daemon(0, 0)) {
964149426Spjd	    int saved_errno = errno;
965149426Spjd	    pidfile_remove(pfh);
966149426Spjd	    errno = saved_errno;
96795629Siedowse	    logerr(1, "failed to become a daemon");
96831604Syokota	} else {
96931604Syokota	    background = TRUE;
970149426Spjd	    pidfile_write(pfh);
97116566Ssos	}
97295629Siedowse    }
97316566Ssos
97431604Syokota    /* clear mouse data */
97558344Syokota    bzero(&action0, sizeof(action0));
97631604Syokota    bzero(&action, sizeof(action));
97731604Syokota    bzero(&action2, sizeof(action2));
97831604Syokota    bzero(&mouse, sizeof(mouse));
97958344Syokota    mouse_button_state = S0;
98058344Syokota    gettimeofday(&mouse_button_state_tv, NULL);
98179430Siedowse    mouse_move_delayed = 0;
98258344Syokota    for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
98358344Syokota	bstate[i].count = 0;
98458344Syokota	bstate[i].tv = mouse_button_state_tv;
98558344Syokota    }
98658344Syokota    for (i = 0; i < sizeof(zstate)/sizeof(zstate[0]); ++i) {
98758344Syokota	zstate[i].count = 0;
98858344Syokota	zstate[i].tv = mouse_button_state_tv;
98958344Syokota    }
99031604Syokota
99131604Syokota    /* choose which ioctl command to use */
99231604Syokota    mouse.operation = MOUSE_MOTION_EVENT;
99331604Syokota    extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0);
99431604Syokota
99531604Syokota    /* process mouse data */
99658344Syokota    timeout.tv_sec = 0;
99758344Syokota    timeout.tv_usec = 20000;		/* 20 msec */
99831604Syokota    for (;;) {
99931604Syokota
100021885Ssos	FD_ZERO(&fds);
100131604Syokota	FD_SET(rodent.mfd, &fds);
100258344Syokota	if (rodent.mremsfd >= 0)
100358344Syokota	    FD_SET(rodent.mremsfd, &fds);
100458344Syokota	if (rodent.mremcfd >= 0)
100558344Syokota	    FD_SET(rodent.mremcfd, &fds);
100636991Sahasty
100758344Syokota	c = select(FD_SETSIZE, &fds, NULL, NULL,
100858344Syokota		   (rodent.flags & Emulate3Button) ? &timeout : NULL);
100958344Syokota	if (c < 0) {                    /* error */
101095629Siedowse	    logwarn("failed to read from mouse");
101136991Sahasty	    continue;
101258344Syokota	} else if (c == 0) {            /* timeout */
101358344Syokota	    /* assert(rodent.flags & Emulate3Button) */
101458344Syokota	    action0.button = action0.obutton;
101558344Syokota	    action0.dx = action0.dy = action0.dz = 0;
101658344Syokota	    action0.flags = flags = 0;
101758344Syokota	    if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) {
101858344Syokota		if (debug > 2)
101958344Syokota		    debug("flags:%08x buttons:%08x obuttons:%08x",
102058344Syokota			  action.flags, action.button, action.obutton);
102158344Syokota	    } else {
102258344Syokota		action0.obutton = action0.button;
102358344Syokota		continue;
102458344Syokota	    }
102558344Syokota	} else {
102658344Syokota	    /*  MouseRemote client connect/disconnect  */
102758344Syokota	    if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) {
102858344Syokota		mremote_clientchg(TRUE);
102958344Syokota		continue;
103058344Syokota	    }
103158344Syokota	    if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) {
103258344Syokota		mremote_clientchg(FALSE);
103358344Syokota		continue;
103458344Syokota	    }
103558344Syokota	    /* mouse movement */
103658344Syokota	    if (read(rodent.mfd, &b, 1) == -1) {
103758344Syokota		if (errno == EWOULDBLOCK)
103858344Syokota		    continue;
103958344Syokota		else
104058344Syokota		    return;
104158344Syokota	    }
104258344Syokota	    if ((flags = r_protocol(b, &action0)) == 0)
104358344Syokota		continue;
1044136372Sphilip
1045148161Sphilip	    if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) {
1046136372Sphilip		/* Allow middle button drags to scroll up and down */
1047136372Sphilip		if (action0.button == MOUSE_BUTTON2DOWN) {
1048136372Sphilip		    if (scroll_state == SCROLL_NOTSCROLLING) {
1049136372Sphilip			scroll_state = SCROLL_PREPARE;
1050136372Sphilip			debug("PREPARING TO SCROLL");
1051136372Sphilip		    }
1052136372Sphilip		    debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1053136372Sphilip			  action.flags, action.button, action.obutton);
1054136372Sphilip		} else {
1055136372Sphilip		    debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1056136372Sphilip			  action.flags, action.button, action.obutton);
1057136372Sphilip
1058136372Sphilip		    /* This isn't a middle button down... move along... */
1059136372Sphilip		    if (scroll_state == SCROLL_SCROLLING) {
1060136372Sphilip			/*
1061136372Sphilip			 * We were scrolling, someone let go of button 2.
1062136372Sphilip			 * Now turn autoscroll off.
1063136372Sphilip			 */
1064136372Sphilip			scroll_state = SCROLL_NOTSCROLLING;
1065136372Sphilip			debug("DONE WITH SCROLLING / %d", scroll_state);
1066136372Sphilip		    } else if (scroll_state == SCROLL_PREPARE) {
1067136372Sphilip			mousestatus_t newaction = action0;
1068136372Sphilip
1069136372Sphilip			/* We were preparing to scroll, but we never moved... */
1070136372Sphilip			r_timestamp(&action0);
1071136372Sphilip			r_statetrans(&action0, &newaction,
1072136372Sphilip				     A(newaction.button & MOUSE_BUTTON1DOWN,
1073136372Sphilip				       action0.button & MOUSE_BUTTON3DOWN));
1074136372Sphilip
1075136372Sphilip			/* Send middle down */
1076136372Sphilip			newaction.button = MOUSE_BUTTON2DOWN;
1077136372Sphilip			r_click(&newaction);
1078136372Sphilip
1079136372Sphilip			/* Send middle up */
1080136372Sphilip			r_timestamp(&newaction);
1081136372Sphilip			newaction.obutton = newaction.button;
1082136372Sphilip			newaction.button = action0.button;
1083136372Sphilip			r_click(&newaction);
1084136372Sphilip		    }
1085136372Sphilip		}
1086136372Sphilip	    }
1087136372Sphilip
108858344Syokota	    r_timestamp(&action0);
1089122605Sdes	    r_statetrans(&action0, &action,
1090122605Sdes			 A(action0.button & MOUSE_BUTTON1DOWN,
1091122605Sdes			   action0.button & MOUSE_BUTTON3DOWN));
109258344Syokota	    debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
109358344Syokota		  action.button, action.obutton);
109436991Sahasty	}
109558344Syokota	action0.obutton = action0.button;
109658344Syokota	flags &= MOUSE_POSCHANGED;
109758344Syokota	flags |= action.obutton ^ action.button;
109858344Syokota	action.flags = flags;
109936991Sahasty
110058344Syokota	if (flags) {			/* handler detected action */
110131604Syokota	    r_map(&action, &action2);
110231604Syokota	    debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
110331604Syokota		action2.button, action2.dx, action2.dy, action2.dz);
110431604Syokota
1105148161Sphilip	    if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) {
1106136372Sphilip		/*
1107136372Sphilip		 * If *only* the middle button is pressed AND we are moving
1108136372Sphilip		 * the stick/trackpoint/nipple, scroll!
1109136372Sphilip		 */
1110136372Sphilip		if (scroll_state == SCROLL_PREPARE) {
1111136372Sphilip		    /* Ok, Set we're really scrolling now.... */
1112136372Sphilip		    if (action2.dy || action2.dx)
1113136372Sphilip			scroll_state = SCROLL_SCROLLING;
1114136372Sphilip		}
1115136372Sphilip		if (scroll_state == SCROLL_SCROLLING) {
1116148161Sphilip			 if (rodent.flags & VirtualScroll) {
1117148161Sphilip				 scroll_movement += action2.dy;
1118148161Sphilip				 debug("SCROLL: %d", scroll_movement);
1119136372Sphilip
1120148161Sphilip			    if (scroll_movement < -rodent.scrollthreshold) {
1121148161Sphilip				/* Scroll down */
1122148161Sphilip				action2.dz = -1;
1123148161Sphilip				scroll_movement = 0;
1124148161Sphilip			    }
1125148161Sphilip			    else if (scroll_movement > rodent.scrollthreshold) {
1126148161Sphilip				/* Scroll up */
1127148161Sphilip				action2.dz = 1;
1128148161Sphilip				scroll_movement = 0;
1129148161Sphilip			    }
1130148161Sphilip			 }
1131148161Sphilip			 if (rodent.flags & HVirtualScroll) {
1132148161Sphilip				 hscroll_movement += action2.dx;
1133148161Sphilip				 debug("HORIZONTAL SCROLL: %d", hscroll_movement);
1134136372Sphilip
1135148161Sphilip				 if (hscroll_movement < -rodent.scrollthreshold) {
1136148161Sphilip					 action2.dz = -2;
1137148161Sphilip					 hscroll_movement = 0;
1138148161Sphilip				 }
1139148161Sphilip				 else if (hscroll_movement > rodent.scrollthreshold) {
1140148161Sphilip					 action2.dz = 2;
1141148161Sphilip					 hscroll_movement = 0;
1142148161Sphilip				 }
1143148161Sphilip			 }
1144148161Sphilip
1145136372Sphilip		    /* Don't move while scrolling */
1146136372Sphilip		    action2.dx = action2.dy = 0;
1147136372Sphilip		}
1148136372Sphilip	    }
1149136372Sphilip
1150150310Sphilip	    if (drift_terminate) {
1151150310Sphilip		if (flags != MOUSE_POSCHANGED || action.dz || action2.dz)
1152150310Sphilip		    drift_last_activity = drift_current_tv;
1153150310Sphilip		else {
1154150310Sphilip		    /* X or/and Y movement only - possibly drift */
1155150310Sphilip		    timersub(&drift_current_tv,&drift_last_activity,&drift_tmp);
1156150310Sphilip		    if (timercmp(&drift_tmp, &drift_after_tv, >)) {
1157150310Sphilip			timersub(&drift_current_tv, &drift_since, &drift_tmp);
1158150310Sphilip			if (timercmp(&drift_tmp, &drift_time_tv, <)) {
1159150310Sphilip			    drift_last.x += action2.dx;
1160150310Sphilip			    drift_last.y += action2.dy;
1161150310Sphilip			} else {
1162150310Sphilip			    /* discard old accumulated steps (drift) */
1163150310Sphilip			    if (timercmp(&drift_tmp, &drift_2time_tv, >))
1164150310Sphilip				drift_previous.x = drift_previous.y = 0;
1165150310Sphilip			    else
1166150310Sphilip				drift_previous = drift_last;
1167150310Sphilip			    drift_last.x = action2.dx;
1168150310Sphilip			    drift_last.y = action2.dy;
1169150310Sphilip			    drift_since = drift_current_tv;
1170150310Sphilip			}
1171150310Sphilip			if (abs(drift_last.x) + abs(drift_last.y)
1172150310Sphilip			  > drift_distance) {
1173150310Sphilip			    /* real movement, pass all accumulated steps */
1174150310Sphilip			    action2.dx = drift_previous.x + drift_last.x;
1175150310Sphilip			    action2.dy = drift_previous.y + drift_last.y;
1176150310Sphilip			    /* and reset accumulators */
1177150310Sphilip			    timerclear(&drift_since);
1178150310Sphilip			    drift_last.x = drift_last.y = 0;
1179150310Sphilip			    /* drift_previous will be cleared at next movement*/
1180150310Sphilip			    drift_last_activity = drift_current_tv;
1181150310Sphilip			} else {
1182150310Sphilip			    continue;   /* don't pass current movement to
1183150310Sphilip					 * console driver */
1184150310Sphilip			}
1185150310Sphilip		    }
1186150310Sphilip		}
1187150310Sphilip	    }
1188150310Sphilip
118931604Syokota	    if (extioctl) {
1190136372Sphilip		/* Defer clicks until we aren't VirtualScroll'ing. */
1191136372Sphilip		if (scroll_state == SCROLL_NOTSCROLLING)
1192136372Sphilip		    r_click(&action2);
1193136372Sphilip
1194122605Sdes		if (action2.flags & MOUSE_POSCHANGED) {
1195122605Sdes		    mouse.operation = MOUSE_MOTION_EVENT;
1196122605Sdes		    mouse.u.data.buttons = action2.button;
1197122605Sdes		    mouse.u.data.x = action2.dx * rodent.accelx;
1198122605Sdes		    mouse.u.data.y = action2.dy * rodent.accely;
1199122605Sdes		    mouse.u.data.z = action2.dz;
120031604Syokota		    if (debug < 2)
1201153070Sphilip			if (!paused)
1202153070Sphilip				ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1203122605Sdes		}
120431604Syokota	    } else {
1205122605Sdes		mouse.operation = MOUSE_ACTION;
1206122605Sdes		mouse.u.data.buttons = action2.button;
1207122605Sdes		mouse.u.data.x = action2.dx * rodent.accelx;
1208122605Sdes		mouse.u.data.y = action2.dy * rodent.accely;
1209122605Sdes		mouse.u.data.z = action2.dz;
121031604Syokota		if (debug < 2)
1211153070Sphilip		    if (!paused)
1212153070Sphilip			ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
121331604Syokota	    }
121431604Syokota
1215108533Sschweikh	    /*
1216108533Sschweikh	     * If the Z axis movement is mapped to an imaginary physical
121731604Syokota	     * button, we need to cook up a corresponding button `up' event
121831604Syokota	     * after sending a button `down' event.
121931604Syokota	     */
1220122605Sdes	    if ((rodent.zmap[0] > 0) && (action.dz != 0)) {
122131604Syokota		action.obutton = action.button;
122231604Syokota		action.dx = action.dy = action.dz = 0;
1223122605Sdes		r_map(&action, &action2);
1224122605Sdes		debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
122531604Syokota		    action2.button, action2.dx, action2.dy, action2.dz);
122631604Syokota
1227122605Sdes		if (extioctl) {
1228122605Sdes		    r_click(&action2);
1229122605Sdes		} else {
1230122605Sdes		    mouse.operation = MOUSE_ACTION;
1231122605Sdes		    mouse.u.data.buttons = action2.button;
123231604Syokota		    mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
123331604Syokota		    if (debug < 2)
1234153070Sphilip			if (!paused)
1235153070Sphilip			    ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1236122605Sdes		}
123731604Syokota	    }
123816566Ssos	}
123916566Ssos    }
124031604Syokota    /* NOT REACHED */
1241122605Sdes}
124216566Ssos
124331604Syokotastatic void
124431604Syokotahup(int sig)
124531604Syokota{
124631604Syokota    longjmp(env, 1);
124731604Syokota}
124816566Ssos
1249122605Sdesstatic void
125036991Sahastycleanup(int sig)
125136991Sahasty{
125236991Sahasty    if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM)
125336991Sahasty	unlink(_PATH_MOUSEREMOTE);
125436991Sahasty    exit(0);
125536991Sahasty}
125636991Sahasty
1257153070Sphilipstatic void
1258153070Sphilippause_mouse(int sig)
1259153070Sphilip{
1260153070Sphilip    paused = !paused;
1261153070Sphilip}
1262153070Sphilip
126316566Ssos/**
126416566Ssos ** usage
126516566Ssos **
126616566Ssos ** Complain, and free the CPU for more worthy tasks
126716566Ssos **/
126831604Syokotastatic void
126916566Ssosusage(void)
127016566Ssos{
1271150310Sphilip    fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
127258344Syokota	"usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
1273150310Sphilip	"              [-VH [-U threshold]] [-a X[,Y]] [-C threshold] [-m N=M] [-w N]",
1274150310Sphilip	"              [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]]",
1275150310Sphilip	"              [-T distance[,time[,after]]] -p <port>",
127681364Sdougb	"       moused [-d] -i <port|if|type|model|all> -p <port>");
127716566Ssos    exit(1);
127816566Ssos}
127916566Ssos
128095629Siedowse/*
128195629Siedowse * Output an error message to syslog or stderr as appropriate. If
128295629Siedowse * `errnum' is non-zero, append its string form to the message.
128395629Siedowse */
128495629Siedowsestatic void
128595629Siedowselog_or_warn(int log_pri, int errnum, const char *fmt, ...)
128695629Siedowse{
128795629Siedowse	va_list ap;
128895629Siedowse	char buf[256];
128995629Siedowse
129095629Siedowse	va_start(ap, fmt);
129195629Siedowse	vsnprintf(buf, sizeof(buf), fmt, ap);
129295629Siedowse	va_end(ap);
129395629Siedowse	if (errnum) {
129495629Siedowse		strlcat(buf, ": ", sizeof(buf));
129595629Siedowse		strlcat(buf, strerror(errnum), sizeof(buf));
129695629Siedowse	}
129795629Siedowse
129895629Siedowse	if (background)
129995629Siedowse		syslog(log_pri, "%s", buf);
130095629Siedowse	else
130195629Siedowse		warnx("%s", buf);
130295629Siedowse}
130395629Siedowse
130416566Ssos/**
130516566Ssos ** Mouse interface code, courtesy of XFree86 3.1.2.
130616566Ssos **
130716566Ssos ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
130816566Ssos ** to clean, reformat and rationalise naming, it's quite possible that
130916566Ssos ** some things in here have been broken.
131016566Ssos **
131116566Ssos ** I hope not 8)
131216566Ssos **
131316566Ssos ** The following code is derived from a module marked :
131416566Ssos **/
131516566Ssos
131616566Ssos/* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
131716566Ssos/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
131816566Ssos 17:03:40 dawes Exp $ */
131916566Ssos/*
132016566Ssos *
132116566Ssos * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
132216566Ssos * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
132316566Ssos *
132416566Ssos * Permission to use, copy, modify, distribute, and sell this software and its
132516566Ssos * documentation for any purpose is hereby granted without fee, provided that
132616566Ssos * the above copyright notice appear in all copies and that both that
132716566Ssos * copyright notice and this permission notice appear in supporting
132816566Ssos * documentation, and that the names of Thomas Roell and David Dawes not be
132916566Ssos * used in advertising or publicity pertaining to distribution of the
133016566Ssos * software without specific, written prior permission.  Thomas Roell
133116566Ssos * and David Dawes makes no representations about the suitability of this
133216566Ssos * software for any purpose.  It is provided "as is" without express or
133316566Ssos * implied warranty.
133416566Ssos *
133516566Ssos * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
133616566Ssos * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
133716566Ssos * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
133816566Ssos * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
133916566Ssos * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
134016566Ssos * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
134116566Ssos * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
134216566Ssos *
134316566Ssos */
134416566Ssos
134531604Syokota/**
134631604Syokota ** GlidePoint support from XFree86 3.2.
134731604Syokota ** Derived from the module:
134831604Syokota **/
134916566Ssos
135031604Syokota/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
135131604Syokota/* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
135231604Syokota
135331604Syokota/* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
135431604Syokotastatic unsigned char proto[][7] = {
135531604Syokota    /*  hd_mask hd_id   dp_mask dp_id   bytes b4_mask b4_id */
1356122605Sdes    {	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* MicroSoft */
135731604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* MouseSystems */
135831604Syokota    {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* Logitech */
135931604Syokota    {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MMSeries */
1360122605Sdes    {	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* MouseMan */
136131604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* Bus */
136231604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* InPort */
136331604Syokota    {	0xc0,	0x00,	0x00,	0x00,	3,    0x00,  0xff }, /* PS/2 mouse */
136431604Syokota    {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MM HitTablet */
1365122605Sdes    {	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* GlidePoint */
1366122605Sdes    {	0x40,	0x40,	0x40,	0x00,	3,   ~0x3f,  0x00 }, /* IntelliMouse */
1367122605Sdes    {	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* ThinkingMouse */
136831604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* sysmouse */
1369122605Sdes    {	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* X10 MouseRem */
137041271Syokota    {	0x80,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* KIDSPAD */
137149967Syokota    {	0xc3,	0xc0,	0x00,	0x00,	6,    0x00,  0xff }, /* VersaPad */
137293071Swill    {	0x00,	0x00,	0x00,	0x00,	1,    0x00,  0xff }, /* JogDial */
137331604Syokota#if notyet
137431604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,   ~0x2f,  0x10 }, /* Mariqua */
137531604Syokota#endif
137631604Syokota};
137731604Syokotastatic unsigned char cur_proto[7];
137831604Syokota
137931604Syokotastatic int
138031604Syokotar_identify(void)
138131604Syokota{
138231604Syokota    char pnpbuf[256];	/* PnP identifier string may be up to 256 bytes long */
138331604Syokota    pnpid_t pnpid;
138431604Syokota    symtab_t *t;
138531604Syokota    int level;
138631604Syokota    int len;
138731604Syokota
138831604Syokota    /* set the driver operation level, if applicable */
138931604Syokota    if (rodent.level < 0)
139031604Syokota	rodent.level = 1;
139131604Syokota    ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level);
139231604Syokota    rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0;
139331604Syokota
139431604Syokota    /*
1395122605Sdes     * Interrogate the driver and get some intelligence on the device...
139631604Syokota     * The following ioctl functions are not always supported by device
139731604Syokota     * drivers.  When the driver doesn't support them, we just trust the
139831604Syokota     * user to supply valid information.
139931604Syokota     */
140031604Syokota    rodent.hw.iftype = MOUSE_IF_UNKNOWN;
140131604Syokota    rodent.hw.model = MOUSE_MODEL_GENERIC;
140231604Syokota    ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw);
140331604Syokota
140431604Syokota    if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1405122605Sdes	bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
140631604Syokota    rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
140731604Syokota    rodent.mode.rate = -1;
140831604Syokota    rodent.mode.resolution = MOUSE_RES_UNKNOWN;
140931604Syokota    rodent.mode.accelfactor = 0;
141031604Syokota    rodent.mode.level = 0;
141131604Syokota    if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) {
1412122605Sdes	if ((rodent.mode.protocol == MOUSE_PROTO_UNKNOWN)
141331604Syokota	    || (rodent.mode.protocol >= sizeof(proto)/sizeof(proto[0]))) {
141431604Syokota	    logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol);
141531604Syokota	    return MOUSE_PROTO_UNKNOWN;
1416122605Sdes	} else {
141731604Syokota	    /* INPORT and BUS are the same... */
141831604Syokota	    if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
1419122605Sdes		rodent.mode.protocol = MOUSE_PROTO_BUS;
142031604Syokota	    if (rodent.mode.protocol != rodent.rtype) {
142131604Syokota		/* Hmm, the driver doesn't agree with the user... */
1422122605Sdes		if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1423122605Sdes		    logwarnx("mouse type mismatch (%s != %s), %s is assumed",
1424122605Sdes			r_name(rodent.mode.protocol), r_name(rodent.rtype),
1425122605Sdes			r_name(rodent.mode.protocol));
1426122605Sdes		rodent.rtype = rodent.mode.protocol;
1427122605Sdes		bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
142831604Syokota	    }
1429122605Sdes	}
1430122605Sdes	cur_proto[4] = rodent.mode.packetsize;
1431122605Sdes	cur_proto[0] = rodent.mode.syncmask[0];	/* header byte bit mask */
1432122605Sdes	cur_proto[1] = rodent.mode.syncmask[1];	/* header bit pattern */
143331604Syokota    }
143431604Syokota
1435108470Sschweikh    /* maybe this is a PnP mouse... */
143631604Syokota    if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) {
143731604Syokota
1438122605Sdes	if (rodent.flags & NoPnP)
1439122605Sdes	    return rodent.rtype;
144031604Syokota	if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len))
1441122605Sdes	    return rodent.rtype;
144231604Syokota
1443122605Sdes	debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
1444122605Sdes	    pnpid.neisaid, pnpid.neisaid, pnpid.eisaid,
1445122605Sdes	    pnpid.ncompat, pnpid.ncompat, pnpid.compat,
144631604Syokota	    pnpid.ndescription, pnpid.ndescription, pnpid.description);
144731604Syokota
144831604Syokota	/* we have a valid PnP serial device ID */
1449122605Sdes	rodent.hw.iftype = MOUSE_IF_SERIAL;
145031604Syokota	t = pnpproto(&pnpid);
145131604Syokota	if (t != NULL) {
1452122605Sdes	    rodent.mode.protocol = t->val;
1453122605Sdes	    rodent.hw.model = t->val2;
145431604Syokota	} else {
1455122605Sdes	    rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
145631604Syokota	}
145731604Syokota	if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
145831604Syokota	    rodent.mode.protocol = MOUSE_PROTO_BUS;
145931604Syokota
1460122605Sdes	/* make final adjustment */
146131604Syokota	if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) {
146231604Syokota	    if (rodent.mode.protocol != rodent.rtype) {
146331604Syokota		/* Hmm, the device doesn't agree with the user... */
1464122605Sdes		if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1465122605Sdes		    logwarnx("mouse type mismatch (%s != %s), %s is assumed",
1466122605Sdes			r_name(rodent.mode.protocol), r_name(rodent.rtype),
1467122605Sdes			r_name(rodent.mode.protocol));
1468122605Sdes		rodent.rtype = rodent.mode.protocol;
1469122605Sdes		bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
147031604Syokota	    }
147131604Syokota	}
147231604Syokota    }
147331604Syokota
147431604Syokota    debug("proto params: %02x %02x %02x %02x %d %02x %02x",
1475122605Sdes	cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3],
147631604Syokota	cur_proto[4], cur_proto[5], cur_proto[6]);
147731604Syokota
147831604Syokota    return rodent.rtype;
147931604Syokota}
148031604Syokota
148131604Syokotastatic char *
148231604Syokotar_if(int iftype)
148331604Syokota{
148431604Syokota    char *s;
148531604Syokota
148631604Syokota    s = gettokenname(rifs, iftype);
148731604Syokota    return (s == NULL) ? "unknown" : s;
148831604Syokota}
148931604Syokota
149031604Syokotastatic char *
149131604Syokotar_name(int type)
149231604Syokota{
1493122605Sdes    return ((type == MOUSE_PROTO_UNKNOWN)
149431604Syokota	|| (type > sizeof(rnames)/sizeof(rnames[0]) - 1))
149531604Syokota	? "unknown" : rnames[type];
149631604Syokota}
149731604Syokota
149831604Syokotastatic char *
149931604Syokotar_model(int model)
150031604Syokota{
150131604Syokota    char *s;
150231604Syokota
150331604Syokota    s = gettokenname(rmodels, model);
150431604Syokota    return (s == NULL) ? "unknown" : s;
150531604Syokota}
150631604Syokota
150731604Syokotastatic void
150816566Ssosr_init(void)
150916566Ssos{
151049967Syokota    unsigned char buf[16];	/* scrach buffer */
151131604Syokota    fd_set fds;
151231604Syokota    char *s;
151331604Syokota    char c;
151431604Syokota    int i;
151531604Syokota
151616566Ssos    /**
1517122605Sdes     ** This comment is a little out of context here, but it contains
151816566Ssos     ** some useful information...
151916566Ssos     ********************************************************************
152016566Ssos     **
152116566Ssos     ** The following lines take care of the Logitech MouseMan protocols.
152216566Ssos     **
152316566Ssos     ** NOTE: There are different versions of both MouseMan and TrackMan!
152416566Ssos     **       Hence I add another protocol P_LOGIMAN, which the user can
152516566Ssos     **       specify as MouseMan in his XF86Config file. This entry was
152616566Ssos     **       formerly handled as a special case of P_MS. However, people
152716566Ssos     **       who don't have the middle button problem, can still specify
152816566Ssos     **       Microsoft and use P_MS.
152916566Ssos     **
153016566Ssos     ** By default, these mice should use a 3 byte Microsoft protocol
153116566Ssos     ** plus a 4th byte for the middle button. However, the mouse might
153216566Ssos     ** have switched to a different protocol before we use it, so I send
153316566Ssos     ** the proper sequence just in case.
153416566Ssos     **
153516566Ssos     ** NOTE: - all commands to (at least the European) MouseMan have to
153616566Ssos     **         be sent at 1200 Baud.
153716566Ssos     **       - each command starts with a '*'.
153816566Ssos     **       - whenever the MouseMan receives a '*', it will switch back
153916566Ssos     **	 to 1200 Baud. Hence I have to select the desired protocol
154016566Ssos     **	 first, then select the baud rate.
154116566Ssos     **
154216566Ssos     ** The protocols supported by the (European) MouseMan are:
154316566Ssos     **   -  5 byte packed binary protocol, as with the Mouse Systems
154416566Ssos     **      mouse. Selected by sequence "*U".
154516566Ssos     **   -  2 button 3 byte MicroSoft compatible protocol. Selected
154616566Ssos     **      by sequence "*V".
154716566Ssos     **   -  3 button 3+1 byte MicroSoft compatible protocol (default).
154816566Ssos     **      Selected by sequence "*X".
154916566Ssos     **
155016566Ssos     ** The following baud rates are supported:
155116566Ssos     **   -  1200 Baud (default). Selected by sequence "*n".
155216566Ssos     **   -  9600 Baud. Selected by sequence "*q".
155316566Ssos     **
155416566Ssos     ** Selecting a sample rate is no longer supported with the MouseMan!
155516566Ssos     ** Some additional lines in xf86Config.c take care of ill configured
155616566Ssos     ** baud rates and sample rates. (The user will get an error.)
155716566Ssos     */
155816566Ssos
155931604Syokota    switch (rodent.rtype) {
156031604Syokota
156131604Syokota    case MOUSE_PROTO_LOGI:
1562122605Sdes	/*
156331604Syokota	 * The baud rate selection command must be sent at the current
1564122605Sdes	 * baud rate; try all likely settings
156531604Syokota	 */
156631604Syokota	setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
156731604Syokota	setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
156831604Syokota	setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
156931604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
157031604Syokota	/* select MM series data format */
157131604Syokota	write(rodent.mfd, "S", 1);
157231604Syokota	setmousespeed(rodent.baudrate, rodent.baudrate,
157331604Syokota		      rodentcflags[MOUSE_PROTO_MM]);
157431604Syokota	/* select report rate/frequency */
157531604Syokota	if      (rodent.rate <= 0)   write(rodent.mfd, "O", 1);
157631604Syokota	else if (rodent.rate <= 15)  write(rodent.mfd, "J", 1);
157731604Syokota	else if (rodent.rate <= 27)  write(rodent.mfd, "K", 1);
157831604Syokota	else if (rodent.rate <= 42)  write(rodent.mfd, "L", 1);
157931604Syokota	else if (rodent.rate <= 60)  write(rodent.mfd, "R", 1);
158031604Syokota	else if (rodent.rate <= 85)  write(rodent.mfd, "M", 1);
158131604Syokota	else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1);
158231604Syokota	else			     write(rodent.mfd, "N", 1);
158331604Syokota	break;
158431604Syokota
158531604Syokota    case MOUSE_PROTO_LOGIMOUSEMAN:
158631604Syokota	/* The command must always be sent at 1200 baud */
158731604Syokota	setmousespeed(1200, 1200, rodentcflags[rodent.rtype]);
158816566Ssos	write(rodent.mfd, "*X", 2);
158931604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
159031604Syokota	break;
159118222Speter
159231604Syokota    case MOUSE_PROTO_HITTAB:
159331604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
159418222Speter
159531604Syokota	/*
159631604Syokota	 * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
159731604Syokota	 * The tablet must be configured to be in MM mode, NO parity,
159831604Syokota	 * Binary Format.  xf86Info.sampleRate controls the sensativity
159931604Syokota	 * of the tablet.  We only use this tablet for it's 4-button puck
160031604Syokota	 * so we don't run in "Absolute Mode"
160131604Syokota	 */
160231604Syokota	write(rodent.mfd, "z8", 2);	/* Set Parity = "NONE" */
160331604Syokota	usleep(50000);
160431604Syokota	write(rodent.mfd, "zb", 2);	/* Set Format = "Binary" */
160531604Syokota	usleep(50000);
160631604Syokota	write(rodent.mfd, "@", 1);	/* Set Report Mode = "Stream" */
160731604Syokota	usleep(50000);
160831604Syokota	write(rodent.mfd, "R", 1);	/* Set Output Rate = "45 rps" */
160931604Syokota	usleep(50000);
161031604Syokota	write(rodent.mfd, "I\x20", 2);	/* Set Incrememtal Mode "20" */
161131604Syokota	usleep(50000);
161231604Syokota	write(rodent.mfd, "E", 1);	/* Set Data Type = "Relative */
161331604Syokota	usleep(50000);
161418222Speter
161531604Syokota	/* Resolution is in 'lines per inch' on the Hitachi tablet */
1616122605Sdes	if      (rodent.resolution == MOUSE_RES_LOW)		c = 'g';
161731604Syokota	else if (rodent.resolution == MOUSE_RES_MEDIUMLOW)	c = 'e';
161831604Syokota	else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH)	c = 'h';
161931604Syokota	else if (rodent.resolution == MOUSE_RES_HIGH)		c = 'd';
1620122605Sdes	else if (rodent.resolution <=   40)			c = 'g';
1621122605Sdes	else if (rodent.resolution <=  100)			c = 'd';
1622122605Sdes	else if (rodent.resolution <=  200)			c = 'e';
1623122605Sdes	else if (rodent.resolution <=  500)			c = 'h';
1624122605Sdes	else if (rodent.resolution <= 1000)			c = 'j';
1625122605Sdes	else			c = 'd';
162631604Syokota	write(rodent.mfd, &c, 1);
162731604Syokota	usleep(50000);
162818222Speter
162931604Syokota	write(rodent.mfd, "\021", 1);	/* Resume DATA output */
163031604Syokota	break;
163131604Syokota
163231604Syokota    case MOUSE_PROTO_THINK:
163331604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
163431604Syokota	/* the PnP ID string may be sent again, discard it */
163531604Syokota	usleep(200000);
163631604Syokota	i = FREAD;
163731604Syokota	ioctl(rodent.mfd, TIOCFLUSH, &i);
163831604Syokota	/* send the command to initialize the beast */
163931604Syokota	for (s = "E5E5"; *s; ++s) {
164031604Syokota	    write(rodent.mfd, s, 1);
164131604Syokota	    FD_ZERO(&fds);
164231604Syokota	    FD_SET(rodent.mfd, &fds);
164331604Syokota	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
164431604Syokota		break;
164531604Syokota	    read(rodent.mfd, &c, 1);
164631604Syokota	    debug("%c", c);
164731604Syokota	    if (c != *s)
1648122605Sdes		break;
164918222Speter	}
165031604Syokota	break;
165131604Syokota
165293071Swill    case MOUSE_PROTO_JOGDIAL:
165393071Swill	break;
165431604Syokota    case MOUSE_PROTO_MSC:
165531604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
165631604Syokota	if (rodent.flags & ClearDTR) {
165731604Syokota	   i = TIOCM_DTR;
165831604Syokota	   ioctl(rodent.mfd, TIOCMBIC, &i);
1659122605Sdes	}
1660122605Sdes	if (rodent.flags & ClearRTS) {
166131604Syokota	   i = TIOCM_RTS;
166231604Syokota	   ioctl(rodent.mfd, TIOCMBIC, &i);
1663122605Sdes	}
166431604Syokota	break;
166531604Syokota
166631726Syokota    case MOUSE_PROTO_SYSMOUSE:
166731726Syokota	if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE)
166831726Syokota	    setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1669102413Scharnier	/* FALLTHROUGH */
167031726Syokota
167131604Syokota    case MOUSE_PROTO_BUS:
167231604Syokota    case MOUSE_PROTO_INPORT:
167331604Syokota    case MOUSE_PROTO_PS2:
167431604Syokota	if (rodent.rate >= 0)
167531604Syokota	    rodent.mode.rate = rodent.rate;
167631604Syokota	if (rodent.resolution != MOUSE_RES_UNKNOWN)
167731604Syokota	    rodent.mode.resolution = rodent.resolution;
167831604Syokota	ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode);
167931604Syokota	break;
168031604Syokota
168136991Sahasty    case MOUSE_PROTO_X10MOUSEREM:
168236991Sahasty	mremote_serversetup();
168336991Sahasty	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
168436991Sahasty	break;
168536991Sahasty
168636991Sahasty
168749967Syokota    case MOUSE_PROTO_VERSAPAD:
168849967Syokota	tcsendbreak(rodent.mfd, 0);	/* send break for 400 msec */
168949967Syokota	i = FREAD;
169049967Syokota	ioctl(rodent.mfd, TIOCFLUSH, &i);
169149967Syokota	for (i = 0; i < 7; ++i) {
169249967Syokota	    FD_ZERO(&fds);
169349967Syokota	    FD_SET(rodent.mfd, &fds);
169449967Syokota	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
169549967Syokota		break;
169649967Syokota	    read(rodent.mfd, &c, 1);
169749967Syokota	    buf[i] = c;
169849967Syokota	}
169949967Syokota	debug("%s\n", buf);
170049967Syokota	if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r'))
170149967Syokota	    break;
170249967Syokota	setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
170349967Syokota	tcsendbreak(rodent.mfd, 0);	/* send break for 400 msec again */
170449967Syokota	for (i = 0; i < 7; ++i) {
170549967Syokota	    FD_ZERO(&fds);
170649967Syokota	    FD_SET(rodent.mfd, &fds);
170749967Syokota	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
170849967Syokota		break;
170949967Syokota	    read(rodent.mfd, &c, 1);
171049967Syokota	    debug("%c", c);
171149967Syokota	    if (c != buf[i])
171249967Syokota		break;
171349967Syokota	}
171449967Syokota	i = FREAD;
171549967Syokota	ioctl(rodent.mfd, TIOCFLUSH, &i);
171649967Syokota	break;
171749967Syokota
171831604Syokota    default:
171931604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
172031604Syokota	break;
172116566Ssos    }
172216566Ssos}
172316566Ssos
172431604Syokotastatic int
172531604Syokotar_protocol(u_char rBuf, mousestatus_t *act)
172616566Ssos{
172731604Syokota    /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1728122605Sdes    static int butmapmss[4] = {	/* Microsoft, MouseMan, GlidePoint,
172931604Syokota				   IntelliMouse, Thinking Mouse */
1730122605Sdes	0,
1731122605Sdes	MOUSE_BUTTON3DOWN,
1732122605Sdes	MOUSE_BUTTON1DOWN,
1733122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
173431604Syokota    };
1735122605Sdes    static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint,
173631604Syokota				    Thinking Mouse */
1737122605Sdes	0,
1738122605Sdes	MOUSE_BUTTON4DOWN,
1739122605Sdes	MOUSE_BUTTON2DOWN,
1740122605Sdes	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
174131604Syokota    };
174231604Syokota    /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
174331604Syokota    static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
174431604Syokota				       MouseMan+ */
1745122605Sdes	0,
1746122605Sdes	MOUSE_BUTTON2DOWN,
1747122605Sdes	MOUSE_BUTTON4DOWN,
1748122605Sdes	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
174931604Syokota    };
175031604Syokota    /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
1751122605Sdes    static int butmapmsc[8] = {	/* MouseSystems, MMSeries, Logitech,
175231604Syokota				   Bus, sysmouse */
1753122605Sdes	0,
1754122605Sdes	MOUSE_BUTTON3DOWN,
1755122605Sdes	MOUSE_BUTTON2DOWN,
1756122605Sdes	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
1757122605Sdes	MOUSE_BUTTON1DOWN,
1758122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
175931604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
176031604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
176131604Syokota    };
176231604Syokota    /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
176331604Syokota    static int butmapps2[8] = {	/* PS/2 */
1764122605Sdes	0,
1765122605Sdes	MOUSE_BUTTON1DOWN,
1766122605Sdes	MOUSE_BUTTON3DOWN,
1767122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1768122605Sdes	MOUSE_BUTTON2DOWN,
1769122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
177031604Syokota	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
177131604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
177231604Syokota    };
177331604Syokota    /* for Hitachi tablet */
177431604Syokota    static int butmaphit[8] = {	/* MM HitTablet */
1775122605Sdes	0,
1776122605Sdes	MOUSE_BUTTON3DOWN,
1777122605Sdes	MOUSE_BUTTON2DOWN,
1778122605Sdes	MOUSE_BUTTON1DOWN,
1779122605Sdes	MOUSE_BUTTON4DOWN,
1780122605Sdes	MOUSE_BUTTON5DOWN,
1781122605Sdes	MOUSE_BUTTON6DOWN,
1782122605Sdes	MOUSE_BUTTON7DOWN,
178331604Syokota    };
178449967Syokota    /* for serial VersaPad */
178549967Syokota    static int butmapversa[8] = { /* VersaPad */
1786122605Sdes	0,
1787122605Sdes	0,
1788122605Sdes	MOUSE_BUTTON3DOWN,
1789122605Sdes	MOUSE_BUTTON3DOWN,
1790122605Sdes	MOUSE_BUTTON1DOWN,
1791122605Sdes	MOUSE_BUTTON1DOWN,
1792122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1793122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
179449967Syokota    };
179549967Syokota    /* for PS/2 VersaPad */
179649967Syokota    static int butmapversaps2[8] = { /* VersaPad */
1797122605Sdes	0,
1798122605Sdes	MOUSE_BUTTON3DOWN,
1799122605Sdes	0,
1800122605Sdes	MOUSE_BUTTON3DOWN,
1801122605Sdes	MOUSE_BUTTON1DOWN,
1802122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1803122605Sdes	MOUSE_BUTTON1DOWN,
1804122605Sdes	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
180549967Syokota    };
180616566Ssos    static int           pBufP = 0;
180716566Ssos    static unsigned char pBuf[8];
180849967Syokota    static int		 prev_x, prev_y;
180949967Syokota    static int		 on = FALSE;
181049967Syokota    int			 x, y;
181116566Ssos
181216566Ssos    debug("received char 0x%x",(int)rBuf);
181341271Syokota    if (rodent.rtype == MOUSE_PROTO_KIDSPAD)
181441271Syokota	return kidspad(rBuf, act) ;
1815145001Smdodd    if (rodent.rtype == MOUSE_PROTO_GTCO_DIGIPAD)
1816145001Smdodd	return gtco_digipad(rBuf, act);
181716566Ssos
181816566Ssos    /*
181916566Ssos     * Hack for resyncing: We check here for a package that is:
182016566Ssos     *  a) illegal (detected by wrong data-package header)
182116566Ssos     *  b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
182216566Ssos     *  c) bad header-package
182316566Ssos     *
182416566Ssos     * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
182516566Ssos     *       -128 are allowed, but since they are very seldom we can easily
182616566Ssos     *       use them as package-header with no button pressed.
182716566Ssos     * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
182816566Ssos     *         0x80 is not valid as a header byte. For a PS/2 mouse we skip
182916566Ssos     *         checking data bytes.
183016566Ssos     *         For resyncing a PS/2 mouse we require the two most significant
183116566Ssos     *         bits in the header byte to be 0. These are the overflow bits,
183216566Ssos     *         and in case of an overflow we actually lose sync. Overflows
183316566Ssos     *         are very rare, however, and we quickly gain sync again after
183416566Ssos     *         an overflow condition. This is the best we can do. (Actually,
183516566Ssos     *         we could use bit 0x08 in the header byte for resyncing, since
183616566Ssos     *         that bit is supposed to be always on, but nobody told
183716566Ssos     *         Microsoft...)
183816566Ssos     */
183916566Ssos
184031604Syokota    if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 &&
184131604Syokota	((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80))
184216566Ssos    {
184316566Ssos	pBufP = 0;		/* skip package */
184416566Ssos    }
1845122605Sdes
184631604Syokota    if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1])
184731604Syokota	return 0;
184831604Syokota
184931604Syokota    /* is there an extra data byte? */
185031604Syokota    if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1])
185116566Ssos    {
185216566Ssos	/*
185316566Ssos	 * Hack for Logitech MouseMan Mouse - Middle button
185416566Ssos	 *
185516566Ssos	 * Unfortunately this mouse has variable length packets: the standard
185616566Ssos	 * Microsoft 3 byte packet plus an optional 4th byte whenever the
185716566Ssos	 * middle button status changes.
185816566Ssos	 *
185916566Ssos	 * We have already processed the standard packet with the movement
186016566Ssos	 * and button info.  Now post an event message with the old status
186116566Ssos	 * of the left and right buttons and the updated middle button.
186216566Ssos	 */
186316566Ssos
186416566Ssos	/*
186516566Ssos	 * Even worse, different MouseMen and TrackMen differ in the 4th
186616566Ssos	 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
186716566Ssos	 * 0x02/0x22, so I have to strip off the lower bits.
1868122605Sdes	 *
1869122605Sdes	 * [JCH-96/01/21]
1870122605Sdes	 * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
1871122605Sdes	 * and it is activated by tapping the glidepad with the finger! 8^)
1872122605Sdes	 * We map it to bit bit3, and the reverse map in xf86Events just has
1873122605Sdes	 * to be extended so that it is identified as Button 4. The lower
1874122605Sdes	 * half of the reverse-map may remain unchanged.
187516566Ssos	 */
187631604Syokota
1877122605Sdes	/*
187831604Syokota	 * [KY-97/08/03]
187972645Sasmodai	 * Receive the fourth byte only when preceding three bytes have
188031604Syokota	 * been detected (pBufP >= cur_proto[4]).  In the previous
188131604Syokota	 * versions, the test was pBufP == 0; thus, we may have mistakingly
1882122605Sdes	 * received a byte even if we didn't see anything preceding
188331604Syokota	 * the byte.
188431604Syokota	 */
188531604Syokota
188631604Syokota	if ((rBuf & cur_proto[5]) != cur_proto[6]) {
1887122605Sdes	    pBufP = 0;
188831604Syokota	    return 0;
188916566Ssos	}
189016566Ssos
189131604Syokota	switch (rodent.rtype) {
189231604Syokota#if notyet
189331604Syokota	case MOUSE_PROTO_MARIQUA:
1894122605Sdes	    /*
189531604Syokota	     * This mouse has 16! buttons in addition to the standard
189631604Syokota	     * three of them.  They return 0x10 though 0x1f in the
189731604Syokota	     * so-called `ten key' mode and 0x30 though 0x3f in the
1898122605Sdes	     * `function key' mode.  As there are only 31 bits for
189931604Syokota	     * button state (including the standard three), we ignore
190031604Syokota	     * the bit 0x20 and don't distinguish the two modes.
190131604Syokota	     */
190231604Syokota	    act->dx = act->dy = act->dz = 0;
190331604Syokota	    act->obutton = act->button;
190431604Syokota	    rBuf &= 0x1f;
190531604Syokota	    act->button = (1 << (rBuf - 13))
1906122605Sdes		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
1907122605Sdes	    /*
1908122605Sdes	     * FIXME: this is a button "down" event. There needs to be
190931604Syokota	     * a corresponding button "up" event... XXX
191031604Syokota	     */
191131604Syokota	    break;
191231604Syokota#endif /* notyet */
191393071Swill	case MOUSE_PROTO_JOGDIAL:
191493071Swill	    break;
191531604Syokota
191631604Syokota	/*
191731604Syokota	 * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
191831604Syokota	 * always send the fourth byte, whereas the fourth byte is
1919122605Sdes	 * optional for GlidePoint and ThinkingMouse. The fourth byte
1920122605Sdes	 * is also optional for MouseMan+ and FirstMouse+ in their
1921122605Sdes	 * native mode. It is always sent if they are in the IntelliMouse
192231604Syokota	 * compatible mode.
1923122605Sdes	 */
192431604Syokota	case MOUSE_PROTO_INTELLI:	/* IntelliMouse, NetMouse, Mie Mouse,
192531604Syokota					   MouseMan+ */
192631604Syokota	    act->dx = act->dy = 0;
192731604Syokota	    act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f);
192858231Syokota	    if ((act->dz >= 7) || (act->dz <= -7))
192958231Syokota		act->dz = 0;
193031604Syokota	    act->obutton = act->button;
193131604Syokota	    act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
193231604Syokota		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
193331604Syokota	    break;
193431604Syokota
193531604Syokota	default:
193631604Syokota	    act->dx = act->dy = act->dz = 0;
193731604Syokota	    act->obutton = act->button;
193831604Syokota	    act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
193931604Syokota		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
194031604Syokota	    break;
194131604Syokota	}
194231604Syokota
194331604Syokota	act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
194431604Syokota	    | (act->obutton ^ act->button);
1945122605Sdes	pBufP = 0;
194631604Syokota	return act->flags;
194716566Ssos    }
1948122605Sdes
194931604Syokota    if (pBufP >= cur_proto[4])
195031604Syokota	pBufP = 0;
195116566Ssos    pBuf[pBufP++] = rBuf;
195231604Syokota    if (pBufP != cur_proto[4])
195331604Syokota	return 0;
1954122605Sdes
195516566Ssos    /*
195616566Ssos     * assembly full package
195716566Ssos     */
195816566Ssos
195931604Syokota    debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
1960122605Sdes	cur_proto[4],
1961122605Sdes	pBuf[0], pBuf[1], pBuf[2], pBuf[3],
196231604Syokota	pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
196316566Ssos
196431604Syokota    act->dz = 0;
196531604Syokota    act->obutton = act->button;
1966122605Sdes    switch (rodent.rtype)
196716566Ssos    {
196831604Syokota    case MOUSE_PROTO_MS:		/* Microsoft */
196931604Syokota    case MOUSE_PROTO_LOGIMOUSEMAN:	/* MouseMan/TrackMan */
197036991Sahasty    case MOUSE_PROTO_X10MOUSEREM:	/* X10 MouseRemote */
197134074Syokota	act->button = act->obutton & MOUSE_BUTTON4DOWN;
197216566Ssos	if (rodent.flags & ChordMiddle)
197334074Syokota	    act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS)
1974122605Sdes		? MOUSE_BUTTON2DOWN
197531604Syokota		: butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
197616566Ssos	else
197734074Syokota	    act->button |= (act->obutton & MOUSE_BUTTON2DOWN)
197831604Syokota		| butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
1979122605Sdes
198036991Sahasty	/* Send X10 btn events to remote client (ensure -128-+127 range) */
1981122605Sdes	if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) &&
198236991Sahasty	    ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) {
198336991Sahasty	    if (rodent.mremcfd >= 0) {
1984122605Sdes		unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) |
198536991Sahasty						  (pBuf[1] & 0x3F));
1986122854Sdes		write(rodent.mremcfd, &key, 1);
198736991Sahasty	    }
198836991Sahasty	    return 0;
198936991Sahasty	}
199036991Sahasty
199196930Sknu	act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
199296930Sknu	act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
199316566Ssos	break;
199431604Syokota
199531604Syokota    case MOUSE_PROTO_GLIDEPOINT:	/* GlidePoint */
199631604Syokota    case MOUSE_PROTO_THINK:		/* ThinkingMouse */
199731604Syokota    case MOUSE_PROTO_INTELLI:		/* IntelliMouse, NetMouse, Mie Mouse,
199831604Syokota					   MouseMan+ */
199931604Syokota	act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN))
2000122605Sdes	    | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
200196930Sknu	act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
200296930Sknu	act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
200331604Syokota	break;
2004122605Sdes
200531604Syokota    case MOUSE_PROTO_MSC:		/* MouseSystems Corp */
200631604Syokota#if notyet
200731604Syokota    case MOUSE_PROTO_MARIQUA:		/* Mariqua */
200831604Syokota#endif
200931604Syokota	act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
201096930Sknu	act->dx =    (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
201196930Sknu	act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
201216566Ssos	break;
201393071Swill
201493071Swill    case MOUSE_PROTO_JOGDIAL:		/* JogDial */
201593071Swill	    if (rBuf == 0x6c)
201696930Sknu	      act->dz = -1;
201793071Swill	    if (rBuf == 0x72)
201896930Sknu	      act->dz = 1;
201993071Swill	    if (rBuf == 0x64)
202093071Swill	      act->button = MOUSE_BUTTON1DOWN;
202193071Swill	    if (rBuf == 0x75)
202293071Swill	      act->button = 0;
202393071Swill	break;
202493071Swill
202531604Syokota    case MOUSE_PROTO_HITTAB:		/* MM HitTablet */
202631604Syokota	act->button = butmaphit[pBuf[0] & 0x07];
202731604Syokota	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
202831604Syokota	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
202918222Speter	break;
203018222Speter
203131604Syokota    case MOUSE_PROTO_MM:		/* MM Series */
203231604Syokota    case MOUSE_PROTO_LOGI:		/* Logitech Mice */
203331604Syokota	act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS];
203431604Syokota	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
203531604Syokota	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
203616566Ssos	break;
2037122605Sdes
203849967Syokota    case MOUSE_PROTO_VERSAPAD:		/* VersaPad */
203949967Syokota	act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3];
204049967Syokota	act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
204149967Syokota	act->dx = act->dy = 0;
204249967Syokota	if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) {
204349967Syokota	    on = FALSE;
204449967Syokota	    break;
204549967Syokota	}
204649967Syokota	x = (pBuf[2] << 6) | pBuf[1];
204749967Syokota	if (x & 0x800)
204849967Syokota	    x -= 0x1000;
204949967Syokota	y = (pBuf[4] << 6) | pBuf[3];
205049967Syokota	if (y & 0x800)
205149967Syokota	    y -= 0x1000;
205249967Syokota	if (on) {
205349967Syokota	    act->dx = prev_x - x;
205449967Syokota	    act->dy = prev_y - y;
205549967Syokota	} else {
205649967Syokota	    on = TRUE;
205749967Syokota	}
205849967Syokota	prev_x = x;
205949967Syokota	prev_y = y;
206049967Syokota	break;
206149967Syokota
206231604Syokota    case MOUSE_PROTO_BUS:		/* Bus */
206331604Syokota    case MOUSE_PROTO_INPORT:		/* InPort */
206431604Syokota	act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
206596930Sknu	act->dx =   (signed char)pBuf[1];
206696930Sknu	act->dy = - (signed char)pBuf[2];
206716566Ssos	break;
206816566Ssos
206931604Syokota    case MOUSE_PROTO_PS2:		/* PS/2 */
207031604Syokota	act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS];
207131604Syokota	act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ?    pBuf[1] - 256  :  pBuf[1];
207231604Syokota	act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ?  -(pBuf[2] - 256) : -pBuf[2];
207331604Syokota	/*
207431604Syokota	 * Moused usually operates the psm driver at the operation level 1
207531604Syokota	 * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
2076122605Sdes	 * The following code takes effect only when the user explicitly
2077122605Sdes	 * requets the level 2 at which wheel movement and additional button
207831604Syokota	 * actions are encoded in model-dependent formats. At the level 0
207931604Syokota	 * the following code is no-op because the psm driver says the model
208031604Syokota	 * is MOUSE_MODEL_GENERIC.
208131604Syokota	 */
208231604Syokota	switch (rodent.hw.model) {
208358231Syokota	case MOUSE_MODEL_EXPLORER:
208458231Syokota	    /* wheel and additional button data is in the fourth byte */
208558231Syokota	    act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG)
208658231Syokota		? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f);
208758231Syokota	    act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN)
208858231Syokota		? MOUSE_BUTTON4DOWN : 0;
208958231Syokota	    act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN)
209058231Syokota		? MOUSE_BUTTON5DOWN : 0;
209158231Syokota	    break;
209231604Syokota	case MOUSE_MODEL_INTELLI:
209331604Syokota	case MOUSE_MODEL_NET:
209431604Syokota	    /* wheel data is in the fourth byte */
209596930Sknu	    act->dz = (signed char)pBuf[3];
209658231Syokota	    if ((act->dz >= 7) || (act->dz <= -7))
209758231Syokota		act->dz = 0;
209858231Syokota	    /* some compatible mice may have additional buttons */
209958231Syokota	    act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN)
210058231Syokota		? MOUSE_BUTTON4DOWN : 0;
210158231Syokota	    act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN)
210258231Syokota		? MOUSE_BUTTON5DOWN : 0;
210331604Syokota	    break;
210431604Syokota	case MOUSE_MODEL_MOUSEMANPLUS:
210548778Syokota	    if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
210648778Syokota		    && (abs(act->dx) > 191)
210748778Syokota		    && MOUSE_PS2PLUS_CHECKBITS(pBuf)) {
210831604Syokota		/* the extended data packet encodes button and wheel events */
210948778Syokota		switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) {
211048778Syokota		case 1:
211148778Syokota		    /* wheel data packet */
211248778Syokota		    act->dx = act->dy = 0;
211348778Syokota		    if (pBuf[2] & 0x80) {
211448778Syokota			/* horizontal roller count - ignore it XXX*/
211548778Syokota		    } else {
211648778Syokota			/* vertical roller count */
211748778Syokota			act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG)
211848778Syokota			    ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
211948778Syokota		    }
212048778Syokota		    act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
212148778Syokota			? MOUSE_BUTTON4DOWN : 0;
212248778Syokota		    act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
212348778Syokota			? MOUSE_BUTTON5DOWN : 0;
212448778Syokota		    break;
212548778Syokota		case 2:
212658231Syokota		    /* this packet type is reserved by Logitech */
212758231Syokota		    /*
212858231Syokota		     * IBM ScrollPoint Mouse uses this packet type to
212958231Syokota		     * encode both vertical and horizontal scroll movement.
213058231Syokota		     */
213158231Syokota		    act->dx = act->dy = 0;
213258231Syokota		    /* horizontal roller count */
213358231Syokota		    if (pBuf[2] & 0x0f)
213458231Syokota			act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
213558231Syokota		    /* vertical roller count */
213658231Syokota		    if (pBuf[2] & 0xf0)
213758231Syokota			act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
213858231Syokota#if 0
213958231Syokota		    /* vertical roller count */
214058231Syokota		    act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG)
214158231Syokota			? ((pBuf[2] >> 4) & 0x0f) - 16
214258231Syokota			: ((pBuf[2] >> 4) & 0x0f);
214358231Syokota		    /* horizontal roller count */
214458231Syokota		    act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG)
214558231Syokota			? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
214658231Syokota#endif
214758231Syokota		    break;
214848778Syokota		case 0:
214948778Syokota		    /* device type packet - shouldn't happen */
2150102413Scharnier		    /* FALLTHROUGH */
215148778Syokota		default:
215248778Syokota		    act->dx = act->dy = 0;
215348778Syokota		    act->button = act->obutton;
2154122605Sdes		    debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n",
215548778Syokota			  MOUSE_PS2PLUS_PACKET_TYPE(pBuf),
215648778Syokota			  pBuf[0], pBuf[1], pBuf[2]);
215748778Syokota		    break;
215848778Syokota		}
215931604Syokota	    } else {
216031604Syokota		/* preserve button states */
216131604Syokota		act->button |= act->obutton & MOUSE_EXTBUTTONS;
216231604Syokota	    }
216331604Syokota	    break;
216431604Syokota	case MOUSE_MODEL_GLIDEPOINT:
216531604Syokota	    /* `tapping' action */
216631604Syokota	    act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
216731604Syokota	    break;
216831604Syokota	case MOUSE_MODEL_NETSCROLL:
216958231Syokota	    /* three addtional bytes encode buttons and wheel events */
217058231Syokota	    act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN)
217131604Syokota		? MOUSE_BUTTON4DOWN : 0;
217258231Syokota	    act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN)
217358231Syokota		? MOUSE_BUTTON5DOWN : 0;
217431604Syokota	    act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4];
217531604Syokota	    break;
217631604Syokota	case MOUSE_MODEL_THINK:
217731604Syokota	    /* the fourth button state in the first byte */
217831604Syokota	    act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
217931604Syokota	    break;
218049967Syokota	case MOUSE_MODEL_VERSAPAD:
218149967Syokota	    act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS];
218249967Syokota	    act->button |=
218349967Syokota		(pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
218449967Syokota	    act->dx = act->dy = 0;
218549967Syokota	    if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) {
218649967Syokota		on = FALSE;
218749967Syokota		break;
218849967Syokota	    }
218949967Syokota	    x = ((pBuf[4] << 8) & 0xf00) | pBuf[1];
219049967Syokota	    if (x & 0x800)
219149967Syokota		x -= 0x1000;
219249967Syokota	    y = ((pBuf[4] << 4) & 0xf00) | pBuf[2];
219349967Syokota	    if (y & 0x800)
219449967Syokota		y -= 0x1000;
219549967Syokota	    if (on) {
219649967Syokota		act->dx = prev_x - x;
219749967Syokota		act->dy = prev_y - y;
219849967Syokota	    } else {
219949967Syokota		on = TRUE;
220049967Syokota	    }
220149967Syokota	    prev_x = x;
220249967Syokota	    prev_y = y;
220349967Syokota	    break;
220458231Syokota	case MOUSE_MODEL_4D:
220558231Syokota	    act->dx = (pBuf[1] & 0x80) ?    pBuf[1] - 256  :  pBuf[1];
220658231Syokota	    act->dy = (pBuf[2] & 0x80) ?  -(pBuf[2] - 256) : -pBuf[2];
220758231Syokota	    switch (pBuf[0] & MOUSE_4D_WHEELBITS) {
220858231Syokota	    case 0x10:
220958231Syokota		act->dz = 1;
221058231Syokota		break;
221158231Syokota	    case 0x30:
221258231Syokota		act->dz = -1;
221358231Syokota		break;
221458231Syokota	    case 0x40:	/* 2nd wheel rolling right XXX */
221558231Syokota		act->dz = 2;
221658231Syokota		break;
221758231Syokota	    case 0xc0:	/* 2nd wheel rolling left XXX */
221858231Syokota		act->dz = -2;
221958231Syokota		break;
222058231Syokota	    }
222158231Syokota	    break;
222258231Syokota	case MOUSE_MODEL_4DPLUS:
222358231Syokota	    if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) {
222458231Syokota		act->dx = act->dy = 0;
222558231Syokota		if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN)
222658231Syokota		    act->button |= MOUSE_BUTTON4DOWN;
222758231Syokota		act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG)
222858231Syokota			      ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07);
222958231Syokota	    } else {
223058231Syokota		/* preserve previous button states */
223158231Syokota		act->button |= act->obutton & MOUSE_EXTBUTTONS;
223258231Syokota	    }
223358231Syokota	    break;
223431604Syokota	case MOUSE_MODEL_GENERIC:
223531604Syokota	default:
223631604Syokota	    break;
223731604Syokota	}
223816566Ssos	break;
223931604Syokota
224031604Syokota    case MOUSE_PROTO_SYSMOUSE:		/* sysmouse */
224131604Syokota	act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
224296930Sknu	act->dx =    (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
224396930Sknu	act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
224431604Syokota	if (rodent.level == 1) {
224596930Sknu	    act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1;
224631604Syokota	    act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
224731604Syokota	}
224831604Syokota	break;
224931604Syokota
225031604Syokota    default:
225131604Syokota	return 0;
225216566Ssos    }
2253122605Sdes    /*
225431604Syokota     * We don't reset pBufP here yet, as there may be an additional data
225531604Syokota     * byte in some protocols. See above.
225631604Syokota     */
225731604Syokota
225831604Syokota    /* has something changed? */
225931604Syokota    act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
226031604Syokota	| (act->obutton ^ act->button);
226131604Syokota
226258344Syokota    return act->flags;
226358344Syokota}
226458344Syokota
226558344Syokotastatic int
226658344Syokotar_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans)
226758344Syokota{
226858344Syokota    int changed;
226958344Syokota    int flags;
227058344Syokota
227158344Syokota    a2->dx = a1->dx;
227258344Syokota    a2->dy = a1->dy;
227358344Syokota    a2->dz = a1->dz;
227458344Syokota    a2->obutton = a2->button;
227558344Syokota    a2->button = a1->button;
227658344Syokota    a2->flags = a1->flags;
227758344Syokota    changed = FALSE;
227858344Syokota
227931604Syokota    if (rodent.flags & Emulate3Button) {
228058344Syokota	if (debug > 2)
2281122605Sdes	    debug("state:%d, trans:%d -> state:%d",
228258344Syokota		  mouse_button_state, trans,
228358344Syokota		  states[mouse_button_state].s[trans]);
228479430Siedowse	/*
228579430Siedowse	 * Avoid re-ordering button and movement events. While a button
228679430Siedowse	 * event is deferred, throw away up to BUTTON2_MAXMOVE movement
228779430Siedowse	 * events to allow for mouse jitter. If more movement events
228879430Siedowse	 * occur, then complete the deferred button events immediately.
228979430Siedowse	 */
229079430Siedowse	if ((a2->dx != 0 || a2->dy != 0) &&
229179430Siedowse	    S_DELAYED(states[mouse_button_state].s[trans])) {
229279430Siedowse		if (++mouse_move_delayed > BUTTON2_MAXMOVE) {
229379430Siedowse			mouse_move_delayed = 0;
229479430Siedowse			mouse_button_state =
229579430Siedowse			    states[mouse_button_state].s[A_TIMEOUT];
229679430Siedowse			changed = TRUE;
229779432Siedowse		} else
229879430Siedowse			a2->dx = a2->dy = 0;
229979430Siedowse	} else
230079430Siedowse		mouse_move_delayed = 0;
230179430Siedowse	if (mouse_button_state != states[mouse_button_state].s[trans])
230279430Siedowse		changed = TRUE;
230379430Siedowse	if (changed)
230479430Siedowse		gettimeofday(&mouse_button_state_tv, NULL);
230558344Syokota	mouse_button_state = states[mouse_button_state].s[trans];
230658344Syokota	a2->button &=
230758344Syokota	    ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN);
230858344Syokota	a2->button &= states[mouse_button_state].mask;
230958344Syokota	a2->button |= states[mouse_button_state].buttons;
231058344Syokota	flags = a2->flags & MOUSE_POSCHANGED;
231158344Syokota	flags |= a2->obutton ^ a2->button;
231258344Syokota	if (flags & MOUSE_BUTTON2DOWN) {
231358344Syokota	    a2->flags = flags & MOUSE_BUTTON2DOWN;
231458344Syokota	    r_timestamp(a2);
231558344Syokota	}
231658344Syokota	a2->flags = flags;
231731604Syokota    }
231858344Syokota    return changed;
231916566Ssos}
232018222Speter
232131604Syokota/* phisical to logical button mapping */
232231604Syokotastatic int p2l[MOUSE_MAXBUTTON] = {
2323122605Sdes    MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
2324122605Sdes    MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
232531604Syokota    0x00000100,        0x00000200,        0x00000400,        0x00000800,
232631604Syokota    0x00001000,        0x00002000,        0x00004000,        0x00008000,
232731604Syokota    0x00010000,        0x00020000,        0x00040000,        0x00080000,
232831604Syokota    0x00100000,        0x00200000,        0x00400000,        0x00800000,
232931604Syokota    0x01000000,        0x02000000,        0x04000000,        0x08000000,
233031604Syokota    0x10000000,        0x20000000,        0x40000000,
233131604Syokota};
233231604Syokota
233331604Syokotastatic char *
233431604Syokotaskipspace(char *s)
233531604Syokota{
233631604Syokota    while(isspace(*s))
233731604Syokota	++s;
233831604Syokota    return s;
233931604Syokota}
234031604Syokota
234131604Syokotastatic int
234231604Syokotar_installmap(char *arg)
234331604Syokota{
234431604Syokota    int pbutton;
234531604Syokota    int lbutton;
234631604Syokota    char *s;
234731604Syokota
234831604Syokota    while (*arg) {
234931604Syokota	arg = skipspace(arg);
235031604Syokota	s = arg;
235131604Syokota	while (isdigit(*arg))
235231604Syokota	    ++arg;
235331604Syokota	arg = skipspace(arg);
235431604Syokota	if ((arg <= s) || (*arg != '='))
235531604Syokota	    return FALSE;
235631604Syokota	lbutton = atoi(s);
235731604Syokota
235831604Syokota	arg = skipspace(++arg);
235931604Syokota	s = arg;
236031604Syokota	while (isdigit(*arg))
236131604Syokota	    ++arg;
236231604Syokota	if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
236331604Syokota	    return FALSE;
236431604Syokota	pbutton = atoi(s);
236531604Syokota
236631604Syokota	if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
236731604Syokota	    return FALSE;
236831604Syokota	if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
236931604Syokota	    return FALSE;
237031604Syokota	p2l[pbutton - 1] = 1 << (lbutton - 1);
237158344Syokota	mstate[lbutton - 1] = &bstate[pbutton - 1];
237231604Syokota    }
237331604Syokota
237431604Syokota    return TRUE;
237531604Syokota}
237631604Syokota
237731604Syokotastatic void
237831604Syokotar_map(mousestatus_t *act1, mousestatus_t *act2)
237931604Syokota{
238031604Syokota    register int pb;
238131604Syokota    register int pbuttons;
238231604Syokota    int lbuttons;
238331604Syokota
238431604Syokota    pbuttons = act1->button;
238531604Syokota    lbuttons = 0;
238631604Syokota
238731604Syokota    act2->obutton = act2->button;
238841270Syokota    if (pbuttons & rodent.wmode) {
238941270Syokota	pbuttons &= ~rodent.wmode;
239041270Syokota	act1->dz = act1->dy;
239141270Syokota	act1->dx = 0;
239241270Syokota	act1->dy = 0;
239341270Syokota    }
239431604Syokota    act2->dx = act1->dx;
239531604Syokota    act2->dy = act1->dy;
239631604Syokota    act2->dz = act1->dz;
239731604Syokota
239858231Syokota    switch (rodent.zmap[0]) {
239931604Syokota    case 0:	/* do nothing */
240031604Syokota	break;
240131604Syokota    case MOUSE_XAXIS:
240231604Syokota	if (act1->dz != 0) {
240331604Syokota	    act2->dx = act1->dz;
240431604Syokota	    act2->dz = 0;
240531604Syokota	}
240631604Syokota	break;
240731604Syokota    case MOUSE_YAXIS:
240831604Syokota	if (act1->dz != 0) {
240931604Syokota	    act2->dy = act1->dz;
241031604Syokota	    act2->dz = 0;
241131604Syokota	}
241231604Syokota	break;
241331604Syokota    default:	/* buttons */
241458231Syokota	pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1]
241558231Syokota		    | rodent.zmap[2] | rodent.zmap[3]);
241658344Syokota	if ((act1->dz < -1) && rodent.zmap[2]) {
241758231Syokota	    pbuttons |= rodent.zmap[2];
241858344Syokota	    zstate[2].count = 1;
241958344Syokota	} else if (act1->dz < 0) {
242058231Syokota	    pbuttons |= rodent.zmap[0];
242158344Syokota	    zstate[0].count = 1;
242258344Syokota	} else if ((act1->dz > 1) && rodent.zmap[3]) {
242358231Syokota	    pbuttons |= rodent.zmap[3];
242458344Syokota	    zstate[3].count = 1;
242558344Syokota	} else if (act1->dz > 0) {
242658231Syokota	    pbuttons |= rodent.zmap[1];
242758344Syokota	    zstate[1].count = 1;
242858344Syokota	}
242931604Syokota	act2->dz = 0;
243031604Syokota	break;
243131604Syokota    }
243231604Syokota
243331604Syokota    for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
243431604Syokota	lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
243531604Syokota	pbuttons >>= 1;
243631604Syokota    }
243731604Syokota    act2->button = lbuttons;
243831604Syokota
243931604Syokota    act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
244031604Syokota	| (act2->obutton ^ act2->button);
244131604Syokota}
244231604Syokota
244331604Syokotastatic void
244458344Syokotar_timestamp(mousestatus_t *act)
244531604Syokota{
244631604Syokota    struct timeval tv;
244731604Syokota    struct timeval tv1;
244831604Syokota    struct timeval tv2;
244958344Syokota    struct timeval tv3;
245031604Syokota    int button;
245131604Syokota    int mask;
245231604Syokota    int i;
245331604Syokota
245431604Syokota    mask = act->flags & MOUSE_BUTTONS;
245558344Syokota#if 0
245631604Syokota    if (mask == 0)
245731604Syokota	return;
245858344Syokota#endif
245931604Syokota
246058344Syokota    gettimeofday(&tv1, NULL);
2461150310Sphilip    drift_current_tv = tv1;
246258344Syokota
246358344Syokota    /* double click threshold */
246431604Syokota    tv2.tv_sec = rodent.clickthreshold/1000;
246531604Syokota    tv2.tv_usec = (rodent.clickthreshold%1000)*1000;
2466122605Sdes    timersub(&tv1, &tv2, &tv);
246731604Syokota    debug("tv:  %ld %ld", tv.tv_sec, tv.tv_usec);
246858344Syokota
246958344Syokota    /* 3 button emulation timeout */
247058344Syokota    tv2.tv_sec = rodent.button2timeout/1000;
247158344Syokota    tv2.tv_usec = (rodent.button2timeout%1000)*1000;
2472122605Sdes    timersub(&tv1, &tv2, &tv3);
247358344Syokota
247431604Syokota    button = MOUSE_BUTTON1DOWN;
247531604Syokota    for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2476122605Sdes	if (mask & 1) {
2477122605Sdes	    if (act->button & button) {
2478122605Sdes		/* the button is down */
2479122605Sdes		debug("  :  %ld %ld",
248058344Syokota		    bstate[i].tv.tv_sec, bstate[i].tv.tv_usec);
248158344Syokota		if (timercmp(&tv, &bstate[i].tv, >)) {
2482122605Sdes		    bstate[i].count = 1;
2483122605Sdes		} else {
2484122605Sdes		    ++bstate[i].count;
2485122605Sdes		}
248658344Syokota		bstate[i].tv = tv1;
2487122605Sdes	    } else {
2488122605Sdes		/* the button is up */
2489122605Sdes		bstate[i].tv = tv1;
2490122605Sdes	    }
2491122605Sdes	} else {
249258344Syokota	    if (act->button & button) {
249358344Syokota		/* the button has been down */
249458344Syokota		if (timercmp(&tv3, &bstate[i].tv, >)) {
249558344Syokota		    bstate[i].count = 1;
249658344Syokota		    bstate[i].tv = tv1;
249758344Syokota		    act->flags |= button;
249858344Syokota		    debug("button %d timeout", i + 1);
249958344Syokota		}
250058344Syokota	    } else {
250158344Syokota		/* the button has been up */
250258344Syokota	    }
250358344Syokota	}
250458344Syokota	button <<= 1;
250558344Syokota	mask >>= 1;
250658344Syokota    }
250758344Syokota}
250858344Syokota
250958344Syokotastatic int
251058344Syokotar_timeout(void)
251158344Syokota{
251258344Syokota    struct timeval tv;
251358344Syokota    struct timeval tv1;
251458344Syokota    struct timeval tv2;
251558344Syokota
251659090Syokota    if (states[mouse_button_state].timeout)
251759090Syokota	return TRUE;
251858344Syokota    gettimeofday(&tv1, NULL);
251958344Syokota    tv2.tv_sec = rodent.button2timeout/1000;
252058344Syokota    tv2.tv_usec = (rodent.button2timeout%1000)*1000;
2521122605Sdes    timersub(&tv1, &tv2, &tv);
252258344Syokota    return timercmp(&tv, &mouse_button_state_tv, >);
252358344Syokota}
252458344Syokota
252558344Syokotastatic void
252658344Syokotar_click(mousestatus_t *act)
252758344Syokota{
252858344Syokota    struct mouse_info mouse;
252958344Syokota    int button;
253058344Syokota    int mask;
253158344Syokota    int i;
253258344Syokota
253358344Syokota    mask = act->flags & MOUSE_BUTTONS;
253458344Syokota    if (mask == 0)
253558344Syokota	return;
253658344Syokota
253758344Syokota    button = MOUSE_BUTTON1DOWN;
253858344Syokota    for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2539122605Sdes	if (mask & 1) {
254058344Syokota	    debug("mstate[%d]->count:%d", i, mstate[i]->count);
2541122605Sdes	    if (act->button & button) {
2542122605Sdes		/* the button is down */
2543122605Sdes		mouse.u.event.value = mstate[i]->count;
2544122605Sdes	    } else {
2545122605Sdes		/* the button is up */
2546122605Sdes		mouse.u.event.value = 0;
2547122605Sdes	    }
254831604Syokota	    mouse.operation = MOUSE_BUTTON_EVENT;
254931604Syokota	    mouse.u.event.id = button;
255031604Syokota	    if (debug < 2)
2551153070Sphilip		if (!paused)
2552153070Sphilip		    ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
255331604Syokota	    debug("button %d  count %d", i + 1, mouse.u.event.value);
2554122605Sdes	}
255531604Syokota	button <<= 1;
255631604Syokota	mask >>= 1;
255731604Syokota    }
255831604Syokota}
255931604Syokota
256018222Speter/* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
256118222Speter/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
256218222Speter/*
256318222Speter * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
256418222Speter *
256518222Speter * Permission to use, copy, modify, distribute, and sell this software and its
256618222Speter * documentation for any purpose is hereby granted without fee, provided that
256718222Speter * the above copyright notice appear in all copies and that both that
256818222Speter * copyright notice and this permission notice appear in supporting
2569122605Sdes * documentation, and that the name of David Dawes
2570122605Sdes * not be used in advertising or publicity pertaining to distribution of
257118222Speter * the software without specific, written prior permission.
2572122605Sdes * David Dawes makes no representations about the suitability of this
2573122605Sdes * software for any purpose.  It is provided "as is" without express or
257418222Speter * implied warranty.
257518222Speter *
2576122605Sdes * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
2577122605Sdes * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
2578122605Sdes * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
2579122605Sdes * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
2580122605Sdes * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
2581122605Sdes * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
258218222Speter * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
258318222Speter *
258418222Speter */
258518222Speter
258618222Speter
258731604Syokotastatic void
258831604Syokotasetmousespeed(int old, int new, unsigned cflag)
258918222Speter{
259018222Speter	struct termios tty;
259118222Speter	char *c;
259218222Speter
259318222Speter	if (tcgetattr(rodent.mfd, &tty) < 0)
259418222Speter	{
259595629Siedowse		logwarn("unable to get status of mouse fd");
259631604Syokota		return;
259718222Speter	}
259818222Speter
259918222Speter	tty.c_iflag = IGNBRK | IGNPAR;
260018222Speter	tty.c_oflag = 0;
260118222Speter	tty.c_lflag = 0;
260218222Speter	tty.c_cflag = (tcflag_t)cflag;
260318222Speter	tty.c_cc[VTIME] = 0;
260418222Speter	tty.c_cc[VMIN] = 1;
260518222Speter
260618222Speter	switch (old)
260718222Speter	{
260818222Speter	case 9600:
260918222Speter		cfsetispeed(&tty, B9600);
261018222Speter		cfsetospeed(&tty, B9600);
261118222Speter		break;
261218222Speter	case 4800:
261318222Speter		cfsetispeed(&tty, B4800);
261418222Speter		cfsetospeed(&tty, B4800);
261518222Speter		break;
261618222Speter	case 2400:
261718222Speter		cfsetispeed(&tty, B2400);
261818222Speter		cfsetospeed(&tty, B2400);
261918222Speter		break;
262018222Speter	case 1200:
262118222Speter	default:
262218222Speter		cfsetispeed(&tty, B1200);
262318222Speter		cfsetospeed(&tty, B1200);
262418222Speter	}
262518222Speter
262618222Speter	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
262718222Speter	{
262895629Siedowse		logwarn("unable to set status of mouse fd");
262931604Syokota		return;
263018222Speter	}
263118222Speter
263218222Speter	switch (new)
263318222Speter	{
263418222Speter	case 9600:
263518222Speter		c = "*q";
263618222Speter		cfsetispeed(&tty, B9600);
263718222Speter		cfsetospeed(&tty, B9600);
263818222Speter		break;
263918222Speter	case 4800:
264018222Speter		c = "*p";
264118222Speter		cfsetispeed(&tty, B4800);
264218222Speter		cfsetospeed(&tty, B4800);
264318222Speter		break;
264418222Speter	case 2400:
264518222Speter		c = "*o";
264618222Speter		cfsetispeed(&tty, B2400);
264718222Speter		cfsetospeed(&tty, B2400);
264818222Speter		break;
264918222Speter	case 1200:
265018222Speter	default:
265118222Speter		c = "*n";
265218222Speter		cfsetispeed(&tty, B1200);
265318222Speter		cfsetospeed(&tty, B1200);
265418222Speter	}
265518222Speter
2656122605Sdes	if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN
265731604Syokota	    || rodent.rtype == MOUSE_PROTO_LOGI)
265818222Speter	{
265918222Speter		if (write(rodent.mfd, c, 2) != 2)
266018222Speter		{
266195629Siedowse			logwarn("unable to write to mouse fd");
266231604Syokota			return;
266318222Speter		}
266418222Speter	}
266518222Speter	usleep(100000);
266618222Speter
266718222Speter	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
266895629Siedowse		logwarn("unable to set status of mouse fd");
266931604Syokota}
267031604Syokota
2671122605Sdes/*
2672122605Sdes * PnP COM device support
2673122605Sdes *
267431604Syokota * It's a simplistic implementation, but it works :-)
267531604Syokota * KY, 31/7/97.
267631604Syokota */
267731604Syokota
267831604Syokota/*
2679122605Sdes * Try to elicit a PnP ID as described in
2680122605Sdes * Microsoft, Hayes: "Plug and Play External COM Device Specification,
268131604Syokota * rev 1.00", 1995.
268231604Syokota *
268331604Syokota * The routine does not fully implement the COM Enumerator as par Section
268431604Syokota * 2.1 of the document.  In particular, we don't have idle state in which
2685122605Sdes * the driver software monitors the com port for dynamic connection or
2686122605Sdes * removal of a device at the port, because `moused' simply quits if no
268731604Syokota * device is found.
268831604Syokota *
2689122605Sdes * In addition, as PnP COM device enumeration procedure slightly has
269031604Syokota * changed since its first publication, devices which follow earlier
2691122605Sdes * revisions of the above spec. may fail to respond if the rev 1.0
269231604Syokota * procedure is used. XXX
269331604Syokota */
269431604Syokotastatic int
269540255Syokotapnpwakeup1(void)
269631604Syokota{
269731604Syokota    struct timeval timeout;
269831604Syokota    fd_set fds;
269931604Syokota    int i;
270031604Syokota
2701122605Sdes    /*
270231604Syokota     * This is the procedure described in rev 1.0 of PnP COM device spec.
270331604Syokota     * Unfortunately, some devices which comform to earlier revisions of
270431604Syokota     * the spec gets confused and do not return the ID string...
270531604Syokota     */
270640255Syokota    debug("PnP COM device rev 1.0 probe...");
270731604Syokota
270831604Syokota    /* port initialization (2.1.2) */
270931604Syokota    ioctl(rodent.mfd, TIOCMGET, &i);
271031604Syokota    i |= TIOCM_DTR;		/* DTR = 1 */
271131604Syokota    i &= ~TIOCM_RTS;		/* RTS = 0 */
271231604Syokota    ioctl(rodent.mfd, TIOCMSET, &i);
271340255Syokota    usleep(240000);
271431604Syokota
271540255Syokota    /*
2716122605Sdes     * The PnP COM device spec. dictates that the mouse must set DSR
2717122605Sdes     * in response to DTR (by hardware or by software) and that if DSR is
271840255Syokota     * not asserted, the host computer should think that there is no device
271941269Syokota     * at this serial port.  But some mice just don't do that...
272040255Syokota     */
272140255Syokota    ioctl(rodent.mfd, TIOCMGET, &i);
272240255Syokota    debug("modem status 0%o", i);
272340255Syokota    if ((i & TIOCM_DSR) == 0)
272440255Syokota	return FALSE;
272540255Syokota
272631604Syokota    /* port setup, 1st phase (2.1.3) */
272731604Syokota    setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
272831604Syokota    i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
272931604Syokota    ioctl(rodent.mfd, TIOCMBIC, &i);
273040255Syokota    usleep(240000);
273131604Syokota    i = TIOCM_DTR;		/* DTR = 1, RTS = 0 */
273231604Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
273340255Syokota    usleep(240000);
273431604Syokota
273531604Syokota    /* wait for response, 1st phase (2.1.4) */
273631604Syokota    i = FREAD;
273731604Syokota    ioctl(rodent.mfd, TIOCFLUSH, &i);
273831604Syokota    i = TIOCM_RTS;		/* DTR = 1, RTS = 1 */
273931604Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
274031604Syokota
274131604Syokota    /* try to read something */
274231604Syokota    FD_ZERO(&fds);
274331604Syokota    FD_SET(rodent.mfd, &fds);
274431604Syokota    timeout.tv_sec = 0;
274540255Syokota    timeout.tv_usec = 240000;
274640255Syokota    if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
274740255Syokota	debug("pnpwakeup1(): valid response in first phase.");
274840255Syokota	return TRUE;
274941269Syokota    }
275031604Syokota
275141269Syokota    /* port setup, 2nd phase (2.1.5) */
275241269Syokota    i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
275341269Syokota    ioctl(rodent.mfd, TIOCMBIC, &i);
275441269Syokota    usleep(240000);
275531604Syokota
275641269Syokota    /* wait for respose, 2nd phase (2.1.6) */
275741269Syokota    i = FREAD;
275841269Syokota    ioctl(rodent.mfd, TIOCFLUSH, &i);
275941269Syokota    i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
276041269Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
276131604Syokota
276241269Syokota    /* try to read something */
276341269Syokota    FD_ZERO(&fds);
276441269Syokota    FD_SET(rodent.mfd, &fds);
276541269Syokota    timeout.tv_sec = 0;
276641269Syokota    timeout.tv_usec = 240000;
276741269Syokota    if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
276841269Syokota	debug("pnpwakeup1(): valid response in second phase.");
276941269Syokota	return TRUE;
277031604Syokota    }
277141269Syokota
277240255Syokota    return FALSE;
277340255Syokota}
277440255Syokota
277540255Syokotastatic int
277640255Syokotapnpwakeup2(void)
277740255Syokota{
277840255Syokota    struct timeval timeout;
277940255Syokota    fd_set fds;
278040255Syokota    int i;
278140255Syokota
278231604Syokota    /*
278331604Syokota     * This is a simplified procedure; it simply toggles RTS.
278431604Syokota     */
278541269Syokota    debug("alternate probe...");
278631604Syokota
278731604Syokota    ioctl(rodent.mfd, TIOCMGET, &i);
278831604Syokota    i |= TIOCM_DTR;		/* DTR = 1 */
278931604Syokota    i &= ~TIOCM_RTS;		/* RTS = 0 */
279031604Syokota    ioctl(rodent.mfd, TIOCMSET, &i);
279140255Syokota    usleep(240000);
279231604Syokota
279331604Syokota    setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
279431604Syokota
279531604Syokota    /* wait for respose */
279631604Syokota    i = FREAD;
279731604Syokota    ioctl(rodent.mfd, TIOCFLUSH, &i);
279831604Syokota    i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
279931604Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
280031604Syokota
280131604Syokota    /* try to read something */
280231604Syokota    FD_ZERO(&fds);
280331604Syokota    FD_SET(rodent.mfd, &fds);
280431604Syokota    timeout.tv_sec = 0;
280540255Syokota    timeout.tv_usec = 240000;
280640255Syokota    if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
280740255Syokota	debug("pnpwakeup2(): valid response.");
280840255Syokota	return TRUE;
280940255Syokota    }
281041269Syokota
281140255Syokota    return FALSE;
281240255Syokota}
281331604Syokota
281440255Syokotastatic int
281540255Syokotapnpgets(char *buf)
281640255Syokota{
281740255Syokota    struct timeval timeout;
281840255Syokota    fd_set fds;
281940255Syokota    int begin;
282040255Syokota    int i;
282140255Syokota    char c;
282240255Syokota
282340255Syokota    if (!pnpwakeup1() && !pnpwakeup2()) {
282440255Syokota	/*
2825122605Sdes	 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2826122605Sdes	 * in idle state.  But, `moused' shall set DTR = RTS = 1 and proceed,
2827122605Sdes	 * assuming there is something at the port even if it didn't
282840255Syokota	 * respond to the PnP enumeration procedure.
282940255Syokota	 */
283040255Syokota	i = TIOCM_DTR | TIOCM_RTS;		/* DTR = 1, RTS = 1 */
283140255Syokota	ioctl(rodent.mfd, TIOCMBIS, &i);
283240255Syokota	return 0;
283340255Syokota    }
283440255Syokota
283531604Syokota    /* collect PnP COM device ID (2.1.7) */
283640255Syokota    begin = -1;
283731604Syokota    i = 0;
283840255Syokota    usleep(240000);	/* the mouse must send `Begin ID' within 200msec */
283931604Syokota    while (read(rodent.mfd, &c, 1) == 1) {
284031604Syokota	/* we may see "M", or "M3..." before `Begin ID' */
284140255Syokota	buf[i++] = c;
2842122605Sdes	if ((c == 0x08) || (c == 0x28)) {	/* Begin ID */
284340255Syokota	    debug("begin-id %02x", c);
284440255Syokota	    begin = i - 1;
284531604Syokota	    break;
2846122605Sdes	}
2847122605Sdes	debug("%c %02x", c, c);
284840255Syokota	if (i >= 256)
284940255Syokota	    break;
285031604Syokota    }
285140255Syokota    if (begin < 0) {
285231604Syokota	/* we haven't seen `Begin ID' in time... */
285331604Syokota	goto connect_idle;
285431604Syokota    }
285531604Syokota
285631604Syokota    ++c;			/* make it `End ID' */
285731604Syokota    for (;;) {
2858122605Sdes	FD_ZERO(&fds);
2859122605Sdes	FD_SET(rodent.mfd, &fds);
2860122605Sdes	timeout.tv_sec = 0;
2861122605Sdes	timeout.tv_usec = 240000;
2862122605Sdes	if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
286331604Syokota	    break;
286431604Syokota
286531604Syokota	read(rodent.mfd, &buf[i], 1);
2866122605Sdes	if (buf[i++] == c)	/* End ID */
286731604Syokota	    break;
286831604Syokota	if (i >= 256)
286931604Syokota	    break;
287031604Syokota    }
287140255Syokota    if (begin > 0) {
287240255Syokota	i -= begin;
287340255Syokota	bcopy(&buf[begin], &buf[0], i);
287440255Syokota    }
287531604Syokota    /* string may not be human readable... */
287640255Syokota    debug("len:%d, '%-*.*s'", i, i, i, buf);
287731604Syokota
287840255Syokota    if (buf[i - 1] == c)
287940255Syokota	return i;		/* a valid PnP string */
288040255Syokota
288131604Syokota    /*
2882122605Sdes     * According to PnP spec, we should set DTR = 1 and RTS = 0 while
288340255Syokota     * in idle state.  But, `moused' shall leave the modem control lines
288440255Syokota     * as they are. See above.
288531604Syokota     */
288631604Syokotaconnect_idle:
288740255Syokota
288840255Syokota    /* we may still have something in the buffer */
288940255Syokota    return ((i > 0) ? i : 0);
289031604Syokota}
289131604Syokota
289231604Syokotastatic int
289331604Syokotapnpparse(pnpid_t *id, char *buf, int len)
289431604Syokota{
289531604Syokota    char s[3];
289631604Syokota    int offset;
289731604Syokota    int sum = 0;
289831604Syokota    int i, j;
289931604Syokota
290031604Syokota    id->revision = 0;
290131604Syokota    id->eisaid = NULL;
290231604Syokota    id->serial = NULL;
290331604Syokota    id->class = NULL;
290431604Syokota    id->compat = NULL;
290531604Syokota    id->description = NULL;
290631604Syokota    id->neisaid = 0;
290731604Syokota    id->nserial = 0;
290831604Syokota    id->nclass = 0;
290931604Syokota    id->ncompat = 0;
291031604Syokota    id->ndescription = 0;
291131604Syokota
291240255Syokota    if ((buf[0] != 0x28) && (buf[0] != 0x08)) {
291340255Syokota	/* non-PnP mice */
291440255Syokota	switch(buf[0]) {
291540255Syokota	default:
291640255Syokota	    return FALSE;
291740255Syokota	case 'M': /* Microsoft */
291840255Syokota	    id->eisaid = "PNP0F01";
291940255Syokota	    break;
292040255Syokota	case 'H': /* MouseSystems */
292140255Syokota	    id->eisaid = "PNP0F04";
292240255Syokota	    break;
292340255Syokota	}
292440255Syokota	id->neisaid = strlen(id->eisaid);
292540255Syokota	id->class = "MOUSE";
292640255Syokota	id->nclass = strlen(id->class);
292740255Syokota	debug("non-PnP mouse '%c'", buf[0]);
292840255Syokota	return TRUE;
292940255Syokota    }
293040255Syokota
293140255Syokota    /* PnP mice */
293231604Syokota    offset = 0x28 - buf[0];
293331604Syokota
293431604Syokota    /* calculate checksum */
293531604Syokota    for (i = 0; i < len - 3; ++i) {
293631604Syokota	sum += buf[i];
293731604Syokota	buf[i] += offset;
293831604Syokota    }
293931604Syokota    sum += buf[len - 1];
294031604Syokota    for (; i < len; ++i)
294131604Syokota	buf[i] += offset;
294231604Syokota    debug("PnP ID string: '%*.*s'", len, len, buf);
294331604Syokota
294431604Syokota    /* revision */
294531604Syokota    buf[1] -= offset;
294631604Syokota    buf[2] -= offset;
294731604Syokota    id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
294831604Syokota    debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100);
294931604Syokota
295031604Syokota    /* EISA vender and product ID */
295131604Syokota    id->eisaid = &buf[3];
295231604Syokota    id->neisaid = 7;
295331604Syokota
295431604Syokota    /* option strings */
295531604Syokota    i = 10;
295631604Syokota    if (buf[i] == '\\') {
2957122605Sdes	/* device serial # */
2958122605Sdes	for (j = ++i; i < len; ++i) {
2959122605Sdes	    if (buf[i] == '\\')
296031604Syokota		break;
2961122605Sdes	}
296231604Syokota	if (i >= len)
296331604Syokota	    i -= 3;
296431604Syokota	if (i - j == 8) {
2965122605Sdes	    id->serial = &buf[j];
2966122605Sdes	    id->nserial = 8;
296718222Speter	}
296831604Syokota    }
296931604Syokota    if (buf[i] == '\\') {
2970122605Sdes	/* PnP class */
2971122605Sdes	for (j = ++i; i < len; ++i) {
2972122605Sdes	    if (buf[i] == '\\')
297331604Syokota		break;
2974122605Sdes	}
297531604Syokota	if (i >= len)
297631604Syokota	    i -= 3;
297731604Syokota	if (i > j + 1) {
2978122605Sdes	    id->class = &buf[j];
2979122605Sdes	    id->nclass = i - j;
2980122605Sdes	}
298131604Syokota    }
298231604Syokota    if (buf[i] == '\\') {
298331604Syokota	/* compatible driver */
2984122605Sdes	for (j = ++i; i < len; ++i) {
2985122605Sdes	    if (buf[i] == '\\')
298631604Syokota		break;
2987122605Sdes	}
298831604Syokota	/*
2989122605Sdes	 * PnP COM spec prior to v0.96 allowed '*' in this field,
299031604Syokota	 * it's not allowed now; just igore it.
299131604Syokota	 */
299231604Syokota	if (buf[j] == '*')
299331604Syokota	    ++j;
299431604Syokota	if (i >= len)
299531604Syokota	    i -= 3;
299631604Syokota	if (i > j + 1) {
2997122605Sdes	    id->compat = &buf[j];
2998122605Sdes	    id->ncompat = i - j;
2999122605Sdes	}
300031604Syokota    }
300131604Syokota    if (buf[i] == '\\') {
300231604Syokota	/* product description */
3003122605Sdes	for (j = ++i; i < len; ++i) {
3004122605Sdes	    if (buf[i] == ';')
300531604Syokota		break;
3006122605Sdes	}
300731604Syokota	if (i >= len)
300831604Syokota	    i -= 3;
300931604Syokota	if (i > j + 1) {
3010122605Sdes	    id->description = &buf[j];
3011122605Sdes	    id->ndescription = i - j;
3012122605Sdes	}
301331604Syokota    }
301431604Syokota
301531604Syokota    /* checksum exists if there are any optional fields */
301631604Syokota    if ((id->nserial > 0) || (id->nclass > 0)
301731604Syokota	|| (id->ncompat > 0) || (id->ndescription > 0)) {
3018122605Sdes	debug("PnP checksum: 0x%X", sum);
3019122605Sdes	sprintf(s, "%02X", sum & 0x0ff);
3020122605Sdes	if (strncmp(s, &buf[len - 3], 2) != 0) {
302131604Syokota#if 0
3022122605Sdes	    /*
3023122605Sdes	     * I found some mice do not comply with the PnP COM device
302431604Syokota	     * spec regarding checksum... XXX
302531604Syokota	     */
3026122605Sdes	    logwarnx("PnP checksum error", 0);
302731604Syokota	    return FALSE;
302831604Syokota#endif
3029122605Sdes	}
303031604Syokota    }
303131604Syokota
303231604Syokota    return TRUE;
303318222Speter}
303431604Syokota
303531604Syokotastatic symtab_t *
303631604Syokotapnpproto(pnpid_t *id)
303731604Syokota{
303831604Syokota    symtab_t *t;
303931604Syokota    int i, j;
304031604Syokota
304131604Syokota    if (id->nclass > 0)
3042122854Sdes	if (strncmp(id->class, "MOUSE", id->nclass) != 0 &&
3043122854Sdes	    strncmp(id->class, "TABLET", id->nclass) != 0)
304431604Syokota	    /* this is not a mouse! */
304531604Syokota	    return NULL;
304631604Syokota
304731604Syokota    if (id->neisaid > 0) {
3048122605Sdes	t = gettoken(pnpprod, id->eisaid, id->neisaid);
304931604Syokota	if (t->val != MOUSE_PROTO_UNKNOWN)
3050122605Sdes	    return t;
305131604Syokota    }
305231604Syokota
305331604Syokota    /*
305431604Syokota     * The 'Compatible drivers' field may contain more than one
305531604Syokota     * ID separated by ','.
305631604Syokota     */
305731604Syokota    if (id->ncompat <= 0)
305831604Syokota	return NULL;
305931604Syokota    for (i = 0; i < id->ncompat; ++i) {
3060122605Sdes	for (j = i; id->compat[i] != ','; ++i)
3061122605Sdes	    if (i >= id->ncompat)
306231604Syokota		break;
3063122605Sdes	if (i > j) {
3064122605Sdes	    t = gettoken(pnpprod, id->compat + j, i - j);
306531604Syokota	    if (t->val != MOUSE_PROTO_UNKNOWN)
3066122605Sdes		return t;
306731604Syokota	}
306831604Syokota    }
306931604Syokota
307031604Syokota    return NULL;
307131604Syokota}
307231604Syokota
307331604Syokota/* name/val mapping */
307431604Syokota
307531604Syokotastatic symtab_t *
307631604Syokotagettoken(symtab_t *tab, char *s, int len)
307731604Syokota{
307831604Syokota    int i;
307931604Syokota
308031604Syokota    for (i = 0; tab[i].name != NULL; ++i) {
308131604Syokota	if (strncmp(tab[i].name, s, len) == 0)
308231604Syokota	    break;
308331604Syokota    }
308431604Syokota    return &tab[i];
308531604Syokota}
308631604Syokota
308731604Syokotastatic char *
308831604Syokotagettokenname(symtab_t *tab, int val)
308931604Syokota{
309031604Syokota    int i;
309131604Syokota
309231604Syokota    for (i = 0; tab[i].name != NULL; ++i) {
309331604Syokota	if (tab[i].val == val)
309431604Syokota	    return tab[i].name;
309531604Syokota    }
309631604Syokota    return NULL;
309731604Syokota}
309836991Sahasty
309941271Syokota
310041271Syokota/*
310141271Syokota * code to read from the Genius Kidspad tablet.
310241271Syokota
310341271SyokotaThe tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005,
310441271Syokotaand to pre-pnp probes (RTS toggle) with 'T' (tablet ?)
310541271Syokota9600, 8 bit, parity odd.
310641271Syokota
310741271SyokotaThe tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains
310841271Syokotathe proximity, tip and button info:
310941271Syokota   (byte0 & 0x1)	true = tip pressed
311041271Syokota   (byte0 & 0x2)	true = button pressed
311141271Syokota   (byte0 & 0x40)	false = pen in proximity of tablet.
311241271Syokota
311341271SyokotaThe next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid).
311441271Syokota
311541271SyokotaOnly absolute coordinates are returned, so we use the following approach:
311641271Syokotawe store the last coordinates sent when the pen went out of the tablet,
311741271Syokota
311841271Syokota
311941271Syokota *
312041271Syokota */
312141271Syokota
312241271Syokotatypedef enum {
312341271Syokota    S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP
312441271Syokota} k_status ;
312541271Syokota
312641271Syokotastatic int
312741271Syokotakidspad(u_char rxc, mousestatus_t *act)
312841271Syokota{
312995629Siedowse    static int buf[5];
313041271Syokota    static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1 ;
313141271Syokota    static k_status status = S_IDLE ;
313241271Syokota    static struct timeval old, now ;
313341271Syokota
313478737Sdd    int x, y ;
313541271Syokota
3136122854Sdes    if (buflen > 0 && (rxc & 0x80)) {
313741271Syokota	fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc);
313841271Syokota	buflen = 0 ;
313941271Syokota    }
3140122854Sdes    if (buflen == 0 && (rxc & 0xb8) != 0xb8) {
314141271Syokota	fprintf(stderr, "invalid code 0 0x%x\n", rxc);
314241271Syokota	return 0 ; /* invalid code, no action */
314341271Syokota    }
314441271Syokota    buf[buflen++] = rxc ;
314541271Syokota    if (buflen < 5)
314641271Syokota	return 0 ;
314741271Syokota
314841271Syokota    buflen = 0 ; /* for next time... */
314941271Syokota
315041271Syokota    x = buf[1]+128*(buf[2] - 7) ;
315141271Syokota    if (x < 0) x = 0 ;
315241271Syokota    y = 28*128 - (buf[3] + 128* (buf[4] - 7)) ;
315341271Syokota    if (y < 0) y = 0 ;
315441271Syokota
315541271Syokota    x /= 8 ;
315641271Syokota    y /= 8 ;
315741271Syokota
315841271Syokota    act->flags = 0 ;
315941271Syokota    act->obutton = act->button ;
316041271Syokota    act->dx = act->dy = act->dz = 0 ;
316141271Syokota    gettimeofday(&now, NULL);
3162122854Sdes    if (buf[0] & 0x40) /* pen went out of reach */
316341271Syokota	status = S_IDLE ;
316441271Syokota    else if (status == S_IDLE) { /* pen is newly near the tablet */
316541271Syokota	act->flags |= MOUSE_POSCHANGED ; /* force update */
316641271Syokota	status = S_PROXY ;
316741271Syokota	x_prev = x ;
316841271Syokota	y_prev = y ;
316941271Syokota    }
317041271Syokota    old = now ;
317141271Syokota    act->dx = x - x_prev ;
317241271Syokota    act->dy = y - y_prev ;
317341271Syokota    if (act->dx || act->dy)
317441271Syokota	act->flags |= MOUSE_POSCHANGED ;
317541271Syokota    x_prev = x ;
317641271Syokota    y_prev = y ;
317741271Syokota    if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */
317841271Syokota	act->button = 0 ;
3179122854Sdes	if (buf[0] & 0x01) /* tip pressed */
318041271Syokota	    act->button |= MOUSE_BUTTON1DOWN ;
3181122854Sdes	if (buf[0] & 0x02) /* button pressed */
318241271Syokota	    act->button |= MOUSE_BUTTON2DOWN ;
318341271Syokota	act->flags |= MOUSE_BUTTONSCHANGED ;
318441271Syokota    }
318541271Syokota    b_prev = buf[0] ;
318641271Syokota    return act->flags ;
318741271Syokota}
318841271Syokota
3189145001Smdoddstatic int
3190145001Smdoddgtco_digipad (u_char rxc, mousestatus_t *act)
3191145001Smdodd{
3192145001Smdodd	static u_char buf[5];
3193145001Smdodd 	static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1 ;
3194145001Smdodd	static k_status status = S_IDLE ;
3195145001Smdodd        int x, y;
3196145001Smdodd
3197145001Smdodd#define	GTCO_HEADER	0x80
3198145001Smdodd#define	GTCO_PROXIMITY	0x40
3199145001Smdodd#define	GTCO_START	(GTCO_HEADER|GTCO_PROXIMITY)
3200145001Smdodd#define	GTCO_BUTTONMASK	0x3c
3201145001Smdodd
3202145001Smdodd
3203145001Smdodd	if (buflen > 0 && ((rxc & GTCO_HEADER) != GTCO_HEADER)) {
3204145001Smdodd		fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc);
3205145001Smdodd		buflen = 0 ;
3206145001Smdodd	}
3207145001Smdodd	if (buflen == 0 && (rxc & GTCO_START) != GTCO_START) {
3208145001Smdodd		fprintf(stderr, "invalid code 0 0x%x\n", rxc);
3209145001Smdodd		return 0 ; /* invalid code, no action */
3210145001Smdodd	}
3211145001Smdodd
3212145001Smdodd	buf[buflen++] = rxc ;
3213145001Smdodd	if (buflen < 5)
3214145001Smdodd		return 0 ;
3215145001Smdodd
3216145001Smdodd	buflen = 0 ; /* for next time... */
3217145001Smdodd
3218145001Smdodd	x = ((buf[2] & ~GTCO_START) << 6 | (buf[1] & ~GTCO_START));
3219145001Smdodd	y = 4768 - ((buf[4] & ~GTCO_START) << 6 | (buf[3] & ~GTCO_START));
3220145001Smdodd
3221145001Smdodd	x /= 2.5;
3222145001Smdodd	y /= 2.5;
3223145001Smdodd
3224145001Smdodd	act->flags = 0 ;
3225145001Smdodd	act->obutton = act->button ;
3226145001Smdodd	act->dx = act->dy = act->dz = 0 ;
3227145001Smdodd
3228145001Smdodd	if ((buf[0] & 0x40) == 0) /* pen went out of reach */
3229145001Smdodd		status = S_IDLE ;
3230145001Smdodd	else if (status == S_IDLE) { /* pen is newly near the tablet */
3231145001Smdodd		act->flags |= MOUSE_POSCHANGED ; /* force update */
3232145001Smdodd		status = S_PROXY ;
3233145001Smdodd		x_prev = x ;
3234145001Smdodd		y_prev = y ;
3235145001Smdodd	}
3236145001Smdodd
3237145001Smdodd	act->dx = x - x_prev ;
3238145001Smdodd	act->dy = y - y_prev ;
3239145001Smdodd	if (act->dx || act->dy)
3240145001Smdodd		act->flags |= MOUSE_POSCHANGED ;
3241145001Smdodd	x_prev = x ;
3242145001Smdodd	y_prev = y ;
3243145001Smdodd
3244145001Smdodd	/* possibly record button change */
3245145001Smdodd	if (b_prev != 0 && b_prev != buf[0]) {
3246145001Smdodd		act->button = 0 ;
3247145001Smdodd		if (buf[0] & 0x04) /* tip pressed/yellow */
3248145001Smdodd			act->button |= MOUSE_BUTTON1DOWN ;
3249145001Smdodd		if (buf[0] & 0x08) /* grey/white */
3250145001Smdodd			act->button |= MOUSE_BUTTON2DOWN ;
3251145001Smdodd		if (buf[0] & 0x10) /* black/green */
3252145001Smdodd			act->button |= MOUSE_BUTTON3DOWN ;
3253145001Smdodd		if (buf[0] & 0x20) /* tip+grey/blue */
3254145001Smdodd			act->button |= MOUSE_BUTTON4DOWN ;
3255145001Smdodd		act->flags |= MOUSE_BUTTONSCHANGED ;
3256145001Smdodd	}
3257145001Smdodd	b_prev = buf[0] ;
3258145001Smdodd	return act->flags ;
3259145001Smdodd}
3260145001Smdodd
3261122605Sdesstatic void
326236991Sahastymremote_serversetup()
326336991Sahasty{
326436991Sahasty    struct sockaddr_un ad;
326536991Sahasty
326636991Sahasty    /* Open a UNIX domain stream socket to listen for mouse remote clients */
3267122605Sdes    unlink(_PATH_MOUSEREMOTE);
326836991Sahasty
3269122854Sdes    if ((rodent.mremsfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
327036991Sahasty	logerrx(1, "unable to create unix domain socket %s",_PATH_MOUSEREMOTE);
327136991Sahasty
327236991Sahasty    umask(0111);
3273122605Sdes
327436991Sahasty    bzero(&ad, sizeof(ad));
327536991Sahasty    ad.sun_family = AF_UNIX;
327636991Sahasty    strcpy(ad.sun_path, _PATH_MOUSEREMOTE);
327736991Sahasty#ifndef SUN_LEN
3278122854Sdes#define SUN_LEN(unp) (((char *)(unp)->sun_path - (char *)(unp)) + \
3279122854Sdes		       strlen((unp)->path))
328036991Sahasty#endif
3281122605Sdes    if (bind(rodent.mremsfd, (struct sockaddr *) &ad, SUN_LEN(&ad)) < 0)
328236991Sahasty	logerrx(1, "unable to bind unix domain socket %s", _PATH_MOUSEREMOTE);
328336991Sahasty
328436991Sahasty    listen(rodent.mremsfd, 1);
328536991Sahasty}
328636991Sahasty
3287122605Sdesstatic void
328836991Sahastymremote_clientchg(int add)
328936991Sahasty{
329036991Sahasty    struct sockaddr_un ad;
329136991Sahasty    int ad_len, fd;
329236991Sahasty
329336991Sahasty    if (rodent.rtype != MOUSE_PROTO_X10MOUSEREM)
329436991Sahasty	return;
329536991Sahasty
3296122854Sdes    if (add) {
329736991Sahasty	/*  Accept client connection, if we don't already have one  */
329836991Sahasty	ad_len = sizeof(ad);
329936991Sahasty	fd = accept(rodent.mremsfd, (struct sockaddr *) &ad, &ad_len);
330036991Sahasty	if (fd < 0)
330136991Sahasty	    logwarnx("failed accept on mouse remote socket");
330236991Sahasty
3303122854Sdes	if (rodent.mremcfd < 0) {
330436991Sahasty	    rodent.mremcfd = fd;
330536991Sahasty	    debug("remote client connect...accepted");
330636991Sahasty	}
330736991Sahasty	else {
330836991Sahasty	    close(fd);
330936991Sahasty	    debug("another remote client connect...disconnected");
331036991Sahasty	}
331136991Sahasty    }
331236991Sahasty    else {
331336991Sahasty	/* Client disconnected */
331436991Sahasty	debug("remote client disconnected");
3315122854Sdes	close(rodent.mremcfd);
331636991Sahasty	rodent.mremcfd = -1;
331736991Sahasty    }
331836991Sahasty}
3319