xref: /freebsd/usr.sbin/moused/moused.c (revision 83409a9357a43f2ba595c84ae6904ab4c3ac1ab9)
1ad771aa1SSøren Schmidt /**
21de7b4b8SPedro F. Giffuni  ** SPDX-License-Identifier: BSD-4-Clause
31de7b4b8SPedro F. Giffuni  **
4ad771aa1SSøren Schmidt  ** Copyright (c) 1995 Michael Smith, All rights reserved.
5ad771aa1SSøren Schmidt  **
6ad771aa1SSøren Schmidt  ** Redistribution and use in source and binary forms, with or without
7ad771aa1SSøren Schmidt  ** modification, are permitted provided that the following conditions
8ad771aa1SSøren Schmidt  ** are met:
9ad771aa1SSøren Schmidt  ** 1. Redistributions of source code must retain the above copyright
10ad771aa1SSøren Schmidt  **    notice, this list of conditions and the following disclaimer as
11ad771aa1SSøren Schmidt  **    the first lines of this file unmodified.
12ad771aa1SSøren Schmidt  ** 2. Redistributions in binary form must reproduce the above copyright
13ad771aa1SSøren Schmidt  **    notice, this list of conditions and the following disclaimer in the
14ad771aa1SSøren Schmidt  **    documentation and/or other materials provided with the distribution.
15ad771aa1SSøren Schmidt  ** 3. All advertising materials mentioning features or use of this software
16ad771aa1SSøren Schmidt  **    must display the following acknowledgment:
17ad771aa1SSøren Schmidt  **      This product includes software developed by Michael Smith.
18ad771aa1SSøren Schmidt  ** 4. The name of the author may not be used to endorse or promote products
19ad771aa1SSøren Schmidt  **    derived from this software without specific prior written permission.
20ad771aa1SSøren Schmidt  **
21ad771aa1SSøren Schmidt  **
22ad771aa1SSøren Schmidt  ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY
23ad771aa1SSøren Schmidt  ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24ad771aa1SSøren Schmidt  ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25ad771aa1SSøren Schmidt  ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR
26ad771aa1SSøren Schmidt  ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27ad771aa1SSøren Schmidt  ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28ad771aa1SSøren Schmidt  ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29ad771aa1SSøren Schmidt  ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30ad771aa1SSøren Schmidt  ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31ad771aa1SSøren Schmidt  ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32ad771aa1SSøren Schmidt  ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33ad771aa1SSøren Schmidt  **
34ad771aa1SSøren Schmidt  **/
35ad771aa1SSøren Schmidt 
36ad771aa1SSøren Schmidt /**
37ad771aa1SSøren Schmidt  ** MOUSED.C
38ad771aa1SSøren Schmidt  **
395f436cfbSKazutaka YOKOTA  ** Mouse daemon : listens to a serial port, the bus mouse interface, or
405f436cfbSKazutaka YOKOTA  ** the PS/2 mouse port for mouse data stream, interprets data and passes
415f436cfbSKazutaka YOKOTA  ** ioctls off to the console driver.
42ad771aa1SSøren Schmidt  **
43ad771aa1SSøren Schmidt  ** The mouse interface functions are derived closely from the mouse
44ad771aa1SSøren Schmidt  ** handler in the XFree86 X server.  Many thanks to the XFree86 people
45ad771aa1SSøren Schmidt  ** for their great work!
46ad771aa1SSøren Schmidt  **
47ad771aa1SSøren Schmidt  **/
48ad771aa1SSøren Schmidt 
49038ec830SDag-Erling Smørgrav #include <sys/param.h>
50038ec830SDag-Erling Smørgrav #include <sys/consio.h>
51038ec830SDag-Erling Smørgrav #include <sys/mouse.h>
52038ec830SDag-Erling Smørgrav #include <sys/socket.h>
53038ec830SDag-Erling Smørgrav #include <sys/stat.h>
54038ec830SDag-Erling Smørgrav #include <sys/time.h>
55038ec830SDag-Erling Smørgrav #include <sys/un.h>
56038ec830SDag-Erling Smørgrav 
57038ec830SDag-Erling Smørgrav #include <ctype.h>
5807e1d533SPhilippe Charnier #include <err.h>
5907e1d533SPhilippe Charnier #include <errno.h>
6007e1d533SPhilippe Charnier #include <fcntl.h>
61a80d5fc2SPawel Jakub Dawidek #include <libutil.h>
6207e1d533SPhilippe Charnier #include <limits.h>
63038ec830SDag-Erling Smørgrav #include <setjmp.h>
64038ec830SDag-Erling Smørgrav #include <signal.h>
65038ec830SDag-Erling Smørgrav #include <stdarg.h>
66f2559616SJung-uk Kim #include <stdint.h>
67ad771aa1SSøren Schmidt #include <stdio.h>
68ad771aa1SSøren Schmidt #include <stdlib.h>
69ad771aa1SSøren Schmidt #include <string.h>
705f436cfbSKazutaka YOKOTA #include <syslog.h>
71038ec830SDag-Erling Smørgrav #include <termios.h>
7220a2630bSSøren Schmidt #include <unistd.h>
7386b3ea36SPhilip Paeps #include <math.h>
74ad771aa1SSøren Schmidt 
755f436cfbSKazutaka YOKOTA #define MAX_CLICKTHRESHOLD	2000	/* 2 seconds */
7644bdcfa6SKazutaka YOKOTA #define MAX_BUTTON2TIMEOUT	2000	/* 2 seconds */
7744bdcfa6SKazutaka YOKOTA #define DFLT_CLICKTHRESHOLD	 500	/* 0.5 second */
789c9d9993SKazutaka YOKOTA #define DFLT_BUTTON2TIMEOUT	 100	/* 0.1 second */
792a669c47SPhilip Paeps #define DFLT_SCROLLTHRESHOLD	   3	/* 3 pixels */
803e95467cSPhilip Paeps #define DFLT_SCROLLSPEED	   2	/* 2 pixels */
815f436cfbSKazutaka YOKOTA 
8270ccc8d8SIan Dowse /* Abort 3-button emulation delay after this many movement events. */
8370ccc8d8SIan Dowse #define BUTTON2_MAXMOVE	3
8470ccc8d8SIan Dowse 
855f436cfbSKazutaka YOKOTA #define TRUE		1
865f436cfbSKazutaka YOKOTA #define FALSE		0
875f436cfbSKazutaka YOKOTA 
885f436cfbSKazutaka YOKOTA #define MOUSE_XAXIS	(-1)
895f436cfbSKazutaka YOKOTA #define MOUSE_YAXIS	(-2)
905f436cfbSKazutaka YOKOTA 
9101533d85SKazutaka YOKOTA /* Logitech PS2++ protocol */
9201533d85SKazutaka YOKOTA #define MOUSE_PS2PLUS_CHECKBITS(b)	\
9301533d85SKazutaka YOKOTA 			((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
9401533d85SKazutaka YOKOTA #define MOUSE_PS2PLUS_PACKET_TYPE(b)	\
9501533d85SKazutaka YOKOTA 			(((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
9601533d85SKazutaka YOKOTA 
975f436cfbSKazutaka YOKOTA #define	ChordMiddle	0x0001
985f436cfbSKazutaka YOKOTA #define Emulate3Button	0x0002
995f436cfbSKazutaka YOKOTA #define ClearDTR	0x0004
1005f436cfbSKazutaka YOKOTA #define ClearRTS	0x0008
1015f436cfbSKazutaka YOKOTA #define NoPnP		0x0010
1022a669c47SPhilip Paeps #define VirtualScroll	0x0020
1032c9b9132SPhilip Paeps #define HVirtualScroll	0x0040
10486b3ea36SPhilip Paeps #define ExponentialAcc	0x0080
1055f436cfbSKazutaka YOKOTA 
1065f436cfbSKazutaka YOKOTA #define ID_NONE		0
1075f436cfbSKazutaka YOKOTA #define ID_PORT		1
1085f436cfbSKazutaka YOKOTA #define ID_IF		2
1095f436cfbSKazutaka YOKOTA #define ID_TYPE		4
1105f436cfbSKazutaka YOKOTA #define ID_MODEL	8
1115f436cfbSKazutaka YOKOTA #define ID_ALL		(ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
1125f436cfbSKazutaka YOKOTA 
11313f1c59bSJung-uk Kim /* Operations on timespecs */
11413f1c59bSJung-uk Kim #define	tsclr(tvp)	((tvp)->tv_sec = (tvp)->tv_nsec = 0)
11513f1c59bSJung-uk Kim #define	tscmp(tvp, uvp, cmp)						\
11613f1c59bSJung-uk Kim 	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
11713f1c59bSJung-uk Kim 	    ((tvp)->tv_nsec cmp (uvp)->tv_nsec) :			\
11813f1c59bSJung-uk Kim 	    ((tvp)->tv_sec cmp (uvp)->tv_sec))
11913f1c59bSJung-uk Kim #define	tssub(tvp, uvp, vvp)						\
12013f1c59bSJung-uk Kim 	do {								\
12113f1c59bSJung-uk Kim 		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
12213f1c59bSJung-uk Kim 		(vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec;	\
12313f1c59bSJung-uk Kim 		if ((vvp)->tv_nsec < 0) {				\
12413f1c59bSJung-uk Kim 			(vvp)->tv_sec--;				\
12513f1c59bSJung-uk Kim 			(vvp)->tv_nsec += 1000000000;			\
12613f1c59bSJung-uk Kim 		}							\
12713f1c59bSJung-uk Kim 	} while (0)
12813f1c59bSJung-uk Kim 
129a68654e6SStefan Farfeleder #define debug(...) do {						\
13062e621e8SIan Dowse 	if (debug && nodaemon)					\
131a68654e6SStefan Farfeleder 		warnx(__VA_ARGS__);				\
13262e621e8SIan Dowse } while (0)
13362e621e8SIan Dowse 
134a68654e6SStefan Farfeleder #define logerr(e, ...) do {					\
135a68654e6SStefan Farfeleder 	log_or_warn(LOG_DAEMON | LOG_ERR, errno, __VA_ARGS__);	\
13662e621e8SIan Dowse 	exit(e);						\
13762e621e8SIan Dowse } while (0)
13862e621e8SIan Dowse 
139a68654e6SStefan Farfeleder #define logerrx(e, ...) do {					\
140a68654e6SStefan Farfeleder 	log_or_warn(LOG_DAEMON | LOG_ERR, 0, __VA_ARGS__);	\
14162e621e8SIan Dowse 	exit(e);						\
14262e621e8SIan Dowse } while (0)
14362e621e8SIan Dowse 
144a68654e6SStefan Farfeleder #define logwarn(...)						\
145a68654e6SStefan Farfeleder 	log_or_warn(LOG_DAEMON | LOG_WARNING, errno, __VA_ARGS__)
14662e621e8SIan Dowse 
147a68654e6SStefan Farfeleder #define logwarnx(...)						\
148a68654e6SStefan Farfeleder 	log_or_warn(LOG_DAEMON | LOG_WARNING, 0, __VA_ARGS__)
1495f436cfbSKazutaka YOKOTA 
1505f436cfbSKazutaka YOKOTA /* structures */
1515f436cfbSKazutaka YOKOTA 
1525f436cfbSKazutaka YOKOTA /* symbol table entry */
1535f436cfbSKazutaka YOKOTA typedef struct {
1542657f6e9SJung-uk Kim     const char *name;
1555f436cfbSKazutaka YOKOTA     int val;
1565f436cfbSKazutaka YOKOTA     int val2;
1575f436cfbSKazutaka YOKOTA } symtab_t;
1585f436cfbSKazutaka YOKOTA 
1595f436cfbSKazutaka YOKOTA /* serial PnP ID string */
1605f436cfbSKazutaka YOKOTA typedef struct {
1615f436cfbSKazutaka YOKOTA     int revision;	/* PnP revision, 100 for 1.00 */
1622657f6e9SJung-uk Kim     const char *eisaid;	/* EISA ID including mfr ID and product ID */
1635f436cfbSKazutaka YOKOTA     char *serial;	/* serial No, optional */
1642657f6e9SJung-uk Kim     const char *class;	/* device class, optional */
1655f436cfbSKazutaka YOKOTA     char *compat;	/* list of compatible drivers, optional */
1665f436cfbSKazutaka YOKOTA     char *description;	/* product description, optional */
1675f436cfbSKazutaka YOKOTA     int neisaid;	/* length of the above fields... */
1685f436cfbSKazutaka YOKOTA     int nserial;
1695f436cfbSKazutaka YOKOTA     int nclass;
1705f436cfbSKazutaka YOKOTA     int ncompat;
1715f436cfbSKazutaka YOKOTA     int ndescription;
1725f436cfbSKazutaka YOKOTA } pnpid_t;
1735f436cfbSKazutaka YOKOTA 
1745f436cfbSKazutaka YOKOTA /* global variables */
1755f436cfbSKazutaka YOKOTA 
1767a106fe4SEd Schouten static int	debug = 0;
1777a106fe4SEd Schouten static int	nodaemon = FALSE;
1787a106fe4SEd Schouten static int	background = FALSE;
1797a106fe4SEd Schouten static int	paused = FALSE;
1807a106fe4SEd Schouten static int	identify = ID_NONE;
1817a106fe4SEd Schouten static int	extioctl = FALSE;
1827a106fe4SEd Schouten static const char *pidfile = "/var/run/moused.pid";
1837a106fe4SEd Schouten static struct pidfh *pfh;
184ad771aa1SSøren Schmidt 
1852a669c47SPhilip Paeps #define SCROLL_NOTSCROLLING	0
1862a669c47SPhilip Paeps #define SCROLL_PREPARE		1
1872a669c47SPhilip Paeps #define SCROLL_SCROLLING	2
1882a669c47SPhilip Paeps 
1892a669c47SPhilip Paeps static int	scroll_state;
1902a669c47SPhilip Paeps static int	scroll_movement;
1912c9b9132SPhilip Paeps static int	hscroll_movement;
1922a669c47SPhilip Paeps 
1935f436cfbSKazutaka YOKOTA /* local variables */
194ad771aa1SSøren Schmidt 
1955f436cfbSKazutaka YOKOTA /* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
1965f436cfbSKazutaka YOKOTA static symtab_t rifs[] = {
1972657f6e9SJung-uk Kim     { "serial",		MOUSE_IF_SERIAL,	0 },
1982657f6e9SJung-uk Kim     { "ps/2",		MOUSE_IF_PS2,		0 },
1992657f6e9SJung-uk Kim     { "sysmouse",	MOUSE_IF_SYSMOUSE,	0 },
2002657f6e9SJung-uk Kim     { "usb",		MOUSE_IF_USB,		0 },
2012657f6e9SJung-uk Kim     { NULL,		MOUSE_IF_UNKNOWN,	0 },
2025f436cfbSKazutaka YOKOTA };
203ad771aa1SSøren Schmidt 
2045f436cfbSKazutaka YOKOTA /* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */
2052657f6e9SJung-uk Kim static const char *rnames[] = {
206ad771aa1SSøren Schmidt     "microsoft",
207ad771aa1SSøren Schmidt     "mousesystems",
208ad771aa1SSøren Schmidt     "logitech",
2095f436cfbSKazutaka YOKOTA     "mmseries",
210ad771aa1SSøren Schmidt     "mouseman",
211c1cdf6a4SWarner Losh     "wasbusmouse",
212c1cdf6a4SWarner Losh     "wasinportmouse",
213ad771aa1SSøren Schmidt     "ps/2",
21413379e47SPeter Wemm     "mmhitab",
2155f436cfbSKazutaka YOKOTA     "glidepoint",
2165f436cfbSKazutaka YOKOTA     "intellimouse",
2175f436cfbSKazutaka YOKOTA     "thinkingmouse",
2185f436cfbSKazutaka YOKOTA     "sysmouse",
21967978692SAmancio Hasty     "x10mouseremote",
2201b11ca6cSKazutaka YOKOTA     "kidspad",
22105f92020SWill Andrews     "versapad",
22205f92020SWill Andrews     "jogdial",
2235f436cfbSKazutaka YOKOTA #if notyet
2245f436cfbSKazutaka YOKOTA     "mariqua",
2255f436cfbSKazutaka YOKOTA #endif
226ce99e877SMatthew N. Dodd     "gtco_digipad",
227ad771aa1SSøren Schmidt     NULL
228ad771aa1SSøren Schmidt };
229ad771aa1SSøren Schmidt 
2305f436cfbSKazutaka YOKOTA /* models */
2315f436cfbSKazutaka YOKOTA static symtab_t	rmodels[] = {
2322657f6e9SJung-uk Kim     { "NetScroll",		MOUSE_MODEL_NETSCROLL,		0 },
2332657f6e9SJung-uk Kim     { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET,		0 },
2342657f6e9SJung-uk Kim     { "GlidePoint",		MOUSE_MODEL_GLIDEPOINT,		0 },
2352657f6e9SJung-uk Kim     { "ThinkingMouse",		MOUSE_MODEL_THINK,		0 },
2362657f6e9SJung-uk Kim     { "IntelliMouse",		MOUSE_MODEL_INTELLI,		0 },
2372657f6e9SJung-uk Kim     { "EasyScroll/SmartScroll",	MOUSE_MODEL_EASYSCROLL,		0 },
2382657f6e9SJung-uk Kim     { "MouseMan+",		MOUSE_MODEL_MOUSEMANPLUS,	0 },
2392657f6e9SJung-uk Kim     { "Kidspad",		MOUSE_MODEL_KIDSPAD,		0 },
2402657f6e9SJung-uk Kim     { "VersaPad",		MOUSE_MODEL_VERSAPAD,		0 },
2412657f6e9SJung-uk Kim     { "IntelliMouse Explorer",	MOUSE_MODEL_EXPLORER,		0 },
2422657f6e9SJung-uk Kim     { "4D Mouse",		MOUSE_MODEL_4D,			0 },
2432657f6e9SJung-uk Kim     { "4D+ Mouse",		MOUSE_MODEL_4DPLUS,		0 },
2442657f6e9SJung-uk Kim     { "Synaptics Touchpad",	MOUSE_MODEL_SYNAPTICS,		0 },
245569d8f7eSJung-uk Kim     { "TrackPoint",		MOUSE_MODEL_TRACKPOINT,		0 },
2464f57f07eSOleksandr Tymoshenko     { "Elantech Touchpad",	MOUSE_MODEL_ELANTECH,		0 },
2472657f6e9SJung-uk Kim     { "generic",		MOUSE_MODEL_GENERIC,		0 },
2482657f6e9SJung-uk Kim     { NULL,			MOUSE_MODEL_UNKNOWN,		0 },
249ad771aa1SSøren Schmidt };
250ad771aa1SSøren Schmidt 
2515f436cfbSKazutaka YOKOTA /* PnP EISA/product IDs */
2525f436cfbSKazutaka YOKOTA static symtab_t pnpprod[] = {
2535f436cfbSKazutaka YOKOTA     /* Kensignton ThinkingMouse */
2545f436cfbSKazutaka YOKOTA     { "KML0001",	MOUSE_PROTO_THINK,	MOUSE_MODEL_THINK },
2555f436cfbSKazutaka YOKOTA     /* MS IntelliMouse */
2565f436cfbSKazutaka YOKOTA     { "MSH0001",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
2575f436cfbSKazutaka YOKOTA     /* MS IntelliMouse TrackBall */
2585f436cfbSKazutaka YOKOTA     { "MSH0004",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
2596555de48SAndrey A. Chernov     /* Tremon Wheel Mouse MUSD */
2606555de48SAndrey A. Chernov     { "HTK0001",        MOUSE_PROTO_INTELLI,    MOUSE_MODEL_INTELLI },
2614b6860cfSAndrey A. Chernov     /* Genius PnP Mouse */
2624b6860cfSAndrey A. Chernov     { "KYE0001",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
26317441011SKazutaka YOKOTA     /* MouseSystems SmartScroll Mouse (OEM from Genius?) */
26417441011SKazutaka YOKOTA     { "KYE0002",	MOUSE_PROTO_MS,		MOUSE_MODEL_EASYSCROLL },
2655f436cfbSKazutaka YOKOTA     /* Genius NetMouse */
2665f436cfbSKazutaka YOKOTA     { "KYE0003",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_NET },
2671b11ca6cSKazutaka YOKOTA     /* Genius Kidspad, Easypad and other tablets */
2681b11ca6cSKazutaka YOKOTA     { "KYE0005",	MOUSE_PROTO_KIDSPAD,	MOUSE_MODEL_KIDSPAD },
2694b6860cfSAndrey A. Chernov     /* Genius EZScroll */
2704b6860cfSAndrey A. Chernov     { "KYEEZ00",	MOUSE_PROTO_MS,		MOUSE_MODEL_EASYSCROLL },
27127d63c19SKazutaka YOKOTA     /* Logitech Cordless MouseMan Wheel */
27227d63c19SKazutaka YOKOTA     { "LGI8033",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
27330ee7535SKazutaka YOKOTA     /* Logitech MouseMan (new 4 button model) */
27430ee7535SKazutaka YOKOTA     { "LGI800C",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
2755f436cfbSKazutaka YOKOTA     /* Logitech MouseMan+ */
2765f436cfbSKazutaka YOKOTA     { "LGI8050",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
2775f436cfbSKazutaka YOKOTA     /* Logitech FirstMouse+ */
2785f436cfbSKazutaka YOKOTA     { "LGI8051",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
279f17c0039SKazutaka YOKOTA     /* Logitech serial */
280f17c0039SKazutaka YOKOTA     { "LGI8001",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
281fb966343SKazutaka YOKOTA     /* A4 Tech 4D/4D+ Mouse */
282fb966343SKazutaka YOKOTA     { "A4W0005",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_4D },
283fb966343SKazutaka YOKOTA     /* 8D Scroll Mouse */
284fb966343SKazutaka YOKOTA     { "PEC9802",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
285d65ffe4aSKazutaka YOKOTA     /* Mitsumi Wireless Scroll Mouse */
286d65ffe4aSKazutaka YOKOTA     { "MTM6401",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
287ad771aa1SSøren Schmidt 
2885f436cfbSKazutaka YOKOTA     /* MS serial */
2895f436cfbSKazutaka YOKOTA     { "PNP0F01",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
2905f436cfbSKazutaka YOKOTA     /* MS PS/2 */
2915f436cfbSKazutaka YOKOTA     { "PNP0F03",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
2925f436cfbSKazutaka YOKOTA     /*
2935f436cfbSKazutaka YOKOTA      * EzScroll returns PNP0F04 in the compatible device field; but it
2945f436cfbSKazutaka YOKOTA      * doesn't look compatible... XXX
2955f436cfbSKazutaka YOKOTA      */
2965f436cfbSKazutaka YOKOTA     /* MouseSystems */
2975f436cfbSKazutaka YOKOTA     { "PNP0F04",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
2985f436cfbSKazutaka YOKOTA     /* MouseSystems */
2995f436cfbSKazutaka YOKOTA     { "PNP0F05",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
3005f436cfbSKazutaka YOKOTA #if notyet
3015f436cfbSKazutaka YOKOTA     /* Genius Mouse */
302b2183f97SDag-Erling Smørgrav     { "PNP0F06",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3035f436cfbSKazutaka YOKOTA     /* Genius Mouse */
304b2183f97SDag-Erling Smørgrav     { "PNP0F07",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3055f436cfbSKazutaka YOKOTA #endif
3065f436cfbSKazutaka YOKOTA     /* Logitech serial */
3075f436cfbSKazutaka YOKOTA     { "PNP0F08",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
3085f436cfbSKazutaka YOKOTA     /* MS BallPoint serial */
3095f436cfbSKazutaka YOKOTA     { "PNP0F09",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
3105f436cfbSKazutaka YOKOTA     /* MS PnP serial */
3115f436cfbSKazutaka YOKOTA     { "PNP0F0A",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
3125f436cfbSKazutaka YOKOTA     /* MS PnP BallPoint serial */
3135f436cfbSKazutaka YOKOTA     { "PNP0F0B",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
31464b3bcc6SGordon Bergling     /* MS serial compatible */
3155f436cfbSKazutaka YOKOTA     { "PNP0F0C",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
31664b3bcc6SGordon Bergling     /* MS PS/2 compatible */
3175f436cfbSKazutaka YOKOTA     { "PNP0F0E",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
31864b3bcc6SGordon Bergling     /* MS BallPoint compatible */
3195f436cfbSKazutaka YOKOTA     { "PNP0F0F",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
3205f436cfbSKazutaka YOKOTA #if notyet
3215f436cfbSKazutaka YOKOTA     /* TI QuickPort */
322b2183f97SDag-Erling Smørgrav     { "PNP0F10",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3235f436cfbSKazutaka YOKOTA #endif
3245f436cfbSKazutaka YOKOTA     /* Logitech PS/2 */
3255f436cfbSKazutaka YOKOTA     { "PNP0F12",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
3265f436cfbSKazutaka YOKOTA     /* PS/2 */
3275f436cfbSKazutaka YOKOTA     { "PNP0F13",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
3285f436cfbSKazutaka YOKOTA #if notyet
3295f436cfbSKazutaka YOKOTA     /* MS Kids Mouse */
330b2183f97SDag-Erling Smørgrav     { "PNP0F14",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3315f436cfbSKazutaka YOKOTA #endif
3325f436cfbSKazutaka YOKOTA #if notyet
3335f436cfbSKazutaka YOKOTA     /* Logitech SWIFT */
334b2183f97SDag-Erling Smørgrav     { "PNP0F16",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3355f436cfbSKazutaka YOKOTA #endif
3365f436cfbSKazutaka YOKOTA     /* Logitech serial compat */
3375f436cfbSKazutaka YOKOTA     { "PNP0F17",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
3385f436cfbSKazutaka YOKOTA     /* Logitech PS/2 compatible */
3395f436cfbSKazutaka YOKOTA     { "PNP0F19",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
3405f436cfbSKazutaka YOKOTA #if notyet
3415f436cfbSKazutaka YOKOTA     /* Logitech SWIFT compatible */
342b2183f97SDag-Erling Smørgrav     { "PNP0F1A",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3435f436cfbSKazutaka YOKOTA     /* HP Omnibook */
344b2183f97SDag-Erling Smørgrav     { "PNP0F1B",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3455f436cfbSKazutaka YOKOTA     /* Compaq LTE TrackBall PS/2 */
346b2183f97SDag-Erling Smørgrav     { "PNP0F1C",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3475f436cfbSKazutaka YOKOTA     /* Compaq LTE TrackBall serial */
348b2183f97SDag-Erling Smørgrav     { "PNP0F1D",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3495f436cfbSKazutaka YOKOTA     /* MS Kidts Trackball */
350b2183f97SDag-Erling Smørgrav     { "PNP0F1E",	MOUSE_PROTO_XXX,	MOUSE_MODEL_GENERIC },
3515f436cfbSKazutaka YOKOTA #endif
3522e09fb67SKazutaka YOKOTA     /* Interlink VersaPad */
3532e09fb67SKazutaka YOKOTA     { "LNK0001",	MOUSE_PROTO_VERSAPAD,	MOUSE_MODEL_VERSAPAD },
3545f436cfbSKazutaka YOKOTA 
3555f436cfbSKazutaka YOKOTA     { NULL,		MOUSE_PROTO_UNKNOWN,	MOUSE_MODEL_GENERIC },
3565f436cfbSKazutaka YOKOTA };
3575f436cfbSKazutaka YOKOTA 
3585f436cfbSKazutaka YOKOTA /* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */
3595f436cfbSKazutaka YOKOTA static unsigned short rodentcflags[] =
360ad771aa1SSøren Schmidt {
3615f436cfbSKazutaka YOKOTA     (CS7	           | CREAD | CLOCAL | HUPCL),	/* MicroSoft */
3625f436cfbSKazutaka YOKOTA     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* MouseSystems */
3635f436cfbSKazutaka YOKOTA     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* Logitech */
3645f436cfbSKazutaka YOKOTA     (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL),	/* MMSeries */
3655f436cfbSKazutaka YOKOTA     (CS7		   | CREAD | CLOCAL | HUPCL),	/* MouseMan */
3665f436cfbSKazutaka YOKOTA     0,							/* Bus */
3675f436cfbSKazutaka YOKOTA     0,							/* InPort */
3685f436cfbSKazutaka YOKOTA     0,							/* PS/2 */
3695f436cfbSKazutaka YOKOTA     (CS8		   | CREAD | CLOCAL | HUPCL),	/* MM HitTablet */
3705f436cfbSKazutaka YOKOTA     (CS7	           | CREAD | CLOCAL | HUPCL),	/* GlidePoint */
3715f436cfbSKazutaka YOKOTA     (CS7                   | CREAD | CLOCAL | HUPCL),	/* IntelliMouse */
3725f436cfbSKazutaka YOKOTA     (CS7                   | CREAD | CLOCAL | HUPCL),	/* Thinking Mouse */
3735d6618faSKazutaka YOKOTA     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* sysmouse */
37467978692SAmancio Hasty     (CS7	           | CREAD | CLOCAL | HUPCL),	/* X10 MouseRemote */
3751b11ca6cSKazutaka YOKOTA     (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL),	/* kidspad etc. */
3762e09fb67SKazutaka YOKOTA     (CS8		   | CREAD | CLOCAL | HUPCL),	/* VersaPad */
37705f92020SWill Andrews     0,							/* JogDial */
3785f436cfbSKazutaka YOKOTA #if notyet
3795f436cfbSKazutaka YOKOTA     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL),	/* Mariqua */
3805f436cfbSKazutaka YOKOTA #endif
381ce99e877SMatthew N. Dodd     (CS8		   | CREAD |	      HUPCL ),	/* GTCO Digi-Pad */
3825f436cfbSKazutaka YOKOTA };
383ad771aa1SSøren Schmidt 
3845f436cfbSKazutaka YOKOTA static struct rodentparam {
3855f436cfbSKazutaka YOKOTA     int flags;
3862657f6e9SJung-uk Kim     const char *portname;	/* /dev/XXX */
3875f436cfbSKazutaka YOKOTA     int rtype;			/* MOUSE_PROTO_XXX */
3885f436cfbSKazutaka YOKOTA     int level;			/* operation level: 0 or greater */
3895f436cfbSKazutaka YOKOTA     int baudrate;
3905f436cfbSKazutaka YOKOTA     int rate;			/* report rate */
3915f436cfbSKazutaka YOKOTA     int resolution;		/* MOUSE_RES_XXX or a positive number */
392fb966343SKazutaka YOKOTA     int zmap[4];		/* MOUSE_{X|Y}AXIS or a button number */
3939fb1d70cSKazutaka YOKOTA     int wmode;			/* wheel mode button number */
3945f436cfbSKazutaka YOKOTA     int mfd;			/* mouse file descriptor */
3955f436cfbSKazutaka YOKOTA     int cfd;			/* /dev/consolectl file descriptor */
39667978692SAmancio Hasty     int mremsfd;		/* mouse remote server file descriptor */
39767978692SAmancio Hasty     int mremcfd;		/* mouse remote client file descriptor */
39808f950a3SHans Petter Selasky     int is_removable;		/* set if device is removable, like USB */
3995f436cfbSKazutaka YOKOTA     long clickthreshold;	/* double click speed in msec */
40044bdcfa6SKazutaka YOKOTA     long button2timeout;	/* 3 button emulation timeout */
4015f436cfbSKazutaka YOKOTA     mousehw_t hw;		/* mouse device hardware information */
4025f436cfbSKazutaka YOKOTA     mousemode_t mode;		/* protocol information */
403efe4cd6aSGeorge C A Reid     float accelx;		/* Acceleration in the X axis */
404efe4cd6aSGeorge C A Reid     float accely;		/* Acceleration in the Y axis */
40586b3ea36SPhilip Paeps     float expoaccel;		/* Exponential acceleration */
40686b3ea36SPhilip Paeps     float expoffset;		/* Movement offset for exponential accel. */
407d9338247SPhilip Paeps     float remainx;		/* Remainder on X and Y axis, respectively... */
408d9338247SPhilip Paeps     float remainy;		/*    ... to compensate for rounding errors. */
4092a669c47SPhilip Paeps     int scrollthreshold;	/* Movement distance before virtual scrolling */
4103e95467cSPhilip Paeps     int scrollspeed;		/* Movement distance to rate of scrolling */
4115f436cfbSKazutaka YOKOTA } rodent = {
412358f61ceSStefan Farfeleder     .flags = 0,
413358f61ceSStefan Farfeleder     .portname = NULL,
414358f61ceSStefan Farfeleder     .rtype = MOUSE_PROTO_UNKNOWN,
415358f61ceSStefan Farfeleder     .level = -1,
416358f61ceSStefan Farfeleder     .baudrate = 1200,
417358f61ceSStefan Farfeleder     .rate = 0,
418358f61ceSStefan Farfeleder     .resolution = MOUSE_RES_UNKNOWN,
419358f61ceSStefan Farfeleder     .zmap = { 0, 0, 0, 0 },
420358f61ceSStefan Farfeleder     .wmode = 0,
421358f61ceSStefan Farfeleder     .mfd = -1,
422358f61ceSStefan Farfeleder     .cfd = -1,
423358f61ceSStefan Farfeleder     .mremsfd = -1,
424358f61ceSStefan Farfeleder     .mremcfd = -1,
42508f950a3SHans Petter Selasky     .is_removable = 0,
426358f61ceSStefan Farfeleder     .clickthreshold = DFLT_CLICKTHRESHOLD,
427358f61ceSStefan Farfeleder     .button2timeout = DFLT_BUTTON2TIMEOUT,
428358f61ceSStefan Farfeleder     .accelx = 1.0,
429358f61ceSStefan Farfeleder     .accely = 1.0,
43086b3ea36SPhilip Paeps     .expoaccel = 1.0,
43186b3ea36SPhilip Paeps     .expoffset = 1.0,
432d9338247SPhilip Paeps     .remainx = 0.0,
433d9338247SPhilip Paeps     .remainy = 0.0,
4342a669c47SPhilip Paeps     .scrollthreshold = DFLT_SCROLLTHRESHOLD,
4353e95467cSPhilip Paeps     .scrollspeed = DFLT_SCROLLSPEED,
4365f436cfbSKazutaka YOKOTA };
437ad771aa1SSøren Schmidt 
4385f436cfbSKazutaka YOKOTA /* button status */
43944bdcfa6SKazutaka YOKOTA struct button_state {
4405f436cfbSKazutaka YOKOTA     int count;		/* 0: up, 1: single click, 2: double click,... */
44113f1c59bSJung-uk Kim     struct timespec ts;	/* timestamp on the last button event */
44244bdcfa6SKazutaka YOKOTA };
44344bdcfa6SKazutaka YOKOTA static struct button_state	bstate[MOUSE_MAXBUTTON];	/* button state */
44444bdcfa6SKazutaka YOKOTA static struct button_state	*mstate[MOUSE_MAXBUTTON];/* mapped button st.*/
44544bdcfa6SKazutaka YOKOTA static struct button_state	zstate[4];		 /* Z/W axis state */
44644bdcfa6SKazutaka YOKOTA 
44744bdcfa6SKazutaka YOKOTA /* state machine for 3 button emulation */
44844bdcfa6SKazutaka YOKOTA 
44944bdcfa6SKazutaka YOKOTA #define S0	0	/* start */
45044bdcfa6SKazutaka YOKOTA #define S1	1	/* button 1 delayed down */
45144bdcfa6SKazutaka YOKOTA #define S2	2	/* button 3 delayed down */
45244bdcfa6SKazutaka YOKOTA #define S3	3	/* both buttons down -> button 2 down */
45344bdcfa6SKazutaka YOKOTA #define S4	4	/* button 1 delayed up */
45444bdcfa6SKazutaka YOKOTA #define S5	5	/* button 1 down */
45544bdcfa6SKazutaka YOKOTA #define S6	6	/* button 3 down */
45644bdcfa6SKazutaka YOKOTA #define S7	7	/* both buttons down */
45744bdcfa6SKazutaka YOKOTA #define S8	8	/* button 3 delayed up */
45844bdcfa6SKazutaka YOKOTA #define S9	9	/* button 1 or 3 up after S3 */
45944bdcfa6SKazutaka YOKOTA 
46044bdcfa6SKazutaka YOKOTA #define A(b1, b3)	(((b1) ? 2 : 0) | ((b3) ? 1 : 0))
46144bdcfa6SKazutaka YOKOTA #define A_TIMEOUT	4
46270ccc8d8SIan Dowse #define S_DELAYED(st)	(states[st].s[A_TIMEOUT] != (st))
46344bdcfa6SKazutaka YOKOTA 
46444bdcfa6SKazutaka YOKOTA static struct {
46544bdcfa6SKazutaka YOKOTA     int s[A_TIMEOUT + 1];
46644bdcfa6SKazutaka YOKOTA     int buttons;
46744bdcfa6SKazutaka YOKOTA     int mask;
468127d54baSKazutaka YOKOTA     int timeout;
46944bdcfa6SKazutaka YOKOTA } states[10] = {
47044bdcfa6SKazutaka YOKOTA     /* S0 */
471127d54baSKazutaka YOKOTA     { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
47244bdcfa6SKazutaka YOKOTA     /* S1 */
473127d54baSKazutaka YOKOTA     { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, FALSE },
47444bdcfa6SKazutaka YOKOTA     /* S2 */
475127d54baSKazutaka YOKOTA     { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, FALSE },
47644bdcfa6SKazutaka YOKOTA     /* S3 */
477127d54baSKazutaka YOKOTA     { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, FALSE },
47844bdcfa6SKazutaka YOKOTA     /* S4 */
479127d54baSKazutaka YOKOTA     { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, TRUE },
48044bdcfa6SKazutaka YOKOTA     /* S5 */
481127d54baSKazutaka YOKOTA     { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, FALSE },
48244bdcfa6SKazutaka YOKOTA     /* S6 */
483127d54baSKazutaka YOKOTA     { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, FALSE },
48444bdcfa6SKazutaka YOKOTA     /* S7 */
485127d54baSKazutaka YOKOTA     { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, FALSE },
48644bdcfa6SKazutaka YOKOTA     /* S8 */
487127d54baSKazutaka YOKOTA     { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, TRUE },
48844bdcfa6SKazutaka YOKOTA     /* S9 */
489127d54baSKazutaka YOKOTA     { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
49044bdcfa6SKazutaka YOKOTA };
49144bdcfa6SKazutaka YOKOTA static int		mouse_button_state;
49213f1c59bSJung-uk Kim static struct timespec	mouse_button_state_ts;
49370ccc8d8SIan Dowse static int		mouse_move_delayed;
494ad771aa1SSøren Schmidt 
4955f436cfbSKazutaka YOKOTA static jmp_buf env;
4965f436cfbSKazutaka YOKOTA 
49713f1c59bSJung-uk Kim struct drift_xy {
49813f1c59bSJung-uk Kim     int x;
49913f1c59bSJung-uk Kim     int y;
50013f1c59bSJung-uk Kim };
501d5f2946aSPhilip Paeps static int		drift_distance = 4;	/* max steps X+Y */
502d5f2946aSPhilip Paeps static int		drift_time = 500;	/* in 0.5 sec */
50313f1c59bSJung-uk Kim static struct timespec	drift_time_ts;
50413f1c59bSJung-uk Kim static struct timespec	drift_2time_ts;		/* 2*drift_time */
505d5f2946aSPhilip Paeps static int		drift_after = 4000;	/* 4 sec */
50613f1c59bSJung-uk Kim static struct timespec	drift_after_ts;
507d5f2946aSPhilip Paeps static int		drift_terminate = FALSE;
50813f1c59bSJung-uk Kim static struct timespec	drift_current_ts;
50913f1c59bSJung-uk Kim static struct timespec	drift_tmp;
51013f1c59bSJung-uk Kim static struct timespec	drift_last_activity = {0, 0};
51113f1c59bSJung-uk Kim static struct timespec	drift_since = {0, 0};
51213f1c59bSJung-uk Kim static struct drift_xy	drift_last = {0, 0};	/* steps in last drift_time */
51313f1c59bSJung-uk Kim static struct drift_xy  drift_previous = {0, 0};	/* steps in prev. drift_time */
514d5f2946aSPhilip Paeps 
5155f436cfbSKazutaka YOKOTA /* function prototypes */
5165f436cfbSKazutaka YOKOTA 
517d9338247SPhilip Paeps static void	linacc(int, int, int*, int*);
51886b3ea36SPhilip Paeps static void	expoacc(int, int, int*, int*);
5195f436cfbSKazutaka YOKOTA static void	moused(void);
5205f436cfbSKazutaka YOKOTA static void	hup(int sig);
52167978692SAmancio Hasty static void	cleanup(int sig);
5229eac5bb9SPhilip Paeps static void	pause_mouse(int sig);
5235f436cfbSKazutaka YOKOTA static void	usage(void);
52462e621e8SIan Dowse static void	log_or_warn(int log_pri, int errnum, const char *fmt, ...)
52562e621e8SIan Dowse 		    __printflike(3, 4);
5265f436cfbSKazutaka YOKOTA 
5275f436cfbSKazutaka YOKOTA static int	r_identify(void);
5282657f6e9SJung-uk Kim static const char *r_if(int type);
5292657f6e9SJung-uk Kim static const char *r_name(int type);
5302657f6e9SJung-uk Kim static const char *r_model(int model);
5315f436cfbSKazutaka YOKOTA static void	r_init(void);
5325f436cfbSKazutaka YOKOTA static int	r_protocol(u_char b, mousestatus_t *act);
53344bdcfa6SKazutaka YOKOTA static int	r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans);
5345f436cfbSKazutaka YOKOTA static int	r_installmap(char *arg);
5355f436cfbSKazutaka YOKOTA static void	r_map(mousestatus_t *act1, mousestatus_t *act2);
53644bdcfa6SKazutaka YOKOTA static void	r_timestamp(mousestatus_t *act);
53744bdcfa6SKazutaka YOKOTA static int	r_timeout(void);
5385f436cfbSKazutaka YOKOTA static void	r_click(mousestatus_t *act);
5395f436cfbSKazutaka YOKOTA static void	setmousespeed(int old, int new, unsigned cflag);
5405f436cfbSKazutaka YOKOTA 
541f41621f9SKazutaka YOKOTA static int	pnpwakeup1(void);
542f41621f9SKazutaka YOKOTA static int	pnpwakeup2(void);
5435f436cfbSKazutaka YOKOTA static int	pnpgets(char *buf);
5445f436cfbSKazutaka YOKOTA static int	pnpparse(pnpid_t *id, char *buf, int len);
5455f436cfbSKazutaka YOKOTA static symtab_t	*pnpproto(pnpid_t *id);
5465f436cfbSKazutaka YOKOTA 
5472657f6e9SJung-uk Kim static symtab_t	*gettoken(symtab_t *tab, const char *s, int len);
5482657f6e9SJung-uk Kim static const char *gettokenname(symtab_t *tab, int val);
549ad771aa1SSøren Schmidt 
5502657f6e9SJung-uk Kim static void	mremote_serversetup(void);
55167978692SAmancio Hasty static void	mremote_clientchg(int add);
55267978692SAmancio Hasty 
5531b11ca6cSKazutaka YOKOTA static int	kidspad(u_char rxc, mousestatus_t *act);
554ce99e877SMatthew N. Dodd static int	gtco_digipad(u_char, mousestatus_t *);
5551b11ca6cSKazutaka YOKOTA 
556e46b89dcSPeter Wemm int
557ad771aa1SSøren Schmidt main(int argc, char *argv[])
558ad771aa1SSøren Schmidt {
5595f436cfbSKazutaka YOKOTA     int c;
5605f436cfbSKazutaka YOKOTA     int	i;
561fb966343SKazutaka YOKOTA     int	j;
562ad771aa1SSøren Schmidt 
56344bdcfa6SKazutaka YOKOTA     for (i = 0; i < MOUSE_MAXBUTTON; ++i)
56444bdcfa6SKazutaka YOKOTA 	mstate[i] = &bstate[i];
56544bdcfa6SKazutaka YOKOTA 
5663e95467cSPhilip Paeps     while ((c = getopt(argc, argv, "3A:C:DE:F:HI:L:PRS:T:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
5675f436cfbSKazutaka YOKOTA 	switch(c) {
5685f436cfbSKazutaka YOKOTA 
5695f436cfbSKazutaka YOKOTA 	case '3':
5705f436cfbSKazutaka YOKOTA 	    rodent.flags |= Emulate3Button;
5715f436cfbSKazutaka YOKOTA 	    break;
5725f436cfbSKazutaka YOKOTA 
57344bdcfa6SKazutaka YOKOTA 	case 'E':
57444bdcfa6SKazutaka YOKOTA 	    rodent.button2timeout = atoi(optarg);
57544bdcfa6SKazutaka YOKOTA 	    if ((rodent.button2timeout < 0) ||
57644bdcfa6SKazutaka YOKOTA 		(rodent.button2timeout > MAX_BUTTON2TIMEOUT)) {
57744bdcfa6SKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
57844bdcfa6SKazutaka YOKOTA 		usage();
57944bdcfa6SKazutaka YOKOTA 	    }
58044bdcfa6SKazutaka YOKOTA 	    break;
58144bdcfa6SKazutaka YOKOTA 
582efe4cd6aSGeorge C A Reid 	case 'a':
583efe4cd6aSGeorge C A Reid 	    i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely);
584efe4cd6aSGeorge C A Reid 	    if (i == 0) {
58586b3ea36SPhilip Paeps 		warnx("invalid linear acceleration argument '%s'", optarg);
586efe4cd6aSGeorge C A Reid 		usage();
587efe4cd6aSGeorge C A Reid 	    }
588efe4cd6aSGeorge C A Reid 
589efe4cd6aSGeorge C A Reid 	    if (i == 1)
590efe4cd6aSGeorge C A Reid 		rodent.accely = rodent.accelx;
591efe4cd6aSGeorge C A Reid 
592efe4cd6aSGeorge C A Reid 	    break;
593efe4cd6aSGeorge C A Reid 
59486b3ea36SPhilip Paeps 	case 'A':
59586b3ea36SPhilip Paeps 	    rodent.flags |= ExponentialAcc;
59686b3ea36SPhilip Paeps 	    i = sscanf(optarg, "%f,%f", &rodent.expoaccel, &rodent.expoffset);
59786b3ea36SPhilip Paeps 	    if (i == 0) {
59886b3ea36SPhilip Paeps 		warnx("invalid exponential acceleration argument '%s'", optarg);
59986b3ea36SPhilip Paeps 		usage();
60086b3ea36SPhilip Paeps 	    }
60186b3ea36SPhilip Paeps 
60286b3ea36SPhilip Paeps 	    if (i == 1)
60386b3ea36SPhilip Paeps 		rodent.expoffset = 1.0;
60486b3ea36SPhilip Paeps 
60586b3ea36SPhilip Paeps 	    break;
60686b3ea36SPhilip Paeps 
607ad771aa1SSøren Schmidt 	case 'c':
608ad771aa1SSøren Schmidt 	    rodent.flags |= ChordMiddle;
609ad771aa1SSøren Schmidt 	    break;
610ad771aa1SSøren Schmidt 
611ad771aa1SSøren Schmidt 	case 'd':
6125f436cfbSKazutaka YOKOTA 	    ++debug;
613ad771aa1SSøren Schmidt 	    break;
614ad771aa1SSøren Schmidt 
615ad771aa1SSøren Schmidt 	case 'f':
6165f436cfbSKazutaka YOKOTA 	    nodaemon = TRUE;
6175f436cfbSKazutaka YOKOTA 	    break;
6185f436cfbSKazutaka YOKOTA 
6195f436cfbSKazutaka YOKOTA 	case 'i':
6205f436cfbSKazutaka YOKOTA 	    if (strcmp(optarg, "all") == 0)
6215f436cfbSKazutaka YOKOTA 		identify = ID_ALL;
6225f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "port") == 0)
6235f436cfbSKazutaka YOKOTA 		identify = ID_PORT;
6245f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "if") == 0)
6255f436cfbSKazutaka YOKOTA 		identify = ID_IF;
6265f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "type") == 0)
6275f436cfbSKazutaka YOKOTA 		identify = ID_TYPE;
6285f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "model") == 0)
6295f436cfbSKazutaka YOKOTA 		identify = ID_MODEL;
6305f436cfbSKazutaka YOKOTA 	    else {
6315f436cfbSKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
6325f436cfbSKazutaka YOKOTA 		usage();
6335f436cfbSKazutaka YOKOTA 	    }
6345f436cfbSKazutaka YOKOTA 	    nodaemon = TRUE;
6355f436cfbSKazutaka YOKOTA 	    break;
6365f436cfbSKazutaka YOKOTA 
6375f436cfbSKazutaka YOKOTA 	case 'l':
6385f436cfbSKazutaka YOKOTA 	    rodent.level = atoi(optarg);
6395f436cfbSKazutaka YOKOTA 	    if ((rodent.level < 0) || (rodent.level > 4)) {
6405f436cfbSKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
6415f436cfbSKazutaka YOKOTA 		usage();
6425f436cfbSKazutaka YOKOTA 	    }
6435f436cfbSKazutaka YOKOTA 	    break;
6445f436cfbSKazutaka YOKOTA 
6455f436cfbSKazutaka YOKOTA 	case 'm':
6465f436cfbSKazutaka YOKOTA 	    if (!r_installmap(optarg)) {
6475f436cfbSKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
6485f436cfbSKazutaka YOKOTA 		usage();
6495f436cfbSKazutaka YOKOTA 	    }
650ad771aa1SSøren Schmidt 	    break;
651ad771aa1SSøren Schmidt 
652ad771aa1SSøren Schmidt 	case 'p':
653ad771aa1SSøren Schmidt 	    rodent.portname = optarg;
654ad771aa1SSøren Schmidt 	    break;
655ad771aa1SSøren Schmidt 
65663599332SPeter Wemm 	case 'r':
6575f436cfbSKazutaka YOKOTA 	    if (strcmp(optarg, "high") == 0)
6585f436cfbSKazutaka YOKOTA 		rodent.resolution = MOUSE_RES_HIGH;
6595f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "medium-high") == 0)
6605f436cfbSKazutaka YOKOTA 		rodent.resolution = MOUSE_RES_HIGH;
6615f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "medium-low") == 0)
6625f436cfbSKazutaka YOKOTA 		rodent.resolution = MOUSE_RES_MEDIUMLOW;
6635f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "low") == 0)
6645f436cfbSKazutaka YOKOTA 		rodent.resolution = MOUSE_RES_LOW;
6655f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "default") == 0)
6665f436cfbSKazutaka YOKOTA 		rodent.resolution = MOUSE_RES_DEFAULT;
6675f436cfbSKazutaka YOKOTA 	    else {
6685f436cfbSKazutaka YOKOTA 		rodent.resolution = atoi(optarg);
6695f436cfbSKazutaka YOKOTA 		if (rodent.resolution <= 0) {
6705f436cfbSKazutaka YOKOTA 		    warnx("invalid argument `%s'", optarg);
6715f436cfbSKazutaka YOKOTA 		    usage();
6725f436cfbSKazutaka YOKOTA 		}
6735f436cfbSKazutaka YOKOTA 	    }
67463599332SPeter Wemm 	    break;
67563599332SPeter Wemm 
676ad771aa1SSøren Schmidt 	case 's':
677ad771aa1SSøren Schmidt 	    rodent.baudrate = 9600;
67813379e47SPeter Wemm 	    break;
67913379e47SPeter Wemm 
6809fb1d70cSKazutaka YOKOTA 	case 'w':
6819fb1d70cSKazutaka YOKOTA 	    i = atoi(optarg);
6829fb1d70cSKazutaka YOKOTA 	    if ((i <= 0) || (i > MOUSE_MAXBUTTON)) {
6839fb1d70cSKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
6849fb1d70cSKazutaka YOKOTA 		usage();
6859fb1d70cSKazutaka YOKOTA 	    }
6869fb1d70cSKazutaka YOKOTA 	    rodent.wmode = 1 << (i - 1);
6879fb1d70cSKazutaka YOKOTA 	    break;
6889fb1d70cSKazutaka YOKOTA 
6895f436cfbSKazutaka YOKOTA 	case 'z':
6905f436cfbSKazutaka YOKOTA 	    if (strcmp(optarg, "x") == 0)
691fb966343SKazutaka YOKOTA 		rodent.zmap[0] = MOUSE_XAXIS;
6925f436cfbSKazutaka YOKOTA 	    else if (strcmp(optarg, "y") == 0)
693fb966343SKazutaka YOKOTA 		rodent.zmap[0] = MOUSE_YAXIS;
6945f436cfbSKazutaka YOKOTA 	    else {
6955f436cfbSKazutaka YOKOTA 		i = atoi(optarg);
6965f436cfbSKazutaka YOKOTA 		/*
6975f436cfbSKazutaka YOKOTA 		 * Use button i for negative Z axis movement and
6985f436cfbSKazutaka YOKOTA 		 * button (i + 1) for positive Z axis movement.
6995f436cfbSKazutaka YOKOTA 		 */
7005f436cfbSKazutaka YOKOTA 		if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
7015f436cfbSKazutaka YOKOTA 		    warnx("invalid argument `%s'", optarg);
7025f436cfbSKazutaka YOKOTA 		    usage();
7035f436cfbSKazutaka YOKOTA 		}
70444bdcfa6SKazutaka YOKOTA 		rodent.zmap[0] = i;
70544bdcfa6SKazutaka YOKOTA 		rodent.zmap[1] = i + 1;
7064e008b7fSKazutaka YOKOTA 		debug("optind: %d, optarg: '%s'", optind, optarg);
707fb966343SKazutaka YOKOTA 		for (j = 1; j < 4; ++j) {
708fb966343SKazutaka YOKOTA 		    if ((optind >= argc) || !isdigit(*argv[optind]))
709fb966343SKazutaka YOKOTA 			break;
710fb966343SKazutaka YOKOTA 		    i = atoi(argv[optind]);
711fb966343SKazutaka YOKOTA 		    if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
712fb966343SKazutaka YOKOTA 			warnx("invalid argument `%s'", argv[optind]);
713fb966343SKazutaka YOKOTA 			usage();
714fb966343SKazutaka YOKOTA 		    }
71544bdcfa6SKazutaka YOKOTA 		    rodent.zmap[j] = i;
716fb966343SKazutaka YOKOTA 		    ++optind;
717fb966343SKazutaka YOKOTA 		}
718127d54baSKazutaka YOKOTA 		if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0))
71944bdcfa6SKazutaka YOKOTA 		    rodent.zmap[3] = rodent.zmap[2] + 1;
7205f436cfbSKazutaka YOKOTA 	    }
7215f436cfbSKazutaka YOKOTA 	    break;
7225f436cfbSKazutaka YOKOTA 
7235f436cfbSKazutaka YOKOTA 	case 'C':
7245f436cfbSKazutaka YOKOTA 	    rodent.clickthreshold = atoi(optarg);
7255f436cfbSKazutaka YOKOTA 	    if ((rodent.clickthreshold < 0) ||
7265f436cfbSKazutaka YOKOTA 		(rodent.clickthreshold > MAX_CLICKTHRESHOLD)) {
7275f436cfbSKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
7285f436cfbSKazutaka YOKOTA 		usage();
7295f436cfbSKazutaka YOKOTA 	    }
73013379e47SPeter Wemm 	    break;
73113379e47SPeter Wemm 
73213379e47SPeter Wemm 	case 'D':
7335f436cfbSKazutaka YOKOTA 	    rodent.flags |= ClearDTR;
7345f436cfbSKazutaka YOKOTA 	    break;
7355f436cfbSKazutaka YOKOTA 
7365f436cfbSKazutaka YOKOTA 	case 'F':
7375f436cfbSKazutaka YOKOTA 	    rodent.rate = atoi(optarg);
7385f436cfbSKazutaka YOKOTA 	    if (rodent.rate <= 0) {
7395f436cfbSKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
7405f436cfbSKazutaka YOKOTA 		usage();
7415f436cfbSKazutaka YOKOTA 	    }
7425f436cfbSKazutaka YOKOTA 	    break;
7435f436cfbSKazutaka YOKOTA 
7442c9b9132SPhilip Paeps 	case 'H':
7452c9b9132SPhilip Paeps 	    rodent.flags |= HVirtualScroll;
7462c9b9132SPhilip Paeps 	    break;
7472c9b9132SPhilip Paeps 
7487b60e552SJordan K. Hubbard 	case 'I':
7497b60e552SJordan K. Hubbard 	    pidfile = optarg;
7507b60e552SJordan K. Hubbard 	    break;
7517b60e552SJordan K. Hubbard 
7523e95467cSPhilip Paeps 	case 'L':
7533e95467cSPhilip Paeps 	    rodent.scrollspeed = atoi(optarg);
7543e95467cSPhilip Paeps 	    if (rodent.scrollspeed < 0) {
7553e95467cSPhilip Paeps 		warnx("invalid argument `%s'", optarg);
7563e95467cSPhilip Paeps 		usage();
7573e95467cSPhilip Paeps 	    }
7583e95467cSPhilip Paeps 	    break;
7593e95467cSPhilip Paeps 
7605f436cfbSKazutaka YOKOTA 	case 'P':
7615f436cfbSKazutaka YOKOTA 	    rodent.flags |= NoPnP;
7625f436cfbSKazutaka YOKOTA 	    break;
7635f436cfbSKazutaka YOKOTA 
7645f436cfbSKazutaka YOKOTA 	case 'R':
7655f436cfbSKazutaka YOKOTA 	    rodent.flags |= ClearRTS;
76613379e47SPeter Wemm 	    break;
76713379e47SPeter Wemm 
76813379e47SPeter Wemm 	case 'S':
76913379e47SPeter Wemm 	    rodent.baudrate = atoi(optarg);
7705f436cfbSKazutaka YOKOTA 	    if (rodent.baudrate <= 0) {
7715f436cfbSKazutaka YOKOTA 		warnx("invalid argument `%s'", optarg);
7725f436cfbSKazutaka YOKOTA 		usage();
7735f436cfbSKazutaka YOKOTA 	    }
77413379e47SPeter Wemm 	    debug("rodent baudrate %d", rodent.baudrate);
77513379e47SPeter Wemm 	    break;
776ad771aa1SSøren Schmidt 
777d5f2946aSPhilip Paeps 	case 'T':
778d5f2946aSPhilip Paeps 	    drift_terminate = TRUE;
779d5f2946aSPhilip Paeps 	    sscanf(optarg, "%d,%d,%d", &drift_distance, &drift_time,
780d5f2946aSPhilip Paeps 		&drift_after);
781d5f2946aSPhilip Paeps 	    if (drift_distance <= 0 || drift_time <= 0 || drift_after <= 0) {
782d5f2946aSPhilip Paeps 		warnx("invalid argument `%s'", optarg);
783d5f2946aSPhilip Paeps 		usage();
784d5f2946aSPhilip Paeps 	    }
785d5f2946aSPhilip Paeps 	    debug("terminate drift: distance %d, time %d, after %d",
786d5f2946aSPhilip Paeps 		drift_distance, drift_time, drift_after);
78713f1c59bSJung-uk Kim 	    drift_time_ts.tv_sec = drift_time / 1000;
78813f1c59bSJung-uk Kim 	    drift_time_ts.tv_nsec = (drift_time % 1000) * 1000000;
78913f1c59bSJung-uk Kim  	    drift_2time_ts.tv_sec = (drift_time *= 2) / 1000;
79013f1c59bSJung-uk Kim 	    drift_2time_ts.tv_nsec = (drift_time % 1000) * 1000000;
79113f1c59bSJung-uk Kim 	    drift_after_ts.tv_sec = drift_after / 1000;
79213f1c59bSJung-uk Kim 	    drift_after_ts.tv_nsec = (drift_after % 1000) * 1000000;
793d5f2946aSPhilip Paeps 	    break;
794d5f2946aSPhilip Paeps 
795ad771aa1SSøren Schmidt 	case 't':
79630ee7535SKazutaka YOKOTA 	    if (strcmp(optarg, "auto") == 0) {
79730ee7535SKazutaka YOKOTA 		rodent.rtype = MOUSE_PROTO_UNKNOWN;
79830ee7535SKazutaka YOKOTA 		rodent.flags &= ~NoPnP;
79930ee7535SKazutaka YOKOTA 		rodent.level = -1;
80030ee7535SKazutaka YOKOTA 		break;
80130ee7535SKazutaka YOKOTA 	    }
8022657f6e9SJung-uk Kim 	    for (i = 0; rnames[i] != NULL; i++)
80330ee7535SKazutaka YOKOTA 		if (strcmp(optarg, rnames[i]) == 0) {
804ad771aa1SSøren Schmidt 		    rodent.rtype = i;
80530ee7535SKazutaka YOKOTA 		    rodent.flags |= NoPnP;
80630ee7535SKazutaka YOKOTA 		    rodent.level = (i == MOUSE_PROTO_SYSMOUSE) ? 1 : 0;
807ad771aa1SSøren Schmidt 		    break;
808ad771aa1SSøren Schmidt 		}
8092657f6e9SJung-uk Kim 	    if (rnames[i] == NULL) {
81013379e47SPeter Wemm 		warnx("no such mouse type `%s'", optarg);
811ad771aa1SSøren Schmidt 		usage();
8122657f6e9SJung-uk Kim 	    }
8132657f6e9SJung-uk Kim 	    break;
814ad771aa1SSøren Schmidt 
8152a669c47SPhilip Paeps 	case 'V':
8162a669c47SPhilip Paeps 	    rodent.flags |= VirtualScroll;
8172a669c47SPhilip Paeps 	    break;
8182a669c47SPhilip Paeps 	case 'U':
8192a669c47SPhilip Paeps 	    rodent.scrollthreshold = atoi(optarg);
8202a669c47SPhilip Paeps 	    if (rodent.scrollthreshold < 0) {
8212a669c47SPhilip Paeps 		warnx("invalid argument `%s'", optarg);
8222a669c47SPhilip Paeps 		usage();
8232a669c47SPhilip Paeps 	    }
8242a669c47SPhilip Paeps 	    break;
8252a669c47SPhilip Paeps 
826ad771aa1SSøren Schmidt 	case 'h':
827ad771aa1SSøren Schmidt 	case '?':
828ad771aa1SSøren Schmidt 	default:
829ad771aa1SSøren Schmidt 	    usage();
830ad771aa1SSøren Schmidt 	}
831ad771aa1SSøren Schmidt 
832127d54baSKazutaka YOKOTA     /* fix Z axis mapping */
833127d54baSKazutaka YOKOTA     for (i = 0; i < 4; ++i) {
834127d54baSKazutaka YOKOTA 	if (rodent.zmap[i] > 0) {
835127d54baSKazutaka YOKOTA 	    for (j = 0; j < MOUSE_MAXBUTTON; ++j) {
836127d54baSKazutaka YOKOTA 		if (mstate[j] == &bstate[rodent.zmap[i] - 1])
837127d54baSKazutaka YOKOTA 		    mstate[j] = &zstate[i];
838127d54baSKazutaka YOKOTA 	    }
839127d54baSKazutaka YOKOTA 	    rodent.zmap[i] = 1 << (rodent.zmap[i] - 1);
840127d54baSKazutaka YOKOTA 	}
841127d54baSKazutaka YOKOTA     }
842127d54baSKazutaka YOKOTA 
8435f436cfbSKazutaka YOKOTA     /* the default port name */
8445f436cfbSKazutaka YOKOTA     switch(rodent.rtype) {
8455f436cfbSKazutaka YOKOTA 
8465f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_PS2:
847ad771aa1SSøren Schmidt 	if (!rodent.portname)
848ad771aa1SSøren Schmidt 	    rodent.portname = "/dev/psm0";
849ad771aa1SSøren Schmidt 	break;
8505f436cfbSKazutaka YOKOTA 
851ad771aa1SSøren Schmidt     default:
852ad771aa1SSøren Schmidt 	if (rodent.portname)
853ad771aa1SSøren Schmidt 	    break;
85407e1d533SPhilippe Charnier 	warnx("no port name specified");
855ad771aa1SSøren Schmidt 	usage();
856ad771aa1SSøren Schmidt     }
857ad771aa1SSøren Schmidt 
85808f950a3SHans Petter Selasky     if (strncmp(rodent.portname, "/dev/ums", 8) == 0)
85908f950a3SHans Petter Selasky 	rodent.is_removable = 1;
86049271db4SDag-Erling Smørgrav 
8615f436cfbSKazutaka YOKOTA     for (;;) {
8625f436cfbSKazutaka YOKOTA 	if (setjmp(env) == 0) {
8635f436cfbSKazutaka YOKOTA 	    signal(SIGHUP, hup);
86467978692SAmancio Hasty 	    signal(SIGINT , cleanup);
86567978692SAmancio Hasty 	    signal(SIGQUIT, cleanup);
86667978692SAmancio Hasty 	    signal(SIGTERM, cleanup);
8679eac5bb9SPhilip Paeps 	    signal(SIGUSR1, pause_mouse);
86808f950a3SHans Petter Selasky 
86949271db4SDag-Erling Smørgrav 	    rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK);
87049271db4SDag-Erling Smørgrav 	    if (rodent.mfd == -1)
8715f436cfbSKazutaka YOKOTA 		logerr(1, "unable to open %s", rodent.portname);
8725f436cfbSKazutaka YOKOTA 	    if (r_identify() == MOUSE_PROTO_UNKNOWN) {
8735f436cfbSKazutaka YOKOTA 		logwarnx("cannot determine mouse type on %s", rodent.portname);
8745f436cfbSKazutaka YOKOTA 		close(rodent.mfd);
8755f436cfbSKazutaka YOKOTA 		rodent.mfd = -1;
876ad771aa1SSøren Schmidt 	    }
8775f436cfbSKazutaka YOKOTA 
8785f436cfbSKazutaka YOKOTA 	    /* print some information */
8795f436cfbSKazutaka YOKOTA 	    if (identify != ID_NONE) {
8805f436cfbSKazutaka YOKOTA 		if (identify == ID_ALL)
8815f436cfbSKazutaka YOKOTA 		    printf("%s %s %s %s\n",
8825f436cfbSKazutaka YOKOTA 			rodent.portname, r_if(rodent.hw.iftype),
8835f436cfbSKazutaka YOKOTA 			r_name(rodent.rtype), r_model(rodent.hw.model));
8845f436cfbSKazutaka YOKOTA 		else if (identify & ID_PORT)
8855f436cfbSKazutaka YOKOTA 		    printf("%s\n", rodent.portname);
8865f436cfbSKazutaka YOKOTA 		else if (identify & ID_IF)
8875f436cfbSKazutaka YOKOTA 		    printf("%s\n", r_if(rodent.hw.iftype));
8885f436cfbSKazutaka YOKOTA 		else if (identify & ID_TYPE)
8895f436cfbSKazutaka YOKOTA 		    printf("%s\n", r_name(rodent.rtype));
8905f436cfbSKazutaka YOKOTA 		else if (identify & ID_MODEL)
8915f436cfbSKazutaka YOKOTA 		    printf("%s\n", r_model(rodent.hw.model));
8925f436cfbSKazutaka YOKOTA 		exit(0);
8935f436cfbSKazutaka YOKOTA 	    } else {
8945f436cfbSKazutaka YOKOTA 		debug("port: %s  interface: %s  type: %s  model: %s",
8955f436cfbSKazutaka YOKOTA 		    rodent.portname, r_if(rodent.hw.iftype),
8965f436cfbSKazutaka YOKOTA 		    r_name(rodent.rtype), r_model(rodent.hw.model));
8975f436cfbSKazutaka YOKOTA 	    }
8985f436cfbSKazutaka YOKOTA 
8995f436cfbSKazutaka YOKOTA 	    if (rodent.mfd == -1) {
9005f436cfbSKazutaka YOKOTA 		/*
9015f436cfbSKazutaka YOKOTA 		 * We cannot continue because of error.  Exit if the
9025f436cfbSKazutaka YOKOTA 		 * program has not become a daemon.  Otherwise, block
9036bccea7cSRebecca Cran 		 * until the user corrects the problem and issues SIGHUP.
9045f436cfbSKazutaka YOKOTA 		 */
9055f436cfbSKazutaka YOKOTA 		if (!background)
9065f436cfbSKazutaka YOKOTA 		    exit(1);
9075f436cfbSKazutaka YOKOTA 		sigpause(0);
9085f436cfbSKazutaka YOKOTA 	    }
9095f436cfbSKazutaka YOKOTA 
910ad771aa1SSøren Schmidt 	    r_init();			/* call init function */
9115f436cfbSKazutaka YOKOTA 	    moused();
912ad771aa1SSøren Schmidt 	}
913ad771aa1SSøren Schmidt 
9145f436cfbSKazutaka YOKOTA 	if (rodent.mfd != -1)
9155f436cfbSKazutaka YOKOTA 	    close(rodent.mfd);
9165f436cfbSKazutaka YOKOTA 	if (rodent.cfd != -1)
9175f436cfbSKazutaka YOKOTA 	    close(rodent.cfd);
9185f436cfbSKazutaka YOKOTA 	rodent.mfd = rodent.cfd = -1;
91908f950a3SHans Petter Selasky 	if (rodent.is_removable)
92008f950a3SHans Petter Selasky 		exit(0);
9215f436cfbSKazutaka YOKOTA     }
9225f436cfbSKazutaka YOKOTA     /* NOT REACHED */
9235f436cfbSKazutaka YOKOTA 
9245f436cfbSKazutaka YOKOTA     exit(0);
9255f436cfbSKazutaka YOKOTA }
9265f436cfbSKazutaka YOKOTA 
92786b3ea36SPhilip Paeps /*
928d9338247SPhilip Paeps  * Function to calculate linear acceleration.
929d9338247SPhilip Paeps  *
930d9338247SPhilip Paeps  * If there are any rounding errors, the remainder
931d9338247SPhilip Paeps  * is stored in the remainx and remainy variables
932d9338247SPhilip Paeps  * and taken into account upon the next movement.
933d9338247SPhilip Paeps  */
934d9338247SPhilip Paeps 
935d9338247SPhilip Paeps static void
936d9338247SPhilip Paeps linacc(int dx, int dy, int *movex, int *movey)
937d9338247SPhilip Paeps {
938d9338247SPhilip Paeps     float fdx, fdy;
939d9338247SPhilip Paeps 
940d9338247SPhilip Paeps     if (dx == 0 && dy == 0) {
941d9338247SPhilip Paeps 	*movex = *movey = 0;
942d9338247SPhilip Paeps 	return;
943d9338247SPhilip Paeps     }
944d9338247SPhilip Paeps     fdx = dx * rodent.accelx + rodent.remainx;
945d9338247SPhilip Paeps     fdy = dy * rodent.accely + rodent.remainy;
946d9338247SPhilip Paeps     *movex = lround(fdx);
947d9338247SPhilip Paeps     *movey = lround(fdy);
948d9338247SPhilip Paeps     rodent.remainx = fdx - *movex;
949d9338247SPhilip Paeps     rodent.remainy = fdy - *movey;
950d9338247SPhilip Paeps }
951d9338247SPhilip Paeps 
952d9338247SPhilip Paeps /*
95386b3ea36SPhilip Paeps  * Function to calculate exponential acceleration.
954d9338247SPhilip Paeps  * (Also includes linear acceleration if enabled.)
95586b3ea36SPhilip Paeps  *
95686b3ea36SPhilip Paeps  * In order to give a smoother behaviour, we record the four
95786b3ea36SPhilip Paeps  * most recent non-zero movements and use their average value
95886b3ea36SPhilip Paeps  * to calculate the acceleration.
95986b3ea36SPhilip Paeps  */
96086b3ea36SPhilip Paeps 
96186b3ea36SPhilip Paeps static void
96286b3ea36SPhilip Paeps expoacc(int dx, int dy, int *movex, int *movey)
96386b3ea36SPhilip Paeps {
96486b3ea36SPhilip Paeps     static float lastlength[3] = {0.0, 0.0, 0.0};
96586b3ea36SPhilip Paeps     float fdx, fdy, length, lbase, accel;
96686b3ea36SPhilip Paeps 
96786b3ea36SPhilip Paeps     if (dx == 0 && dy == 0) {
96886b3ea36SPhilip Paeps 	*movex = *movey = 0;
96986b3ea36SPhilip Paeps 	return;
97086b3ea36SPhilip Paeps     }
97186b3ea36SPhilip Paeps     fdx = dx * rodent.accelx;
97286b3ea36SPhilip Paeps     fdy = dy * rodent.accely;
97386b3ea36SPhilip Paeps     length = sqrtf((fdx * fdx) + (fdy * fdy));		/* Pythagoras */
97486b3ea36SPhilip Paeps     length = (length + lastlength[0] + lastlength[1] + lastlength[2]) / 4;
97586b3ea36SPhilip Paeps     lbase = length / rodent.expoffset;
97686b3ea36SPhilip Paeps     accel = powf(lbase, rodent.expoaccel) / lbase;
977d9338247SPhilip Paeps     fdx = fdx * accel + rodent.remainx;
978d9338247SPhilip Paeps     fdy = fdy * accel + rodent.remainy;
979d9338247SPhilip Paeps     *movex = lroundf(fdx);
980d9338247SPhilip Paeps     *movey = lroundf(fdy);
981d9338247SPhilip Paeps     rodent.remainx = fdx - *movex;
982d9338247SPhilip Paeps     rodent.remainy = fdy - *movey;
98386b3ea36SPhilip Paeps     lastlength[2] = lastlength[1];
98486b3ea36SPhilip Paeps     lastlength[1] = lastlength[0];
98586b3ea36SPhilip Paeps     lastlength[0] = length;	/* Insert new average, not original length! */
98686b3ea36SPhilip Paeps }
98786b3ea36SPhilip Paeps 
9885f436cfbSKazutaka YOKOTA static void
9895f436cfbSKazutaka YOKOTA moused(void)
990ad771aa1SSøren Schmidt {
9915f436cfbSKazutaka YOKOTA     struct mouse_info mouse;
99244bdcfa6SKazutaka YOKOTA     mousestatus_t action0;		/* original mouse action */
9933df5ecacSUlrich Spörlein     mousestatus_t action;		/* interim buffer */
9945f436cfbSKazutaka YOKOTA     mousestatus_t action2;		/* mapped action */
99544bdcfa6SKazutaka YOKOTA     struct timeval timeout;
9965f436cfbSKazutaka YOKOTA     fd_set fds;
9975f436cfbSKazutaka YOKOTA     u_char b;
998a80d5fc2SPawel Jakub Dawidek     pid_t mpid;
99944bdcfa6SKazutaka YOKOTA     int flags;
100044bdcfa6SKazutaka YOKOTA     int c;
100144bdcfa6SKazutaka YOKOTA     int i;
10025f436cfbSKazutaka YOKOTA 
10035f436cfbSKazutaka YOKOTA     if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
100462e621e8SIan Dowse 	logerr(1, "cannot open /dev/consolectl");
10055f436cfbSKazutaka YOKOTA 
100662e621e8SIan Dowse     if (!nodaemon && !background) {
10078b28aef2SPawel Jakub Dawidek 	pfh = pidfile_open(pidfile, 0600, &mpid);
1008a80d5fc2SPawel Jakub Dawidek 	if (pfh == NULL) {
1009a80d5fc2SPawel Jakub Dawidek 	    if (errno == EEXIST)
1010a80d5fc2SPawel Jakub Dawidek 		logerrx(1, "moused already running, pid: %d", mpid);
1011a80d5fc2SPawel Jakub Dawidek 	    logwarn("cannot open pid file");
1012a80d5fc2SPawel Jakub Dawidek 	}
10135f436cfbSKazutaka YOKOTA 	if (daemon(0, 0)) {
1014a80d5fc2SPawel Jakub Dawidek 	    int saved_errno = errno;
1015a80d5fc2SPawel Jakub Dawidek 	    pidfile_remove(pfh);
1016a80d5fc2SPawel Jakub Dawidek 	    errno = saved_errno;
101762e621e8SIan Dowse 	    logerr(1, "failed to become a daemon");
10185f436cfbSKazutaka YOKOTA 	} else {
10195f436cfbSKazutaka YOKOTA 	    background = TRUE;
1020a80d5fc2SPawel Jakub Dawidek 	    pidfile_write(pfh);
10215f436cfbSKazutaka YOKOTA 	}
102262e621e8SIan Dowse     }
10235f436cfbSKazutaka YOKOTA 
10245f436cfbSKazutaka YOKOTA     /* clear mouse data */
102544bdcfa6SKazutaka YOKOTA     bzero(&action0, sizeof(action0));
10265f436cfbSKazutaka YOKOTA     bzero(&action, sizeof(action));
10275f436cfbSKazutaka YOKOTA     bzero(&action2, sizeof(action2));
10285f436cfbSKazutaka YOKOTA     bzero(&mouse, sizeof(mouse));
102944bdcfa6SKazutaka YOKOTA     mouse_button_state = S0;
103013f1c59bSJung-uk Kim     clock_gettime(CLOCK_MONOTONIC_FAST, &mouse_button_state_ts);
103170ccc8d8SIan Dowse     mouse_move_delayed = 0;
103244bdcfa6SKazutaka YOKOTA     for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
103344bdcfa6SKazutaka YOKOTA 	bstate[i].count = 0;
103413f1c59bSJung-uk Kim 	bstate[i].ts = mouse_button_state_ts;
103544bdcfa6SKazutaka YOKOTA     }
1036*83409a93SElyes Haouas     for (i = 0; i < (int)nitems(zstate); ++i) {
103744bdcfa6SKazutaka YOKOTA 	zstate[i].count = 0;
103813f1c59bSJung-uk Kim 	zstate[i].ts = mouse_button_state_ts;
103944bdcfa6SKazutaka YOKOTA     }
10405f436cfbSKazutaka YOKOTA 
10415f436cfbSKazutaka YOKOTA     /* choose which ioctl command to use */
10425f436cfbSKazutaka YOKOTA     mouse.operation = MOUSE_MOTION_EVENT;
10435f436cfbSKazutaka YOKOTA     extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0);
10445f436cfbSKazutaka YOKOTA 
10455f436cfbSKazutaka YOKOTA     /* process mouse data */
104644bdcfa6SKazutaka YOKOTA     timeout.tv_sec = 0;
104744bdcfa6SKazutaka YOKOTA     timeout.tv_usec = 20000;		/* 20 msec */
10485f436cfbSKazutaka YOKOTA     for (;;) {
10495f436cfbSKazutaka YOKOTA 
105020a2630bSSøren Schmidt 	FD_ZERO(&fds);
105120a2630bSSøren Schmidt 	FD_SET(rodent.mfd, &fds);
105244bdcfa6SKazutaka YOKOTA 	if (rodent.mremsfd >= 0)
105344bdcfa6SKazutaka YOKOTA 	    FD_SET(rodent.mremsfd, &fds);
105444bdcfa6SKazutaka YOKOTA 	if (rodent.mremcfd >= 0)
105544bdcfa6SKazutaka YOKOTA 	    FD_SET(rodent.mremcfd, &fds);
105667978692SAmancio Hasty 
105744bdcfa6SKazutaka YOKOTA 	c = select(FD_SETSIZE, &fds, NULL, NULL,
1058ce304e08SAlexander Motin 		   ((rodent.flags & Emulate3Button) &&
1059ce304e08SAlexander Motin 		    S_DELAYED(mouse_button_state)) ? &timeout : NULL);
106044bdcfa6SKazutaka YOKOTA 	if (c < 0) {                    /* error */
106162e621e8SIan Dowse 	    logwarn("failed to read from mouse");
106244bdcfa6SKazutaka YOKOTA 	    continue;
106344bdcfa6SKazutaka YOKOTA 	} else if (c == 0) {            /* timeout */
106444bdcfa6SKazutaka YOKOTA 	    /* assert(rodent.flags & Emulate3Button) */
106544bdcfa6SKazutaka YOKOTA 	    action0.button = action0.obutton;
106644bdcfa6SKazutaka YOKOTA 	    action0.dx = action0.dy = action0.dz = 0;
106744bdcfa6SKazutaka YOKOTA 	    action0.flags = flags = 0;
106844bdcfa6SKazutaka YOKOTA 	    if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) {
106944bdcfa6SKazutaka YOKOTA 		if (debug > 2)
107044bdcfa6SKazutaka YOKOTA 		    debug("flags:%08x buttons:%08x obuttons:%08x",
107144bdcfa6SKazutaka YOKOTA 			  action.flags, action.button, action.obutton);
107244bdcfa6SKazutaka YOKOTA 	    } else {
107344bdcfa6SKazutaka YOKOTA 		action0.obutton = action0.button;
107444bdcfa6SKazutaka YOKOTA 		continue;
107544bdcfa6SKazutaka YOKOTA 	    }
107644bdcfa6SKazutaka YOKOTA 	} else {
107767978692SAmancio Hasty 	    /*  MouseRemote client connect/disconnect  */
107867978692SAmancio Hasty 	    if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) {
107967978692SAmancio Hasty 		mremote_clientchg(TRUE);
108067978692SAmancio Hasty 		continue;
108167978692SAmancio Hasty 	    }
108267978692SAmancio Hasty 	    if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) {
108367978692SAmancio Hasty 		mremote_clientchg(FALSE);
108467978692SAmancio Hasty 		continue;
108567978692SAmancio Hasty 	    }
108644bdcfa6SKazutaka YOKOTA 	    /* mouse movement */
108744bdcfa6SKazutaka YOKOTA 	    if (read(rodent.mfd, &b, 1) == -1) {
108844bdcfa6SKazutaka YOKOTA 		if (errno == EWOULDBLOCK)
108944bdcfa6SKazutaka YOKOTA 		    continue;
109044bdcfa6SKazutaka YOKOTA 		else
109144bdcfa6SKazutaka YOKOTA 		    return;
109244bdcfa6SKazutaka YOKOTA 	    }
109344bdcfa6SKazutaka YOKOTA 	    if ((flags = r_protocol(b, &action0)) == 0)
109444bdcfa6SKazutaka YOKOTA 		continue;
10952a669c47SPhilip Paeps 
10962c9b9132SPhilip Paeps 	    if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) {
10972a669c47SPhilip Paeps 		/* Allow middle button drags to scroll up and down */
10982a669c47SPhilip Paeps 		if (action0.button == MOUSE_BUTTON2DOWN) {
10992a669c47SPhilip Paeps 		    if (scroll_state == SCROLL_NOTSCROLLING) {
11002a669c47SPhilip Paeps 			scroll_state = SCROLL_PREPARE;
11013e95467cSPhilip Paeps 			scroll_movement = hscroll_movement = 0;
11022a669c47SPhilip Paeps 			debug("PREPARING TO SCROLL");
11032a669c47SPhilip Paeps 		    }
11042a669c47SPhilip Paeps 		    debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x",
11052a669c47SPhilip Paeps 			  action.flags, action.button, action.obutton);
11062a669c47SPhilip Paeps 		} else {
11072a669c47SPhilip Paeps 		    debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x",
11082a669c47SPhilip Paeps 			  action.flags, action.button, action.obutton);
11092a669c47SPhilip Paeps 
11102a669c47SPhilip Paeps 		    /* This isn't a middle button down... move along... */
11112a669c47SPhilip Paeps 		    if (scroll_state == SCROLL_SCROLLING) {
11122a669c47SPhilip Paeps 			/*
11132a669c47SPhilip Paeps 			 * We were scrolling, someone let go of button 2.
11142a669c47SPhilip Paeps 			 * Now turn autoscroll off.
11152a669c47SPhilip Paeps 			 */
11162a669c47SPhilip Paeps 			scroll_state = SCROLL_NOTSCROLLING;
11172a669c47SPhilip Paeps 			debug("DONE WITH SCROLLING / %d", scroll_state);
11182a669c47SPhilip Paeps 		    } else if (scroll_state == SCROLL_PREPARE) {
11192a669c47SPhilip Paeps 			mousestatus_t newaction = action0;
11202a669c47SPhilip Paeps 
11212a669c47SPhilip Paeps 			/* We were preparing to scroll, but we never moved... */
11222a669c47SPhilip Paeps 			r_timestamp(&action0);
11232a669c47SPhilip Paeps 			r_statetrans(&action0, &newaction,
11242a669c47SPhilip Paeps 				     A(newaction.button & MOUSE_BUTTON1DOWN,
11252a669c47SPhilip Paeps 				       action0.button & MOUSE_BUTTON3DOWN));
11262a669c47SPhilip Paeps 
11272a669c47SPhilip Paeps 			/* Send middle down */
11282a669c47SPhilip Paeps 			newaction.button = MOUSE_BUTTON2DOWN;
11292a669c47SPhilip Paeps 			r_click(&newaction);
11302a669c47SPhilip Paeps 
11312a669c47SPhilip Paeps 			/* Send middle up */
11322a669c47SPhilip Paeps 			r_timestamp(&newaction);
11332a669c47SPhilip Paeps 			newaction.obutton = newaction.button;
11342a669c47SPhilip Paeps 			newaction.button = action0.button;
11352a669c47SPhilip Paeps 			r_click(&newaction);
11362a669c47SPhilip Paeps 		    }
11372a669c47SPhilip Paeps 		}
11382a669c47SPhilip Paeps 	    }
11392a669c47SPhilip Paeps 
114044bdcfa6SKazutaka YOKOTA 	    r_timestamp(&action0);
114144bdcfa6SKazutaka YOKOTA 	    r_statetrans(&action0, &action,
114244bdcfa6SKazutaka YOKOTA 			 A(action0.button & MOUSE_BUTTON1DOWN,
114344bdcfa6SKazutaka YOKOTA 			   action0.button & MOUSE_BUTTON3DOWN));
114444bdcfa6SKazutaka YOKOTA 	    debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
114544bdcfa6SKazutaka YOKOTA 		  action.button, action.obutton);
114644bdcfa6SKazutaka YOKOTA 	}
114744bdcfa6SKazutaka YOKOTA 	action0.obutton = action0.button;
114844bdcfa6SKazutaka YOKOTA 	flags &= MOUSE_POSCHANGED;
114944bdcfa6SKazutaka YOKOTA 	flags |= action.obutton ^ action.button;
115044bdcfa6SKazutaka YOKOTA 	action.flags = flags;
115167978692SAmancio Hasty 
115244bdcfa6SKazutaka YOKOTA 	if (flags) {			/* handler detected action */
11535f436cfbSKazutaka YOKOTA 	    r_map(&action, &action2);
11545f436cfbSKazutaka YOKOTA 	    debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
11555f436cfbSKazutaka YOKOTA 		action2.button, action2.dx, action2.dy, action2.dz);
11565f436cfbSKazutaka YOKOTA 
11572c9b9132SPhilip Paeps 	    if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) {
11582a669c47SPhilip Paeps 		/*
11592a669c47SPhilip Paeps 		 * If *only* the middle button is pressed AND we are moving
11602a669c47SPhilip Paeps 		 * the stick/trackpoint/nipple, scroll!
11612a669c47SPhilip Paeps 		 */
11622a669c47SPhilip Paeps 		if (scroll_state == SCROLL_PREPARE) {
11633e95467cSPhilip Paeps 			/* Middle button down, waiting for movement threshold */
11643e95467cSPhilip Paeps 			if (action2.dy || action2.dx) {
11653e95467cSPhilip Paeps 				if (rodent.flags & VirtualScroll) {
11663e95467cSPhilip Paeps 					scroll_movement += action2.dy;
11673e95467cSPhilip Paeps 					if (scroll_movement < -rodent.scrollthreshold) {
11683e95467cSPhilip Paeps 						scroll_state = SCROLL_SCROLLING;
11693e95467cSPhilip Paeps 					} else if (scroll_movement > rodent.scrollthreshold) {
11702a669c47SPhilip Paeps 						scroll_state = SCROLL_SCROLLING;
11712a669c47SPhilip Paeps 					}
11723e95467cSPhilip Paeps 				}
11733e95467cSPhilip Paeps 				if (rodent.flags & HVirtualScroll) {
11743e95467cSPhilip Paeps 					hscroll_movement += action2.dx;
11753e95467cSPhilip Paeps 					if (hscroll_movement < -rodent.scrollthreshold) {
11763e95467cSPhilip Paeps 						scroll_state = SCROLL_SCROLLING;
11773e95467cSPhilip Paeps 					} else if (hscroll_movement > rodent.scrollthreshold) {
11783e95467cSPhilip Paeps 						scroll_state = SCROLL_SCROLLING;
11793e95467cSPhilip Paeps 					}
11803e95467cSPhilip Paeps 				}
11813e95467cSPhilip Paeps 				if (scroll_state == SCROLL_SCROLLING) scroll_movement = hscroll_movement = 0;
11823e95467cSPhilip Paeps 			}
11833e95467cSPhilip Paeps 		} else if (scroll_state == SCROLL_SCROLLING) {
11842c9b9132SPhilip Paeps 			 if (rodent.flags & VirtualScroll) {
11852a669c47SPhilip Paeps 				 scroll_movement += action2.dy;
11862a669c47SPhilip Paeps 				 debug("SCROLL: %d", scroll_movement);
11873e95467cSPhilip Paeps 			    if (scroll_movement < -rodent.scrollspeed) {
11882a669c47SPhilip Paeps 				/* Scroll down */
11892a669c47SPhilip Paeps 				action2.dz = -1;
11902a669c47SPhilip Paeps 				scroll_movement = 0;
11912a669c47SPhilip Paeps 			    }
11923e95467cSPhilip Paeps 			    else if (scroll_movement > rodent.scrollspeed) {
11932a669c47SPhilip Paeps 				/* Scroll up */
11942a669c47SPhilip Paeps 				action2.dz = 1;
11952a669c47SPhilip Paeps 				scroll_movement = 0;
11962a669c47SPhilip Paeps 			    }
11972c9b9132SPhilip Paeps 			 }
11982c9b9132SPhilip Paeps 			 if (rodent.flags & HVirtualScroll) {
11992c9b9132SPhilip Paeps 				 hscroll_movement += action2.dx;
12002c9b9132SPhilip Paeps 				 debug("HORIZONTAL SCROLL: %d", hscroll_movement);
12012c9b9132SPhilip Paeps 
12023e95467cSPhilip Paeps 				 if (hscroll_movement < -rodent.scrollspeed) {
12032c9b9132SPhilip Paeps 					 action2.dz = -2;
12042c9b9132SPhilip Paeps 					 hscroll_movement = 0;
12052c9b9132SPhilip Paeps 				 }
12063e95467cSPhilip Paeps 				 else if (hscroll_movement > rodent.scrollspeed) {
12072c9b9132SPhilip Paeps 					 action2.dz = 2;
12082c9b9132SPhilip Paeps 					 hscroll_movement = 0;
12092c9b9132SPhilip Paeps 				 }
12102c9b9132SPhilip Paeps 			 }
12112a669c47SPhilip Paeps 
12122a669c47SPhilip Paeps 		    /* Don't move while scrolling */
12132a669c47SPhilip Paeps 		    action2.dx = action2.dy = 0;
12142a669c47SPhilip Paeps 		}
12152a669c47SPhilip Paeps 	    }
12162a669c47SPhilip Paeps 
1217d5f2946aSPhilip Paeps 	    if (drift_terminate) {
12182657f6e9SJung-uk Kim 		if ((flags & MOUSE_POSCHANGED) == 0 || action.dz || action2.dz)
121913f1c59bSJung-uk Kim 		    drift_last_activity = drift_current_ts;
1220d5f2946aSPhilip Paeps 		else {
1221d5f2946aSPhilip Paeps 		    /* X or/and Y movement only - possibly drift */
122213f1c59bSJung-uk Kim 		    tssub(&drift_current_ts, &drift_last_activity, &drift_tmp);
122313f1c59bSJung-uk Kim 		    if (tscmp(&drift_tmp, &drift_after_ts, >)) {
122413f1c59bSJung-uk Kim 			tssub(&drift_current_ts, &drift_since, &drift_tmp);
122513f1c59bSJung-uk Kim 			if (tscmp(&drift_tmp, &drift_time_ts, <)) {
1226d5f2946aSPhilip Paeps 			    drift_last.x += action2.dx;
1227d5f2946aSPhilip Paeps 			    drift_last.y += action2.dy;
1228d5f2946aSPhilip Paeps 			} else {
1229d5f2946aSPhilip Paeps 			    /* discard old accumulated steps (drift) */
123013f1c59bSJung-uk Kim 			    if (tscmp(&drift_tmp, &drift_2time_ts, >))
1231d5f2946aSPhilip Paeps 				drift_previous.x = drift_previous.y = 0;
1232d5f2946aSPhilip Paeps 			    else
1233d5f2946aSPhilip Paeps 				drift_previous = drift_last;
1234d5f2946aSPhilip Paeps 			    drift_last.x = action2.dx;
1235d5f2946aSPhilip Paeps 			    drift_last.y = action2.dy;
123613f1c59bSJung-uk Kim 			    drift_since = drift_current_ts;
1237d5f2946aSPhilip Paeps 			}
1238d5f2946aSPhilip Paeps 			if (abs(drift_last.x) + abs(drift_last.y)
1239d5f2946aSPhilip Paeps 			  > drift_distance) {
1240d5f2946aSPhilip Paeps 			    /* real movement, pass all accumulated steps */
1241d5f2946aSPhilip Paeps 			    action2.dx = drift_previous.x + drift_last.x;
1242d5f2946aSPhilip Paeps 			    action2.dy = drift_previous.y + drift_last.y;
1243d5f2946aSPhilip Paeps 			    /* and reset accumulators */
124413f1c59bSJung-uk Kim 			    tsclr(&drift_since);
1245d5f2946aSPhilip Paeps 			    drift_last.x = drift_last.y = 0;
1246d5f2946aSPhilip Paeps 			    /* drift_previous will be cleared at next movement*/
124713f1c59bSJung-uk Kim 			    drift_last_activity = drift_current_ts;
1248d5f2946aSPhilip Paeps 			} else {
1249d5f2946aSPhilip Paeps 			    continue;   /* don't pass current movement to
1250d5f2946aSPhilip Paeps 					 * console driver */
1251d5f2946aSPhilip Paeps 			}
1252d5f2946aSPhilip Paeps 		    }
1253d5f2946aSPhilip Paeps 		}
1254d5f2946aSPhilip Paeps 	    }
1255d5f2946aSPhilip Paeps 
12565f436cfbSKazutaka YOKOTA 	    if (extioctl) {
12572a669c47SPhilip Paeps 		/* Defer clicks until we aren't VirtualScroll'ing. */
12582a669c47SPhilip Paeps 		if (scroll_state == SCROLL_NOTSCROLLING)
12595f436cfbSKazutaka YOKOTA 		    r_click(&action2);
12602a669c47SPhilip Paeps 
12615f436cfbSKazutaka YOKOTA 		if (action2.flags & MOUSE_POSCHANGED) {
12625f436cfbSKazutaka YOKOTA 		    mouse.operation = MOUSE_MOTION_EVENT;
12635f436cfbSKazutaka YOKOTA 		    mouse.u.data.buttons = action2.button;
126486b3ea36SPhilip Paeps 		    if (rodent.flags & ExponentialAcc) {
126586b3ea36SPhilip Paeps 			expoacc(action2.dx, action2.dy,
126686b3ea36SPhilip Paeps 			    &mouse.u.data.x, &mouse.u.data.y);
126786b3ea36SPhilip Paeps 		    }
126886b3ea36SPhilip Paeps 		    else {
1269d9338247SPhilip Paeps 			linacc(action2.dx, action2.dy,
1270d9338247SPhilip Paeps 			    &mouse.u.data.x, &mouse.u.data.y);
127186b3ea36SPhilip Paeps 		    }
12725f436cfbSKazutaka YOKOTA 		    mouse.u.data.z = action2.dz;
12735f436cfbSKazutaka YOKOTA 		    if (debug < 2)
12749eac5bb9SPhilip Paeps 			if (!paused)
12755f436cfbSKazutaka YOKOTA 				ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1276ad771aa1SSøren Schmidt 		}
12775f436cfbSKazutaka YOKOTA 	    } else {
1278ad0c0c78SSøren Schmidt 		mouse.operation = MOUSE_ACTION;
12795f436cfbSKazutaka YOKOTA 		mouse.u.data.buttons = action2.button;
128086b3ea36SPhilip Paeps 		if (rodent.flags & ExponentialAcc) {
128186b3ea36SPhilip Paeps 		    expoacc(action2.dx, action2.dy,
128286b3ea36SPhilip Paeps 			&mouse.u.data.x, &mouse.u.data.y);
128386b3ea36SPhilip Paeps 		}
128486b3ea36SPhilip Paeps 		else {
1285d9338247SPhilip Paeps 		    linacc(action2.dx, action2.dy,
1286d9338247SPhilip Paeps 			&mouse.u.data.x, &mouse.u.data.y);
128786b3ea36SPhilip Paeps 		}
12885f436cfbSKazutaka YOKOTA 		mouse.u.data.z = action2.dz;
12895f436cfbSKazutaka YOKOTA 		if (debug < 2)
12909eac5bb9SPhilip Paeps 		    if (!paused)
12915f436cfbSKazutaka YOKOTA 			ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1292ad771aa1SSøren Schmidt 	    }
1293ad771aa1SSøren Schmidt 
12945f436cfbSKazutaka YOKOTA 	    /*
12959d5abbddSJens Schweikhardt 	     * If the Z axis movement is mapped to an imaginary physical
12965f436cfbSKazutaka YOKOTA 	     * button, we need to cook up a corresponding button `up' event
12975f436cfbSKazutaka YOKOTA 	     * after sending a button `down' event.
12985f436cfbSKazutaka YOKOTA 	     */
1299fb966343SKazutaka YOKOTA 	    if ((rodent.zmap[0] > 0) && (action.dz != 0)) {
13005f436cfbSKazutaka YOKOTA 		action.obutton = action.button;
13015f436cfbSKazutaka YOKOTA 		action.dx = action.dy = action.dz = 0;
13025f436cfbSKazutaka YOKOTA 		r_map(&action, &action2);
13035f436cfbSKazutaka YOKOTA 		debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
13045f436cfbSKazutaka YOKOTA 		    action2.button, action2.dx, action2.dy, action2.dz);
13055f436cfbSKazutaka YOKOTA 
13065f436cfbSKazutaka YOKOTA 		if (extioctl) {
13075f436cfbSKazutaka YOKOTA 		    r_click(&action2);
13085f436cfbSKazutaka YOKOTA 		} else {
13095f436cfbSKazutaka YOKOTA 		    mouse.operation = MOUSE_ACTION;
13105f436cfbSKazutaka YOKOTA 		    mouse.u.data.buttons = action2.button;
13115f436cfbSKazutaka YOKOTA 		    mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
13125f436cfbSKazutaka YOKOTA 		    if (debug < 2)
13139eac5bb9SPhilip Paeps 			if (!paused)
13145f436cfbSKazutaka YOKOTA 			    ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
13155f436cfbSKazutaka YOKOTA 		}
13165f436cfbSKazutaka YOKOTA 	    }
13175f436cfbSKazutaka YOKOTA 	}
13185f436cfbSKazutaka YOKOTA     }
13195f436cfbSKazutaka YOKOTA     /* NOT REACHED */
13205f436cfbSKazutaka YOKOTA }
13215f436cfbSKazutaka YOKOTA 
13225f436cfbSKazutaka YOKOTA static void
13232657f6e9SJung-uk Kim hup(__unused int sig)
13245f436cfbSKazutaka YOKOTA {
13255f436cfbSKazutaka YOKOTA     longjmp(env, 1);
13265f436cfbSKazutaka YOKOTA }
1327ad771aa1SSøren Schmidt 
132867978692SAmancio Hasty static void
13292657f6e9SJung-uk Kim cleanup(__unused int sig)
133067978692SAmancio Hasty {
133167978692SAmancio Hasty     if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM)
133267978692SAmancio Hasty 	unlink(_PATH_MOUSEREMOTE);
133367978692SAmancio Hasty     exit(0);
133467978692SAmancio Hasty }
133567978692SAmancio Hasty 
13369eac5bb9SPhilip Paeps static void
13372657f6e9SJung-uk Kim pause_mouse(__unused int sig)
13389eac5bb9SPhilip Paeps {
13399eac5bb9SPhilip Paeps     paused = !paused;
13409eac5bb9SPhilip Paeps }
13419eac5bb9SPhilip Paeps 
1342ad771aa1SSøren Schmidt /**
1343ad771aa1SSøren Schmidt  ** usage
1344ad771aa1SSøren Schmidt  **
1345ad771aa1SSøren Schmidt  ** Complain, and free the CPU for more worthy tasks
1346ad771aa1SSøren Schmidt  **/
13475f436cfbSKazutaka YOKOTA static void
1348ad771aa1SSøren Schmidt usage(void)
1349ad771aa1SSøren Schmidt {
1350d5f2946aSPhilip Paeps     fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
135144bdcfa6SKazutaka YOKOTA 	"usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
13522c9b9132SPhilip Paeps 	"              [-VH [-U threshold]] [-a X[,Y]] [-C threshold] [-m N=M] [-w N]",
1353d5f2946aSPhilip Paeps 	"              [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]]",
1354d5f2946aSPhilip Paeps 	"              [-T distance[,time[,after]]] -p <port>",
1355040eea4cSDoug Barton 	"       moused [-d] -i <port|if|type|model|all> -p <port>");
1356ad771aa1SSøren Schmidt     exit(1);
1357ad771aa1SSøren Schmidt }
1358ad771aa1SSøren Schmidt 
135962e621e8SIan Dowse /*
136062e621e8SIan Dowse  * Output an error message to syslog or stderr as appropriate. If
136162e621e8SIan Dowse  * `errnum' is non-zero, append its string form to the message.
136262e621e8SIan Dowse  */
136362e621e8SIan Dowse static void
136462e621e8SIan Dowse log_or_warn(int log_pri, int errnum, const char *fmt, ...)
136562e621e8SIan Dowse {
136662e621e8SIan Dowse 	va_list ap;
136762e621e8SIan Dowse 	char buf[256];
136862e621e8SIan Dowse 
136962e621e8SIan Dowse 	va_start(ap, fmt);
137062e621e8SIan Dowse 	vsnprintf(buf, sizeof(buf), fmt, ap);
137162e621e8SIan Dowse 	va_end(ap);
137262e621e8SIan Dowse 	if (errnum) {
137362e621e8SIan Dowse 		strlcat(buf, ": ", sizeof(buf));
137462e621e8SIan Dowse 		strlcat(buf, strerror(errnum), sizeof(buf));
137562e621e8SIan Dowse 	}
137662e621e8SIan Dowse 
137762e621e8SIan Dowse 	if (background)
137862e621e8SIan Dowse 		syslog(log_pri, "%s", buf);
137962e621e8SIan Dowse 	else
138062e621e8SIan Dowse 		warnx("%s", buf);
138162e621e8SIan Dowse }
138262e621e8SIan Dowse 
1383ad771aa1SSøren Schmidt /**
1384ad771aa1SSøren Schmidt  ** Mouse interface code, courtesy of XFree86 3.1.2.
1385ad771aa1SSøren Schmidt  **
1386ad771aa1SSøren Schmidt  ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
1387ad771aa1SSøren Schmidt  ** to clean, reformat and rationalise naming, it's quite possible that
1388ad771aa1SSøren Schmidt  ** some things in here have been broken.
1389ad771aa1SSøren Schmidt  **
1390ad771aa1SSøren Schmidt  ** I hope not 8)
1391ad771aa1SSøren Schmidt  **
1392ad771aa1SSøren Schmidt  ** The following code is derived from a module marked :
1393ad771aa1SSøren Schmidt  **/
1394ad771aa1SSøren Schmidt 
1395ad771aa1SSøren Schmidt /* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
1396ad771aa1SSøren Schmidt /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
1397ad771aa1SSøren Schmidt  17:03:40 dawes Exp $ */
1398ad771aa1SSøren Schmidt /*
1399ad771aa1SSøren Schmidt  *
1400ad771aa1SSøren Schmidt  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
1401ad771aa1SSøren Schmidt  * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
1402ad771aa1SSøren Schmidt  *
1403ad771aa1SSøren Schmidt  * Permission to use, copy, modify, distribute, and sell this software and its
1404ad771aa1SSøren Schmidt  * documentation for any purpose is hereby granted without fee, provided that
1405ad771aa1SSøren Schmidt  * the above copyright notice appear in all copies and that both that
1406ad771aa1SSøren Schmidt  * copyright notice and this permission notice appear in supporting
1407ad771aa1SSøren Schmidt  * documentation, and that the names of Thomas Roell and David Dawes not be
1408ad771aa1SSøren Schmidt  * used in advertising or publicity pertaining to distribution of the
1409ad771aa1SSøren Schmidt  * software without specific, written prior permission.  Thomas Roell
1410ad771aa1SSøren Schmidt  * and David Dawes makes no representations about the suitability of this
1411ad771aa1SSøren Schmidt  * software for any purpose.  It is provided "as is" without express or
1412ad771aa1SSøren Schmidt  * implied warranty.
1413ad771aa1SSøren Schmidt  *
1414ad771aa1SSøren Schmidt  * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
1415ad771aa1SSøren Schmidt  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1416ad771aa1SSøren Schmidt  * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
1417ad771aa1SSøren Schmidt  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
1418ad771aa1SSøren Schmidt  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
1419ad771aa1SSøren Schmidt  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1420ad771aa1SSøren Schmidt  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1421ad771aa1SSøren Schmidt  *
1422ad771aa1SSøren Schmidt  */
1423ad771aa1SSøren Schmidt 
14245f436cfbSKazutaka YOKOTA /**
14255f436cfbSKazutaka YOKOTA  ** GlidePoint support from XFree86 3.2.
14265f436cfbSKazutaka YOKOTA  ** Derived from the module:
14275f436cfbSKazutaka YOKOTA  **/
1428ad771aa1SSøren Schmidt 
14295f436cfbSKazutaka YOKOTA /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
14305f436cfbSKazutaka YOKOTA /* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
14315f436cfbSKazutaka YOKOTA 
14325f436cfbSKazutaka YOKOTA /* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
14335f436cfbSKazutaka YOKOTA static unsigned char proto[][7] = {
14345f436cfbSKazutaka YOKOTA     /*  hd_mask hd_id   dp_mask dp_id   bytes b4_mask b4_id */
14355f436cfbSKazutaka YOKOTA     {	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* MicroSoft */
14365f436cfbSKazutaka YOKOTA     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* MouseSystems */
14375f436cfbSKazutaka YOKOTA     {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* Logitech */
14385f436cfbSKazutaka YOKOTA     {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MMSeries */
143936b1e17dSKazutaka YOKOTA     {	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* MouseMan */
14405f436cfbSKazutaka YOKOTA     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* Bus */
14415f436cfbSKazutaka YOKOTA     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* InPort */
14425f436cfbSKazutaka YOKOTA     {	0xc0,	0x00,	0x00,	0x00,	3,    0x00,  0xff }, /* PS/2 mouse */
14435f436cfbSKazutaka YOKOTA     {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MM HitTablet */
14445f436cfbSKazutaka YOKOTA     {	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* GlidePoint */
14455f436cfbSKazutaka YOKOTA     {	0x40,	0x40,	0x40,	0x00,	3,   ~0x3f,  0x00 }, /* IntelliMouse */
14465f436cfbSKazutaka YOKOTA     {	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* ThinkingMouse */
14475f436cfbSKazutaka YOKOTA     {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* sysmouse */
144867978692SAmancio Hasty     {	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* X10 MouseRem */
14491b11ca6cSKazutaka YOKOTA     {	0x80,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* KIDSPAD */
14502e09fb67SKazutaka YOKOTA     {	0xc3,	0xc0,	0x00,	0x00,	6,    0x00,  0xff }, /* VersaPad */
145105f92020SWill Andrews     {	0x00,	0x00,	0x00,	0x00,	1,    0x00,  0xff }, /* JogDial */
14525f436cfbSKazutaka YOKOTA #if notyet
14535f436cfbSKazutaka YOKOTA     {	0xf8,	0x80,	0x00,	0x00,	5,   ~0x2f,  0x10 }, /* Mariqua */
14545f436cfbSKazutaka YOKOTA #endif
14555f436cfbSKazutaka YOKOTA };
14565f436cfbSKazutaka YOKOTA static unsigned char cur_proto[7];
14575f436cfbSKazutaka YOKOTA 
14585f436cfbSKazutaka YOKOTA static int
14595f436cfbSKazutaka YOKOTA r_identify(void)
14605f436cfbSKazutaka YOKOTA {
14615f436cfbSKazutaka YOKOTA     char pnpbuf[256];	/* PnP identifier string may be up to 256 bytes long */
14625f436cfbSKazutaka YOKOTA     pnpid_t pnpid;
14635f436cfbSKazutaka YOKOTA     symtab_t *t;
14645f436cfbSKazutaka YOKOTA     int level;
14655f436cfbSKazutaka YOKOTA     int len;
14665f436cfbSKazutaka YOKOTA 
14675f436cfbSKazutaka YOKOTA     /* set the driver operation level, if applicable */
14685f436cfbSKazutaka YOKOTA     if (rodent.level < 0)
14695f436cfbSKazutaka YOKOTA 	rodent.level = 1;
14705f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level);
14715f436cfbSKazutaka YOKOTA     rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0;
14725f436cfbSKazutaka YOKOTA 
14735f436cfbSKazutaka YOKOTA     /*
14745f436cfbSKazutaka YOKOTA      * Interrogate the driver and get some intelligence on the device...
14755f436cfbSKazutaka YOKOTA      * The following ioctl functions are not always supported by device
14765f436cfbSKazutaka YOKOTA      * drivers.  When the driver doesn't support them, we just trust the
14775f436cfbSKazutaka YOKOTA      * user to supply valid information.
14785f436cfbSKazutaka YOKOTA      */
14795f436cfbSKazutaka YOKOTA     rodent.hw.iftype = MOUSE_IF_UNKNOWN;
14805f436cfbSKazutaka YOKOTA     rodent.hw.model = MOUSE_MODEL_GENERIC;
14815f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw);
14825f436cfbSKazutaka YOKOTA 
14835f436cfbSKazutaka YOKOTA     if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
14845f436cfbSKazutaka YOKOTA 	bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
14855f436cfbSKazutaka YOKOTA     rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
14865f436cfbSKazutaka YOKOTA     rodent.mode.rate = -1;
14875f436cfbSKazutaka YOKOTA     rodent.mode.resolution = MOUSE_RES_UNKNOWN;
14885f436cfbSKazutaka YOKOTA     rodent.mode.accelfactor = 0;
14895f436cfbSKazutaka YOKOTA     rodent.mode.level = 0;
14905f436cfbSKazutaka YOKOTA     if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) {
14912657f6e9SJung-uk Kim 	if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN ||
1492*83409a93SElyes Haouas 	    rodent.mode.protocol >= (int)nitems(proto)) {
14935f436cfbSKazutaka YOKOTA 	    logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol);
14942657f6e9SJung-uk Kim 	    return (MOUSE_PROTO_UNKNOWN);
14955f436cfbSKazutaka YOKOTA 	} else {
14965f436cfbSKazutaka YOKOTA 	    if (rodent.mode.protocol != rodent.rtype) {
14975f436cfbSKazutaka YOKOTA 		/* Hmm, the driver doesn't agree with the user... */
14985f436cfbSKazutaka YOKOTA 		if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
14995f436cfbSKazutaka YOKOTA 		    logwarnx("mouse type mismatch (%s != %s), %s is assumed",
15005f436cfbSKazutaka YOKOTA 			r_name(rodent.mode.protocol), r_name(rodent.rtype),
15015f436cfbSKazutaka YOKOTA 			r_name(rodent.mode.protocol));
15025f436cfbSKazutaka YOKOTA 		rodent.rtype = rodent.mode.protocol;
15035f436cfbSKazutaka YOKOTA 		bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
15045f436cfbSKazutaka YOKOTA 	    }
15055f436cfbSKazutaka YOKOTA 	}
15065f436cfbSKazutaka YOKOTA 	cur_proto[4] = rodent.mode.packetsize;
15075f436cfbSKazutaka YOKOTA 	cur_proto[0] = rodent.mode.syncmask[0];	/* header byte bit mask */
15085f436cfbSKazutaka YOKOTA 	cur_proto[1] = rodent.mode.syncmask[1];	/* header bit pattern */
15095f436cfbSKazutaka YOKOTA     }
15105f436cfbSKazutaka YOKOTA 
1511d64ada50SJens Schweikhardt     /* maybe this is a PnP mouse... */
15125f436cfbSKazutaka YOKOTA     if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) {
15135f436cfbSKazutaka YOKOTA 
15145f436cfbSKazutaka YOKOTA 	if (rodent.flags & NoPnP)
15152657f6e9SJung-uk Kim 	    return (rodent.rtype);
15165f436cfbSKazutaka YOKOTA 	if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len))
15172657f6e9SJung-uk Kim 	    return (rodent.rtype);
15185f436cfbSKazutaka YOKOTA 
15195f436cfbSKazutaka YOKOTA 	debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
15205f436cfbSKazutaka YOKOTA 	    pnpid.neisaid, pnpid.neisaid, pnpid.eisaid,
15215f436cfbSKazutaka YOKOTA 	    pnpid.ncompat, pnpid.ncompat, pnpid.compat,
15225f436cfbSKazutaka YOKOTA 	    pnpid.ndescription, pnpid.ndescription, pnpid.description);
15235f436cfbSKazutaka YOKOTA 
15245f436cfbSKazutaka YOKOTA 	/* we have a valid PnP serial device ID */
15255f436cfbSKazutaka YOKOTA 	rodent.hw.iftype = MOUSE_IF_SERIAL;
15265f436cfbSKazutaka YOKOTA 	t = pnpproto(&pnpid);
15275f436cfbSKazutaka YOKOTA 	if (t != NULL) {
15285f436cfbSKazutaka YOKOTA 	    rodent.mode.protocol = t->val;
15295f436cfbSKazutaka YOKOTA 	    rodent.hw.model = t->val2;
15305f436cfbSKazutaka YOKOTA 	} else {
15315f436cfbSKazutaka YOKOTA 	    rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
15325f436cfbSKazutaka YOKOTA 	}
15335f436cfbSKazutaka YOKOTA 
15345f436cfbSKazutaka YOKOTA 	/* make final adjustment */
15355f436cfbSKazutaka YOKOTA 	if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) {
15365f436cfbSKazutaka YOKOTA 	    if (rodent.mode.protocol != rodent.rtype) {
15375f436cfbSKazutaka YOKOTA 		/* Hmm, the device doesn't agree with the user... */
15385f436cfbSKazutaka YOKOTA 		if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
15395f436cfbSKazutaka YOKOTA 		    logwarnx("mouse type mismatch (%s != %s), %s is assumed",
15405f436cfbSKazutaka YOKOTA 			r_name(rodent.mode.protocol), r_name(rodent.rtype),
15415f436cfbSKazutaka YOKOTA 			r_name(rodent.mode.protocol));
15425f436cfbSKazutaka YOKOTA 		rodent.rtype = rodent.mode.protocol;
15435f436cfbSKazutaka YOKOTA 		bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
15445f436cfbSKazutaka YOKOTA 	    }
15455f436cfbSKazutaka YOKOTA 	}
15465f436cfbSKazutaka YOKOTA     }
15475f436cfbSKazutaka YOKOTA 
15485f436cfbSKazutaka YOKOTA     debug("proto params: %02x %02x %02x %02x %d %02x %02x",
15495f436cfbSKazutaka YOKOTA 	cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3],
15505f436cfbSKazutaka YOKOTA 	cur_proto[4], cur_proto[5], cur_proto[6]);
15515f436cfbSKazutaka YOKOTA 
15522657f6e9SJung-uk Kim     return (rodent.rtype);
15535f436cfbSKazutaka YOKOTA }
15545f436cfbSKazutaka YOKOTA 
15552657f6e9SJung-uk Kim static const char *
15565f436cfbSKazutaka YOKOTA r_if(int iftype)
15575f436cfbSKazutaka YOKOTA {
15585f436cfbSKazutaka YOKOTA 
15592657f6e9SJung-uk Kim     return (gettokenname(rifs, iftype));
15605f436cfbSKazutaka YOKOTA }
15615f436cfbSKazutaka YOKOTA 
15622657f6e9SJung-uk Kim static const char *
15635f436cfbSKazutaka YOKOTA r_name(int type)
15645f436cfbSKazutaka YOKOTA {
15652657f6e9SJung-uk Kim     const char *unknown = "unknown";
15662657f6e9SJung-uk Kim 
1567*83409a93SElyes Haouas     return (type == MOUSE_PROTO_UNKNOWN || type >= (int)nitems(rnames) ?
15682657f6e9SJung-uk Kim 	unknown : rnames[type]);
15695f436cfbSKazutaka YOKOTA }
15705f436cfbSKazutaka YOKOTA 
15712657f6e9SJung-uk Kim static const char *
15725f436cfbSKazutaka YOKOTA r_model(int model)
15735f436cfbSKazutaka YOKOTA {
15745f436cfbSKazutaka YOKOTA 
15752657f6e9SJung-uk Kim     return (gettokenname(rmodels, model));
15765f436cfbSKazutaka YOKOTA }
15775f436cfbSKazutaka YOKOTA 
15785f436cfbSKazutaka YOKOTA static void
1579ad771aa1SSøren Schmidt r_init(void)
1580ad771aa1SSøren Schmidt {
15812e09fb67SKazutaka YOKOTA     unsigned char buf[16];	/* scrach buffer */
15825f436cfbSKazutaka YOKOTA     fd_set fds;
15832657f6e9SJung-uk Kim     const char *s;
15845f436cfbSKazutaka YOKOTA     char c;
15855f436cfbSKazutaka YOKOTA     int i;
15865f436cfbSKazutaka YOKOTA 
1587ad771aa1SSøren Schmidt     /**
1588ad771aa1SSøren Schmidt      ** This comment is a little out of context here, but it contains
1589ad771aa1SSøren Schmidt      ** some useful information...
1590ad771aa1SSøren Schmidt      ********************************************************************
1591ad771aa1SSøren Schmidt      **
1592ad771aa1SSøren Schmidt      ** The following lines take care of the Logitech MouseMan protocols.
1593ad771aa1SSøren Schmidt      **
1594ad771aa1SSøren Schmidt      ** NOTE: There are different versions of both MouseMan and TrackMan!
1595ad771aa1SSøren Schmidt      **       Hence I add another protocol P_LOGIMAN, which the user can
1596ad771aa1SSøren Schmidt      **       specify as MouseMan in his XF86Config file. This entry was
1597ad771aa1SSøren Schmidt      **       formerly handled as a special case of P_MS. However, people
1598ad771aa1SSøren Schmidt      **       who don't have the middle button problem, can still specify
1599ad771aa1SSøren Schmidt      **       Microsoft and use P_MS.
1600ad771aa1SSøren Schmidt      **
1601ad771aa1SSøren Schmidt      ** By default, these mice should use a 3 byte Microsoft protocol
1602ad771aa1SSøren Schmidt      ** plus a 4th byte for the middle button. However, the mouse might
1603ad771aa1SSøren Schmidt      ** have switched to a different protocol before we use it, so I send
1604ad771aa1SSøren Schmidt      ** the proper sequence just in case.
1605ad771aa1SSøren Schmidt      **
1606ad771aa1SSøren Schmidt      ** NOTE: - all commands to (at least the European) MouseMan have to
1607ad771aa1SSøren Schmidt      **         be sent at 1200 Baud.
1608ad771aa1SSøren Schmidt      **       - each command starts with a '*'.
1609ad771aa1SSøren Schmidt      **       - whenever the MouseMan receives a '*', it will switch back
1610ad771aa1SSøren Schmidt      **	 to 1200 Baud. Hence I have to select the desired protocol
1611ad771aa1SSøren Schmidt      **	 first, then select the baud rate.
1612ad771aa1SSøren Schmidt      **
1613ad771aa1SSøren Schmidt      ** The protocols supported by the (European) MouseMan are:
1614ad771aa1SSøren Schmidt      **   -  5 byte packed binary protocol, as with the Mouse Systems
1615ad771aa1SSøren Schmidt      **      mouse. Selected by sequence "*U".
1616ad771aa1SSøren Schmidt      **   -  2 button 3 byte MicroSoft compatible protocol. Selected
1617ad771aa1SSøren Schmidt      **      by sequence "*V".
1618ad771aa1SSøren Schmidt      **   -  3 button 3+1 byte MicroSoft compatible protocol (default).
1619ad771aa1SSøren Schmidt      **      Selected by sequence "*X".
1620ad771aa1SSøren Schmidt      **
1621ad771aa1SSøren Schmidt      ** The following baud rates are supported:
1622ad771aa1SSøren Schmidt      **   -  1200 Baud (default). Selected by sequence "*n".
1623ad771aa1SSøren Schmidt      **   -  9600 Baud. Selected by sequence "*q".
1624ad771aa1SSøren Schmidt      **
1625ad771aa1SSøren Schmidt      ** Selecting a sample rate is no longer supported with the MouseMan!
1626ad771aa1SSøren Schmidt      ** Some additional lines in xf86Config.c take care of ill configured
1627ad771aa1SSøren Schmidt      ** baud rates and sample rates. (The user will get an error.)
1628ad771aa1SSøren Schmidt      */
1629ad771aa1SSøren Schmidt 
16305f436cfbSKazutaka YOKOTA     switch (rodent.rtype) {
1631ad771aa1SSøren Schmidt 
16325f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_LOGI:
16335f436cfbSKazutaka YOKOTA 	/*
16345f436cfbSKazutaka YOKOTA 	 * The baud rate selection command must be sent at the current
16355f436cfbSKazutaka YOKOTA 	 * baud rate; try all likely settings
16365f436cfbSKazutaka YOKOTA 	 */
163713379e47SPeter Wemm 	setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
163813379e47SPeter Wemm 	setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
163913379e47SPeter Wemm 	setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
164013379e47SPeter Wemm 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
16415f436cfbSKazutaka YOKOTA 	/* select MM series data format */
1642ad771aa1SSøren Schmidt 	write(rodent.mfd, "S", 1);
164313379e47SPeter Wemm 	setmousespeed(rodent.baudrate, rodent.baudrate,
16445f436cfbSKazutaka YOKOTA 		      rodentcflags[MOUSE_PROTO_MM]);
16455f436cfbSKazutaka YOKOTA 	/* select report rate/frequency */
16465f436cfbSKazutaka YOKOTA 	if      (rodent.rate <= 0)   write(rodent.mfd, "O", 1);
16475f436cfbSKazutaka YOKOTA 	else if (rodent.rate <= 15)  write(rodent.mfd, "J", 1);
16485f436cfbSKazutaka YOKOTA 	else if (rodent.rate <= 27)  write(rodent.mfd, "K", 1);
16495f436cfbSKazutaka YOKOTA 	else if (rodent.rate <= 42)  write(rodent.mfd, "L", 1);
16505f436cfbSKazutaka YOKOTA 	else if (rodent.rate <= 60)  write(rodent.mfd, "R", 1);
16515f436cfbSKazutaka YOKOTA 	else if (rodent.rate <= 85)  write(rodent.mfd, "M", 1);
16525f436cfbSKazutaka YOKOTA 	else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1);
16535f436cfbSKazutaka YOKOTA 	else			     write(rodent.mfd, "N", 1);
16545f436cfbSKazutaka YOKOTA 	break;
165513379e47SPeter Wemm 
16565f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_LOGIMOUSEMAN:
16575f436cfbSKazutaka YOKOTA 	/* The command must always be sent at 1200 baud */
16585f436cfbSKazutaka YOKOTA 	setmousespeed(1200, 1200, rodentcflags[rodent.rtype]);
16595f436cfbSKazutaka YOKOTA 	write(rodent.mfd, "*X", 2);
16605f436cfbSKazutaka YOKOTA 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
16615f436cfbSKazutaka YOKOTA 	break;
16625f436cfbSKazutaka YOKOTA 
16635f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_HITTAB:
16645f436cfbSKazutaka YOKOTA 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
16655f436cfbSKazutaka YOKOTA 
166613379e47SPeter Wemm 	/*
166713379e47SPeter Wemm 	 * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
166813379e47SPeter Wemm 	 * The tablet must be configured to be in MM mode, NO parity,
166913379e47SPeter Wemm 	 * Binary Format.  xf86Info.sampleRate controls the sensativity
167013379e47SPeter Wemm 	 * of the tablet.  We only use this tablet for it's 4-button puck
167113379e47SPeter Wemm 	 * so we don't run in "Absolute Mode"
167213379e47SPeter Wemm 	 */
167313379e47SPeter Wemm 	write(rodent.mfd, "z8", 2);	/* Set Parity = "NONE" */
167413379e47SPeter Wemm 	usleep(50000);
167513379e47SPeter Wemm 	write(rodent.mfd, "zb", 2);	/* Set Format = "Binary" */
167613379e47SPeter Wemm 	usleep(50000);
167713379e47SPeter Wemm 	write(rodent.mfd, "@", 1);	/* Set Report Mode = "Stream" */
167813379e47SPeter Wemm 	usleep(50000);
167913379e47SPeter Wemm 	write(rodent.mfd, "R", 1);	/* Set Output Rate = "45 rps" */
168013379e47SPeter Wemm 	usleep(50000);
168113379e47SPeter Wemm 	write(rodent.mfd, "I\x20", 2);	/* Set Incrememtal Mode "20" */
168213379e47SPeter Wemm 	usleep(50000);
168313379e47SPeter Wemm 	write(rodent.mfd, "E", 1);	/* Set Data Type = "Relative */
168413379e47SPeter Wemm 	usleep(50000);
168513379e47SPeter Wemm 
16865f436cfbSKazutaka YOKOTA 	/* Resolution is in 'lines per inch' on the Hitachi tablet */
16875f436cfbSKazutaka YOKOTA 	if      (rodent.resolution == MOUSE_RES_LOW)		c = 'g';
16885f436cfbSKazutaka YOKOTA 	else if (rodent.resolution == MOUSE_RES_MEDIUMLOW)	c = 'e';
16895f436cfbSKazutaka YOKOTA 	else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH)	c = 'h';
16905f436cfbSKazutaka YOKOTA 	else if (rodent.resolution == MOUSE_RES_HIGH)		c = 'd';
16915f436cfbSKazutaka YOKOTA 	else if (rodent.resolution <=   40)			c = 'g';
16925f436cfbSKazutaka YOKOTA 	else if (rodent.resolution <=  100)			c = 'd';
16935f436cfbSKazutaka YOKOTA 	else if (rodent.resolution <=  200)			c = 'e';
16945f436cfbSKazutaka YOKOTA 	else if (rodent.resolution <=  500)			c = 'h';
16955f436cfbSKazutaka YOKOTA 	else if (rodent.resolution <= 1000)			c = 'j';
16965f436cfbSKazutaka YOKOTA 	else			c = 'd';
16975f436cfbSKazutaka YOKOTA 	write(rodent.mfd, &c, 1);
169813379e47SPeter Wemm 	usleep(50000);
169913379e47SPeter Wemm 
170013379e47SPeter Wemm 	write(rodent.mfd, "\021", 1);	/* Resume DATA output */
17015f436cfbSKazutaka YOKOTA 	break;
17025f436cfbSKazutaka YOKOTA 
17035f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_THINK:
17045f436cfbSKazutaka YOKOTA 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
17055f436cfbSKazutaka YOKOTA 	/* the PnP ID string may be sent again, discard it */
17065f436cfbSKazutaka YOKOTA 	usleep(200000);
17075f436cfbSKazutaka YOKOTA 	i = FREAD;
17085f436cfbSKazutaka YOKOTA 	ioctl(rodent.mfd, TIOCFLUSH, &i);
17095f436cfbSKazutaka YOKOTA 	/* send the command to initialize the beast */
17105f436cfbSKazutaka YOKOTA 	for (s = "E5E5"; *s; ++s) {
17115f436cfbSKazutaka YOKOTA 	    write(rodent.mfd, s, 1);
17125f436cfbSKazutaka YOKOTA 	    FD_ZERO(&fds);
17135f436cfbSKazutaka YOKOTA 	    FD_SET(rodent.mfd, &fds);
17145f436cfbSKazutaka YOKOTA 	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
17155f436cfbSKazutaka YOKOTA 		break;
17165f436cfbSKazutaka YOKOTA 	    read(rodent.mfd, &c, 1);
17175f436cfbSKazutaka YOKOTA 	    debug("%c", c);
17185f436cfbSKazutaka YOKOTA 	    if (c != *s)
17195f436cfbSKazutaka YOKOTA 		break;
1720ad771aa1SSøren Schmidt 	}
17215f436cfbSKazutaka YOKOTA 	break;
17225f436cfbSKazutaka YOKOTA 
172305f92020SWill Andrews     case MOUSE_PROTO_JOGDIAL:
172405f92020SWill Andrews 	break;
17255f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_MSC:
17265f436cfbSKazutaka YOKOTA 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
17275f436cfbSKazutaka YOKOTA 	if (rodent.flags & ClearDTR) {
17285f436cfbSKazutaka YOKOTA 	   i = TIOCM_DTR;
17295f436cfbSKazutaka YOKOTA 	   ioctl(rodent.mfd, TIOCMBIC, &i);
173013379e47SPeter Wemm 	}
17315f436cfbSKazutaka YOKOTA 	if (rodent.flags & ClearRTS) {
17325f436cfbSKazutaka YOKOTA 	   i = TIOCM_RTS;
17335f436cfbSKazutaka YOKOTA 	   ioctl(rodent.mfd, TIOCMBIC, &i);
173413379e47SPeter Wemm 	}
17355f436cfbSKazutaka YOKOTA 	break;
17365f436cfbSKazutaka YOKOTA 
17375d6618faSKazutaka YOKOTA     case MOUSE_PROTO_SYSMOUSE:
17385d6618faSKazutaka YOKOTA 	if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE)
17395d6618faSKazutaka YOKOTA 	    setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1740f0067240SPhilippe Charnier 	/* FALLTHROUGH */
17415d6618faSKazutaka YOKOTA 
17425f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_PS2:
17435f436cfbSKazutaka YOKOTA 	if (rodent.rate >= 0)
17445f436cfbSKazutaka YOKOTA 	    rodent.mode.rate = rodent.rate;
17455f436cfbSKazutaka YOKOTA 	if (rodent.resolution != MOUSE_RES_UNKNOWN)
17465f436cfbSKazutaka YOKOTA 	    rodent.mode.resolution = rodent.resolution;
17475f436cfbSKazutaka YOKOTA 	ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode);
17485f436cfbSKazutaka YOKOTA 	break;
17495f436cfbSKazutaka YOKOTA 
175067978692SAmancio Hasty     case MOUSE_PROTO_X10MOUSEREM:
175167978692SAmancio Hasty 	mremote_serversetup();
175267978692SAmancio Hasty 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
175367978692SAmancio Hasty 	break;
175467978692SAmancio Hasty 
175567978692SAmancio Hasty 
17562e09fb67SKazutaka YOKOTA     case MOUSE_PROTO_VERSAPAD:
17572e09fb67SKazutaka YOKOTA 	tcsendbreak(rodent.mfd, 0);	/* send break for 400 msec */
17582e09fb67SKazutaka YOKOTA 	i = FREAD;
17592e09fb67SKazutaka YOKOTA 	ioctl(rodent.mfd, TIOCFLUSH, &i);
17602e09fb67SKazutaka YOKOTA 	for (i = 0; i < 7; ++i) {
17612e09fb67SKazutaka YOKOTA 	    FD_ZERO(&fds);
17622e09fb67SKazutaka YOKOTA 	    FD_SET(rodent.mfd, &fds);
17632e09fb67SKazutaka YOKOTA 	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
17642e09fb67SKazutaka YOKOTA 		break;
17652e09fb67SKazutaka YOKOTA 	    read(rodent.mfd, &c, 1);
17662e09fb67SKazutaka YOKOTA 	    buf[i] = c;
17672e09fb67SKazutaka YOKOTA 	}
17682e09fb67SKazutaka YOKOTA 	debug("%s\n", buf);
17692e09fb67SKazutaka YOKOTA 	if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r'))
17702e09fb67SKazutaka YOKOTA 	    break;
17712e09fb67SKazutaka YOKOTA 	setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
17722e09fb67SKazutaka YOKOTA 	tcsendbreak(rodent.mfd, 0);	/* send break for 400 msec again */
17732e09fb67SKazutaka YOKOTA 	for (i = 0; i < 7; ++i) {
17742e09fb67SKazutaka YOKOTA 	    FD_ZERO(&fds);
17752e09fb67SKazutaka YOKOTA 	    FD_SET(rodent.mfd, &fds);
17762e09fb67SKazutaka YOKOTA 	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
17772e09fb67SKazutaka YOKOTA 		break;
17782e09fb67SKazutaka YOKOTA 	    read(rodent.mfd, &c, 1);
17792e09fb67SKazutaka YOKOTA 	    debug("%c", c);
17802e09fb67SKazutaka YOKOTA 	    if (c != buf[i])
17812e09fb67SKazutaka YOKOTA 		break;
17822e09fb67SKazutaka YOKOTA 	}
17832e09fb67SKazutaka YOKOTA 	i = FREAD;
17842e09fb67SKazutaka YOKOTA 	ioctl(rodent.mfd, TIOCFLUSH, &i);
17852e09fb67SKazutaka YOKOTA 	break;
17862e09fb67SKazutaka YOKOTA 
17875f436cfbSKazutaka YOKOTA     default:
17885f436cfbSKazutaka YOKOTA 	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
17895f436cfbSKazutaka YOKOTA 	break;
1790ad771aa1SSøren Schmidt     }
1791ad771aa1SSøren Schmidt }
1792ad771aa1SSøren Schmidt 
17935f436cfbSKazutaka YOKOTA static int
17945f436cfbSKazutaka YOKOTA r_protocol(u_char rBuf, mousestatus_t *act)
1795ad771aa1SSøren Schmidt {
17965f436cfbSKazutaka YOKOTA     /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
17975f436cfbSKazutaka YOKOTA     static int butmapmss[4] = {	/* Microsoft, MouseMan, GlidePoint,
17985f436cfbSKazutaka YOKOTA 				   IntelliMouse, Thinking Mouse */
17995f436cfbSKazutaka YOKOTA 	0,
18005f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18015f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18025f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
18035f436cfbSKazutaka YOKOTA     };
18045f436cfbSKazutaka YOKOTA     static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint,
18055f436cfbSKazutaka YOKOTA 				    Thinking Mouse */
18065f436cfbSKazutaka YOKOTA 	0,
18075f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON4DOWN,
18085f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN,
18095f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
18105f436cfbSKazutaka YOKOTA     };
18115f436cfbSKazutaka YOKOTA     /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
18125f436cfbSKazutaka YOKOTA     static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
18135f436cfbSKazutaka YOKOTA 				       MouseMan+ */
18145f436cfbSKazutaka YOKOTA 	0,
18155f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN,
18165f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON4DOWN,
18175f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
18185f436cfbSKazutaka YOKOTA     };
18195f436cfbSKazutaka YOKOTA     /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
18205f436cfbSKazutaka YOKOTA     static int butmapmsc[8] = {	/* MouseSystems, MMSeries, Logitech,
18215f436cfbSKazutaka YOKOTA 				   Bus, sysmouse */
18225f436cfbSKazutaka YOKOTA 	0,
18235f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18245f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN,
18255f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
18265f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18275f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
18285f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
18295f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
18305f436cfbSKazutaka YOKOTA     };
18315f436cfbSKazutaka YOKOTA     /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
18325f436cfbSKazutaka YOKOTA     static int butmapps2[8] = {	/* PS/2 */
18335f436cfbSKazutaka YOKOTA 	0,
18345f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18355f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18365f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
18375f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN,
18385f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
18395f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
18405f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
18415f436cfbSKazutaka YOKOTA     };
18425f436cfbSKazutaka YOKOTA     /* for Hitachi tablet */
18435f436cfbSKazutaka YOKOTA     static int butmaphit[8] = {	/* MM HitTablet */
18445f436cfbSKazutaka YOKOTA 	0,
18455f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18465f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON2DOWN,
18475f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18485f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON4DOWN,
18495f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON5DOWN,
18505f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON6DOWN,
18515f436cfbSKazutaka YOKOTA 	MOUSE_BUTTON7DOWN,
18525f436cfbSKazutaka YOKOTA     };
18532e09fb67SKazutaka YOKOTA     /* for serial VersaPad */
18542e09fb67SKazutaka YOKOTA     static int butmapversa[8] = { /* VersaPad */
18552e09fb67SKazutaka YOKOTA 	0,
18562e09fb67SKazutaka YOKOTA 	0,
18572e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18582e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18592e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18602e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18612e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
18622e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
18632e09fb67SKazutaka YOKOTA     };
18642e09fb67SKazutaka YOKOTA     /* for PS/2 VersaPad */
18652e09fb67SKazutaka YOKOTA     static int butmapversaps2[8] = { /* VersaPad */
18662e09fb67SKazutaka YOKOTA 	0,
18672e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18682e09fb67SKazutaka YOKOTA 	0,
18692e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON3DOWN,
18702e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18712e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
18722e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN,
18732e09fb67SKazutaka YOKOTA 	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
18742e09fb67SKazutaka YOKOTA     };
1875ad771aa1SSøren Schmidt     static int           pBufP = 0;
1876ad771aa1SSøren Schmidt     static unsigned char pBuf[8];
18772e09fb67SKazutaka YOKOTA     static int		 prev_x, prev_y;
18782e09fb67SKazutaka YOKOTA     static int		 on = FALSE;
18792e09fb67SKazutaka YOKOTA     int			 x, y;
1880ad771aa1SSøren Schmidt 
1881ad771aa1SSøren Schmidt     debug("received char 0x%x",(int)rBuf);
18821b11ca6cSKazutaka YOKOTA     if (rodent.rtype == MOUSE_PROTO_KIDSPAD)
18832657f6e9SJung-uk Kim 	return (kidspad(rBuf, act));
1884ce99e877SMatthew N. Dodd     if (rodent.rtype == MOUSE_PROTO_GTCO_DIGIPAD)
18852657f6e9SJung-uk Kim 	return (gtco_digipad(rBuf, act));
1886ad771aa1SSøren Schmidt 
1887ad771aa1SSøren Schmidt     /*
1888ad771aa1SSøren Schmidt      * Hack for resyncing: We check here for a package that is:
1889ad771aa1SSøren Schmidt      *  a) illegal (detected by wrong data-package header)
1890ad771aa1SSøren Schmidt      *  b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
1891ad771aa1SSøren Schmidt      *  c) bad header-package
1892ad771aa1SSøren Schmidt      *
1893ad771aa1SSøren Schmidt      * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
1894ad771aa1SSøren Schmidt      *       -128 are allowed, but since they are very seldom we can easily
1895ad771aa1SSøren Schmidt      *       use them as package-header with no button pressed.
1896ad771aa1SSøren Schmidt      * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
1897ad771aa1SSøren Schmidt      *         0x80 is not valid as a header byte. For a PS/2 mouse we skip
1898ad771aa1SSøren Schmidt      *         checking data bytes.
1899ad771aa1SSøren Schmidt      *         For resyncing a PS/2 mouse we require the two most significant
1900ad771aa1SSøren Schmidt      *         bits in the header byte to be 0. These are the overflow bits,
1901ad771aa1SSøren Schmidt      *         and in case of an overflow we actually lose sync. Overflows
1902ad771aa1SSøren Schmidt      *         are very rare, however, and we quickly gain sync again after
1903ad771aa1SSøren Schmidt      *         an overflow condition. This is the best we can do. (Actually,
1904ad771aa1SSøren Schmidt      *         we could use bit 0x08 in the header byte for resyncing, since
1905ad771aa1SSøren Schmidt      *         that bit is supposed to be always on, but nobody told
1906ad771aa1SSøren Schmidt      *         Microsoft...)
1907ad771aa1SSøren Schmidt      */
1908ad771aa1SSøren Schmidt 
19095f436cfbSKazutaka YOKOTA     if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 &&
19105f436cfbSKazutaka YOKOTA 	((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80))
1911ad771aa1SSøren Schmidt     {
1912ad771aa1SSøren Schmidt 	pBufP = 0;		/* skip package */
1913ad771aa1SSøren Schmidt     }
1914ad771aa1SSøren Schmidt 
19155f436cfbSKazutaka YOKOTA     if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1])
19162657f6e9SJung-uk Kim 	return (0);
19175f436cfbSKazutaka YOKOTA 
19185f436cfbSKazutaka YOKOTA     /* is there an extra data byte? */
19195f436cfbSKazutaka YOKOTA     if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1])
1920ad771aa1SSøren Schmidt     {
1921ad771aa1SSøren Schmidt 	/*
1922ad771aa1SSøren Schmidt 	 * Hack for Logitech MouseMan Mouse - Middle button
1923ad771aa1SSøren Schmidt 	 *
1924ad771aa1SSøren Schmidt 	 * Unfortunately this mouse has variable length packets: the standard
1925ad771aa1SSøren Schmidt 	 * Microsoft 3 byte packet plus an optional 4th byte whenever the
1926ad771aa1SSøren Schmidt 	 * middle button status changes.
1927ad771aa1SSøren Schmidt 	 *
1928ad771aa1SSøren Schmidt 	 * We have already processed the standard packet with the movement
1929ad771aa1SSøren Schmidt 	 * and button info.  Now post an event message with the old status
1930ad771aa1SSøren Schmidt 	 * of the left and right buttons and the updated middle button.
1931ad771aa1SSøren Schmidt 	 */
1932ad771aa1SSøren Schmidt 
1933ad771aa1SSøren Schmidt 	/*
1934ad771aa1SSøren Schmidt 	 * Even worse, different MouseMen and TrackMen differ in the 4th
1935ad771aa1SSøren Schmidt 	 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
1936ad771aa1SSøren Schmidt 	 * 0x02/0x22, so I have to strip off the lower bits.
19375f436cfbSKazutaka YOKOTA 	 *
19385f436cfbSKazutaka YOKOTA 	 * [JCH-96/01/21]
19395f436cfbSKazutaka YOKOTA 	 * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
19405f436cfbSKazutaka YOKOTA 	 * and it is activated by tapping the glidepad with the finger! 8^)
19415f436cfbSKazutaka YOKOTA 	 * We map it to bit bit3, and the reverse map in xf86Events just has
19425f436cfbSKazutaka YOKOTA 	 * to be extended so that it is identified as Button 4. The lower
19435f436cfbSKazutaka YOKOTA 	 * half of the reverse-map may remain unchanged.
1944ad771aa1SSøren Schmidt 	 */
19455f436cfbSKazutaka YOKOTA 
19465f436cfbSKazutaka YOKOTA 	/*
19475f436cfbSKazutaka YOKOTA 	 * [KY-97/08/03]
1948d7d97eb0SJeroen Ruigrok van der Werven 	 * Receive the fourth byte only when preceding three bytes have
19495f436cfbSKazutaka YOKOTA 	 * been detected (pBufP >= cur_proto[4]).  In the previous
19505f436cfbSKazutaka YOKOTA 	 * versions, the test was pBufP == 0; thus, we may have mistakingly
1951d7d97eb0SJeroen Ruigrok van der Werven 	 * received a byte even if we didn't see anything preceding
19525f436cfbSKazutaka YOKOTA 	 * the byte.
19535f436cfbSKazutaka YOKOTA 	 */
19545f436cfbSKazutaka YOKOTA 
19555f436cfbSKazutaka YOKOTA 	if ((rBuf & cur_proto[5]) != cur_proto[6]) {
19565f436cfbSKazutaka YOKOTA 	    pBufP = 0;
19572657f6e9SJung-uk Kim 	    return (0);
1958ad771aa1SSøren Schmidt 	}
1959ad771aa1SSøren Schmidt 
19605f436cfbSKazutaka YOKOTA 	switch (rodent.rtype) {
19615f436cfbSKazutaka YOKOTA #if notyet
19625f436cfbSKazutaka YOKOTA 	case MOUSE_PROTO_MARIQUA:
19635f436cfbSKazutaka YOKOTA 	    /*
19645f436cfbSKazutaka YOKOTA 	     * This mouse has 16! buttons in addition to the standard
19655f436cfbSKazutaka YOKOTA 	     * three of them.  They return 0x10 though 0x1f in the
19665f436cfbSKazutaka YOKOTA 	     * so-called `ten key' mode and 0x30 though 0x3f in the
19675f436cfbSKazutaka YOKOTA 	     * `function key' mode.  As there are only 31 bits for
19685f436cfbSKazutaka YOKOTA 	     * button state (including the standard three), we ignore
19695f436cfbSKazutaka YOKOTA 	     * the bit 0x20 and don't distinguish the two modes.
19705f436cfbSKazutaka YOKOTA 	     */
19715f436cfbSKazutaka YOKOTA 	    act->dx = act->dy = act->dz = 0;
19725f436cfbSKazutaka YOKOTA 	    act->obutton = act->button;
19735f436cfbSKazutaka YOKOTA 	    rBuf &= 0x1f;
19745f436cfbSKazutaka YOKOTA 	    act->button = (1 << (rBuf - 13))
19755f436cfbSKazutaka YOKOTA 		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
19765f436cfbSKazutaka YOKOTA 	    /*
19775f436cfbSKazutaka YOKOTA 	     * FIXME: this is a button "down" event. There needs to be
19785f436cfbSKazutaka YOKOTA 	     * a corresponding button "up" event... XXX
19795f436cfbSKazutaka YOKOTA 	     */
19805f436cfbSKazutaka YOKOTA 	    break;
19815f436cfbSKazutaka YOKOTA #endif /* notyet */
198205f92020SWill Andrews 	case MOUSE_PROTO_JOGDIAL:
198305f92020SWill Andrews 	    break;
19845f436cfbSKazutaka YOKOTA 
19855f436cfbSKazutaka YOKOTA 	/*
19865f436cfbSKazutaka YOKOTA 	 * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
19875f436cfbSKazutaka YOKOTA 	 * always send the fourth byte, whereas the fourth byte is
19885f436cfbSKazutaka YOKOTA 	 * optional for GlidePoint and ThinkingMouse. The fourth byte
19895f436cfbSKazutaka YOKOTA 	 * is also optional for MouseMan+ and FirstMouse+ in their
19905f436cfbSKazutaka YOKOTA 	 * native mode. It is always sent if they are in the IntelliMouse
19915f436cfbSKazutaka YOKOTA 	 * compatible mode.
19925f436cfbSKazutaka YOKOTA 	 */
19935f436cfbSKazutaka YOKOTA 	case MOUSE_PROTO_INTELLI:	/* IntelliMouse, NetMouse, Mie Mouse,
19945f436cfbSKazutaka YOKOTA 					   MouseMan+ */
19955f436cfbSKazutaka YOKOTA 	    act->dx = act->dy = 0;
19965f436cfbSKazutaka YOKOTA 	    act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f);
1997fb966343SKazutaka YOKOTA 	    if ((act->dz >= 7) || (act->dz <= -7))
1998fb966343SKazutaka YOKOTA 		act->dz = 0;
19995f436cfbSKazutaka YOKOTA 	    act->obutton = act->button;
20005f436cfbSKazutaka YOKOTA 	    act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
20015f436cfbSKazutaka YOKOTA 		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
20025f436cfbSKazutaka YOKOTA 	    break;
20035f436cfbSKazutaka YOKOTA 
20045f436cfbSKazutaka YOKOTA 	default:
20055f436cfbSKazutaka YOKOTA 	    act->dx = act->dy = act->dz = 0;
20065f436cfbSKazutaka YOKOTA 	    act->obutton = act->button;
20075f436cfbSKazutaka YOKOTA 	    act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
20085f436cfbSKazutaka YOKOTA 		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
20095f436cfbSKazutaka YOKOTA 	    break;
2010ad771aa1SSøren Schmidt 	}
2011ad771aa1SSøren Schmidt 
20125f436cfbSKazutaka YOKOTA 	act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
20135f436cfbSKazutaka YOKOTA 	    | (act->obutton ^ act->button);
20145f436cfbSKazutaka YOKOTA 	pBufP = 0;
20152657f6e9SJung-uk Kim 	return (act->flags);
20165f436cfbSKazutaka YOKOTA     }
20175f436cfbSKazutaka YOKOTA 
20185f436cfbSKazutaka YOKOTA     if (pBufP >= cur_proto[4])
20195f436cfbSKazutaka YOKOTA 	pBufP = 0;
2020ad771aa1SSøren Schmidt     pBuf[pBufP++] = rBuf;
20215f436cfbSKazutaka YOKOTA     if (pBufP != cur_proto[4])
20222657f6e9SJung-uk Kim 	return (0);
2023ad771aa1SSøren Schmidt 
2024ad771aa1SSøren Schmidt     /*
2025ad771aa1SSøren Schmidt      * assembly full package
2026ad771aa1SSøren Schmidt      */
2027ad771aa1SSøren Schmidt 
20285f436cfbSKazutaka YOKOTA     debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
20295f436cfbSKazutaka YOKOTA 	cur_proto[4],
20305f436cfbSKazutaka YOKOTA 	pBuf[0], pBuf[1], pBuf[2], pBuf[3],
20315f436cfbSKazutaka YOKOTA 	pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
2032ad771aa1SSøren Schmidt 
20335f436cfbSKazutaka YOKOTA     act->dz = 0;
20345f436cfbSKazutaka YOKOTA     act->obutton = act->button;
2035ad771aa1SSøren Schmidt     switch (rodent.rtype)
2036ad771aa1SSøren Schmidt     {
20375f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_MS:		/* Microsoft */
20385f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_LOGIMOUSEMAN:	/* MouseMan/TrackMan */
203967978692SAmancio Hasty     case MOUSE_PROTO_X10MOUSEREM:	/* X10 MouseRemote */
204036b1e17dSKazutaka YOKOTA 	act->button = act->obutton & MOUSE_BUTTON4DOWN;
2041ad771aa1SSøren Schmidt 	if (rodent.flags & ChordMiddle)
204236b1e17dSKazutaka YOKOTA 	    act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS)
20435f436cfbSKazutaka YOKOTA 		? MOUSE_BUTTON2DOWN
20445f436cfbSKazutaka YOKOTA 		: butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
2045ad771aa1SSøren Schmidt 	else
204636b1e17dSKazutaka YOKOTA 	    act->button |= (act->obutton & MOUSE_BUTTON2DOWN)
20475f436cfbSKazutaka YOKOTA 		| butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
204867978692SAmancio Hasty 
204967978692SAmancio Hasty 	/* Send X10 btn events to remote client (ensure -128-+127 range) */
205067978692SAmancio Hasty 	if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) &&
205167978692SAmancio Hasty 	    ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) {
205267978692SAmancio Hasty 	    if (rodent.mremcfd >= 0) {
205367978692SAmancio Hasty 		unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) |
205467978692SAmancio Hasty 						  (pBuf[1] & 0x3F));
205567978692SAmancio Hasty 		write(rodent.mremcfd, &key, 1);
205667978692SAmancio Hasty 	    }
20572657f6e9SJung-uk Kim 	    return (0);
205867978692SAmancio Hasty 	}
205967978692SAmancio Hasty 
20608f810e50SAkinori MUSHA 	act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
20618f810e50SAkinori MUSHA 	act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
2062ad771aa1SSøren Schmidt 	break;
2063ad771aa1SSøren Schmidt 
20645f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_GLIDEPOINT:	/* GlidePoint */
20655f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_THINK:		/* ThinkingMouse */
20665f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_INTELLI:		/* IntelliMouse, NetMouse, Mie Mouse,
20675f436cfbSKazutaka YOKOTA 					   MouseMan+ */
20685f436cfbSKazutaka YOKOTA 	act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN))
20695f436cfbSKazutaka YOKOTA 	    | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
20708f810e50SAkinori MUSHA 	act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
20718f810e50SAkinori MUSHA 	act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
2072ad771aa1SSøren Schmidt 	break;
2073ad771aa1SSøren Schmidt 
20745f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_MSC:		/* MouseSystems Corp */
20755f436cfbSKazutaka YOKOTA #if notyet
20765f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_MARIQUA:		/* Mariqua */
20775f436cfbSKazutaka YOKOTA #endif
20785f436cfbSKazutaka YOKOTA 	act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
20798f810e50SAkinori MUSHA 	act->dx =    (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
20808f810e50SAkinori MUSHA 	act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
208113379e47SPeter Wemm 	break;
208213379e47SPeter Wemm 
208305f92020SWill Andrews     case MOUSE_PROTO_JOGDIAL:		/* JogDial */
208405f92020SWill Andrews 	    if (rBuf == 0x6c)
208505f92020SWill Andrews 	      act->dz = -1;
208605f92020SWill Andrews 	    if (rBuf == 0x72)
208705f92020SWill Andrews 	      act->dz = 1;
208805f92020SWill Andrews 	    if (rBuf == 0x64)
208905f92020SWill Andrews 	      act->button = MOUSE_BUTTON1DOWN;
209005f92020SWill Andrews 	    if (rBuf == 0x75)
209105f92020SWill Andrews 	      act->button = 0;
209205f92020SWill Andrews 	break;
209305f92020SWill Andrews 
20945f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_HITTAB:		/* MM HitTablet */
20955f436cfbSKazutaka YOKOTA 	act->button = butmaphit[pBuf[0] & 0x07];
20965f436cfbSKazutaka YOKOTA 	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
20975f436cfbSKazutaka YOKOTA 	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
2098ad771aa1SSøren Schmidt 	break;
2099ad771aa1SSøren Schmidt 
21005f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_MM:		/* MM Series */
21015f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_LOGI:		/* Logitech Mice */
21025f436cfbSKazutaka YOKOTA 	act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS];
21035f436cfbSKazutaka YOKOTA 	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
21045f436cfbSKazutaka YOKOTA 	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
2105ad771aa1SSøren Schmidt 	break;
2106ad771aa1SSøren Schmidt 
21072e09fb67SKazutaka YOKOTA     case MOUSE_PROTO_VERSAPAD:		/* VersaPad */
21082e09fb67SKazutaka YOKOTA 	act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3];
21092e09fb67SKazutaka YOKOTA 	act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
21102e09fb67SKazutaka YOKOTA 	act->dx = act->dy = 0;
21112e09fb67SKazutaka YOKOTA 	if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) {
21122e09fb67SKazutaka YOKOTA 	    on = FALSE;
21132e09fb67SKazutaka YOKOTA 	    break;
21142e09fb67SKazutaka YOKOTA 	}
21152e09fb67SKazutaka YOKOTA 	x = (pBuf[2] << 6) | pBuf[1];
21162e09fb67SKazutaka YOKOTA 	if (x & 0x800)
21172e09fb67SKazutaka YOKOTA 	    x -= 0x1000;
21182e09fb67SKazutaka YOKOTA 	y = (pBuf[4] << 6) | pBuf[3];
21192e09fb67SKazutaka YOKOTA 	if (y & 0x800)
21202e09fb67SKazutaka YOKOTA 	    y -= 0x1000;
21212e09fb67SKazutaka YOKOTA 	if (on) {
21222e09fb67SKazutaka YOKOTA 	    act->dx = prev_x - x;
21232e09fb67SKazutaka YOKOTA 	    act->dy = prev_y - y;
21242e09fb67SKazutaka YOKOTA 	} else {
21252e09fb67SKazutaka YOKOTA 	    on = TRUE;
21262e09fb67SKazutaka YOKOTA 	}
21272e09fb67SKazutaka YOKOTA 	prev_x = x;
21282e09fb67SKazutaka YOKOTA 	prev_y = y;
21292e09fb67SKazutaka YOKOTA 	break;
21302e09fb67SKazutaka YOKOTA 
21315f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_PS2:		/* PS/2 */
21325f436cfbSKazutaka YOKOTA 	act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS];
21335f436cfbSKazutaka YOKOTA 	act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ?    pBuf[1] - 256  :  pBuf[1];
21345f436cfbSKazutaka YOKOTA 	act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ?  -(pBuf[2] - 256) : -pBuf[2];
21355f436cfbSKazutaka YOKOTA 	/*
21365f436cfbSKazutaka YOKOTA 	 * Moused usually operates the psm driver at the operation level 1
21375f436cfbSKazutaka YOKOTA 	 * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
21385f436cfbSKazutaka YOKOTA 	 * The following code takes effect only when the user explicitly
21395f436cfbSKazutaka YOKOTA 	 * requets the level 2 at which wheel movement and additional button
21405f436cfbSKazutaka YOKOTA 	 * actions are encoded in model-dependent formats. At the level 0
21415f436cfbSKazutaka YOKOTA 	 * the following code is no-op because the psm driver says the model
21425f436cfbSKazutaka YOKOTA 	 * is MOUSE_MODEL_GENERIC.
21435f436cfbSKazutaka YOKOTA 	 */
21445f436cfbSKazutaka YOKOTA 	switch (rodent.hw.model) {
2145fb966343SKazutaka YOKOTA 	case MOUSE_MODEL_EXPLORER:
2146fb966343SKazutaka YOKOTA 	    /* wheel and additional button data is in the fourth byte */
2147fb966343SKazutaka YOKOTA 	    act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG)
2148fb966343SKazutaka YOKOTA 		? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f);
2149fb966343SKazutaka YOKOTA 	    act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN)
2150fb966343SKazutaka YOKOTA 		? MOUSE_BUTTON4DOWN : 0;
2151fb966343SKazutaka YOKOTA 	    act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN)
2152fb966343SKazutaka YOKOTA 		? MOUSE_BUTTON5DOWN : 0;
2153fb966343SKazutaka YOKOTA 	    break;
21545f436cfbSKazutaka YOKOTA 	case MOUSE_MODEL_INTELLI:
21555f436cfbSKazutaka YOKOTA 	case MOUSE_MODEL_NET:
21565f436cfbSKazutaka YOKOTA 	    /* wheel data is in the fourth byte */
21578f810e50SAkinori MUSHA 	    act->dz = (signed char)pBuf[3];
2158fb966343SKazutaka YOKOTA 	    if ((act->dz >= 7) || (act->dz <= -7))
2159fb966343SKazutaka YOKOTA 		act->dz = 0;
2160fb966343SKazutaka YOKOTA 	    /* some compatible mice may have additional buttons */
2161fb966343SKazutaka YOKOTA 	    act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN)
2162fb966343SKazutaka YOKOTA 		? MOUSE_BUTTON4DOWN : 0;
2163fb966343SKazutaka YOKOTA 	    act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN)
2164fb966343SKazutaka YOKOTA 		? MOUSE_BUTTON5DOWN : 0;
21655f436cfbSKazutaka YOKOTA 	    break;
21665f436cfbSKazutaka YOKOTA 	case MOUSE_MODEL_MOUSEMANPLUS:
216701533d85SKazutaka YOKOTA 	    if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
216801533d85SKazutaka YOKOTA 		    && (abs(act->dx) > 191)
216901533d85SKazutaka YOKOTA 		    && MOUSE_PS2PLUS_CHECKBITS(pBuf)) {
21705f436cfbSKazutaka YOKOTA 		/* the extended data packet encodes button and wheel events */
217101533d85SKazutaka YOKOTA 		switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) {
217201533d85SKazutaka YOKOTA 		case 1:
217301533d85SKazutaka YOKOTA 		    /* wheel data packet */
21745f436cfbSKazutaka YOKOTA 		    act->dx = act->dy = 0;
217501533d85SKazutaka YOKOTA 		    if (pBuf[2] & 0x80) {
217601533d85SKazutaka YOKOTA 			/* horizontal roller count - ignore it XXX*/
217701533d85SKazutaka YOKOTA 		    } else {
217801533d85SKazutaka YOKOTA 			/* vertical roller count */
21792b9e6c75SKazutaka YOKOTA 			act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG)
21805f436cfbSKazutaka YOKOTA 			    ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
218101533d85SKazutaka YOKOTA 		    }
218201533d85SKazutaka YOKOTA 		    act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
218301533d85SKazutaka YOKOTA 			? MOUSE_BUTTON4DOWN : 0;
218401533d85SKazutaka YOKOTA 		    act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
218501533d85SKazutaka YOKOTA 			? MOUSE_BUTTON5DOWN : 0;
218601533d85SKazutaka YOKOTA 		    break;
218701533d85SKazutaka YOKOTA 		case 2:
2188fb966343SKazutaka YOKOTA 		    /* this packet type is reserved by Logitech */
2189fb966343SKazutaka YOKOTA 		    /*
2190fb966343SKazutaka YOKOTA 		     * IBM ScrollPoint Mouse uses this packet type to
2191fb966343SKazutaka YOKOTA 		     * encode both vertical and horizontal scroll movement.
2192fb966343SKazutaka YOKOTA 		     */
2193fb966343SKazutaka YOKOTA 		    act->dx = act->dy = 0;
2194fb966343SKazutaka YOKOTA 		    /* horizontal roller count */
2195fb966343SKazutaka YOKOTA 		    if (pBuf[2] & 0x0f)
2196fb966343SKazutaka YOKOTA 			act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
2197fb966343SKazutaka YOKOTA 		    /* vertical roller count */
2198fb966343SKazutaka YOKOTA 		    if (pBuf[2] & 0xf0)
2199fb966343SKazutaka YOKOTA 			act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
2200fb966343SKazutaka YOKOTA #if 0
2201fb966343SKazutaka YOKOTA 		    /* vertical roller count */
2202fb966343SKazutaka YOKOTA 		    act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG)
2203fb966343SKazutaka YOKOTA 			? ((pBuf[2] >> 4) & 0x0f) - 16
2204fb966343SKazutaka YOKOTA 			: ((pBuf[2] >> 4) & 0x0f);
2205fb966343SKazutaka YOKOTA 		    /* horizontal roller count */
2206fb966343SKazutaka YOKOTA 		    act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG)
2207fb966343SKazutaka YOKOTA 			? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
2208fb966343SKazutaka YOKOTA #endif
2209fb966343SKazutaka YOKOTA 		    break;
221001533d85SKazutaka YOKOTA 		case 0:
221101533d85SKazutaka YOKOTA 		    /* device type packet - shouldn't happen */
221201533d85SKazutaka YOKOTA 		    /* FALLTHROUGH */
221301533d85SKazutaka YOKOTA 		default:
221401533d85SKazutaka YOKOTA 		    act->dx = act->dy = 0;
221501533d85SKazutaka YOKOTA 		    act->button = act->obutton;
221601533d85SKazutaka YOKOTA 		    debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n",
221701533d85SKazutaka YOKOTA 			  MOUSE_PS2PLUS_PACKET_TYPE(pBuf),
221801533d85SKazutaka YOKOTA 			  pBuf[0], pBuf[1], pBuf[2]);
221901533d85SKazutaka YOKOTA 		    break;
222001533d85SKazutaka YOKOTA 		}
22215f436cfbSKazutaka YOKOTA 	    } else {
22225f436cfbSKazutaka YOKOTA 		/* preserve button states */
22235f436cfbSKazutaka YOKOTA 		act->button |= act->obutton & MOUSE_EXTBUTTONS;
22245f436cfbSKazutaka YOKOTA 	    }
22255f436cfbSKazutaka YOKOTA 	    break;
22265f436cfbSKazutaka YOKOTA 	case MOUSE_MODEL_GLIDEPOINT:
22275f436cfbSKazutaka YOKOTA 	    /* `tapping' action */
22285f436cfbSKazutaka YOKOTA 	    act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
22295f436cfbSKazutaka YOKOTA 	    break;
22305f436cfbSKazutaka YOKOTA 	case MOUSE_MODEL_NETSCROLL:
22313df5ecacSUlrich Spörlein 	    /* three additional bytes encode buttons and wheel events */
22325f436cfbSKazutaka YOKOTA 	    act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN)
22335f436cfbSKazutaka YOKOTA 		? MOUSE_BUTTON4DOWN : 0;
2234fb966343SKazutaka YOKOTA 	    act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN)
2235fb966343SKazutaka YOKOTA 		? MOUSE_BUTTON5DOWN : 0;
22365f436cfbSKazutaka YOKOTA 	    act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4];
22375f436cfbSKazutaka YOKOTA 	    break;
22385f436cfbSKazutaka YOKOTA 	case MOUSE_MODEL_THINK:
22395f436cfbSKazutaka YOKOTA 	    /* the fourth button state in the first byte */
22405f436cfbSKazutaka YOKOTA 	    act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
22415f436cfbSKazutaka YOKOTA 	    break;
22422e09fb67SKazutaka YOKOTA 	case MOUSE_MODEL_VERSAPAD:
22432e09fb67SKazutaka YOKOTA 	    act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS];
22442e09fb67SKazutaka YOKOTA 	    act->button |=
22452e09fb67SKazutaka YOKOTA 		(pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
22462e09fb67SKazutaka YOKOTA 	    act->dx = act->dy = 0;
22472e09fb67SKazutaka YOKOTA 	    if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) {
22482e09fb67SKazutaka YOKOTA 		on = FALSE;
22492e09fb67SKazutaka YOKOTA 		break;
22502e09fb67SKazutaka YOKOTA 	    }
22512e09fb67SKazutaka YOKOTA 	    x = ((pBuf[4] << 8) & 0xf00) | pBuf[1];
22522e09fb67SKazutaka YOKOTA 	    if (x & 0x800)
22532e09fb67SKazutaka YOKOTA 		x -= 0x1000;
22542e09fb67SKazutaka YOKOTA 	    y = ((pBuf[4] << 4) & 0xf00) | pBuf[2];
22552e09fb67SKazutaka YOKOTA 	    if (y & 0x800)
22562e09fb67SKazutaka YOKOTA 		y -= 0x1000;
22572e09fb67SKazutaka YOKOTA 	    if (on) {
22582e09fb67SKazutaka YOKOTA 		act->dx = prev_x - x;
22592e09fb67SKazutaka YOKOTA 		act->dy = prev_y - y;
22602e09fb67SKazutaka YOKOTA 	    } else {
22612e09fb67SKazutaka YOKOTA 		on = TRUE;
22622e09fb67SKazutaka YOKOTA 	    }
22632e09fb67SKazutaka YOKOTA 	    prev_x = x;
22642e09fb67SKazutaka YOKOTA 	    prev_y = y;
22652e09fb67SKazutaka YOKOTA 	    break;
2266fb966343SKazutaka YOKOTA 	case MOUSE_MODEL_4D:
2267fb966343SKazutaka YOKOTA 	    act->dx = (pBuf[1] & 0x80) ?    pBuf[1] - 256  :  pBuf[1];
2268fb966343SKazutaka YOKOTA 	    act->dy = (pBuf[2] & 0x80) ?  -(pBuf[2] - 256) : -pBuf[2];
2269fb966343SKazutaka YOKOTA 	    switch (pBuf[0] & MOUSE_4D_WHEELBITS) {
2270fb966343SKazutaka YOKOTA 	    case 0x10:
2271fb966343SKazutaka YOKOTA 		act->dz = 1;
2272fb966343SKazutaka YOKOTA 		break;
2273fb966343SKazutaka YOKOTA 	    case 0x30:
2274fb966343SKazutaka YOKOTA 		act->dz = -1;
2275fb966343SKazutaka YOKOTA 		break;
2276fb966343SKazutaka YOKOTA 	    case 0x40:	/* 2nd wheel rolling right XXX */
2277fb966343SKazutaka YOKOTA 		act->dz = 2;
2278fb966343SKazutaka YOKOTA 		break;
2279fb966343SKazutaka YOKOTA 	    case 0xc0:	/* 2nd wheel rolling left XXX */
2280fb966343SKazutaka YOKOTA 		act->dz = -2;
2281fb966343SKazutaka YOKOTA 		break;
2282fb966343SKazutaka YOKOTA 	    }
2283fb966343SKazutaka YOKOTA 	    break;
2284fb966343SKazutaka YOKOTA 	case MOUSE_MODEL_4DPLUS:
2285fb966343SKazutaka YOKOTA 	    if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) {
2286fb966343SKazutaka YOKOTA 		act->dx = act->dy = 0;
2287fb966343SKazutaka YOKOTA 		if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN)
2288fb966343SKazutaka YOKOTA 		    act->button |= MOUSE_BUTTON4DOWN;
2289fb966343SKazutaka YOKOTA 		act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG)
2290fb966343SKazutaka YOKOTA 			      ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07);
2291fb966343SKazutaka YOKOTA 	    } else {
2292fb966343SKazutaka YOKOTA 		/* preserve previous button states */
2293fb966343SKazutaka YOKOTA 		act->button |= act->obutton & MOUSE_EXTBUTTONS;
2294fb966343SKazutaka YOKOTA 	    }
2295fb966343SKazutaka YOKOTA 	    break;
22965f436cfbSKazutaka YOKOTA 	case MOUSE_MODEL_GENERIC:
22975f436cfbSKazutaka YOKOTA 	default:
2298ad771aa1SSøren Schmidt 	    break;
2299ad771aa1SSøren Schmidt 	}
23005f436cfbSKazutaka YOKOTA 	break;
23015f436cfbSKazutaka YOKOTA 
23025f436cfbSKazutaka YOKOTA     case MOUSE_PROTO_SYSMOUSE:		/* sysmouse */
23035f436cfbSKazutaka YOKOTA 	act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
23048f810e50SAkinori MUSHA 	act->dx =    (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
23058f810e50SAkinori MUSHA 	act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
23065f436cfbSKazutaka YOKOTA 	if (rodent.level == 1) {
23078f810e50SAkinori MUSHA 	    act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1;
23085f436cfbSKazutaka YOKOTA 	    act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
23095f436cfbSKazutaka YOKOTA 	}
23105f436cfbSKazutaka YOKOTA 	break;
23115f436cfbSKazutaka YOKOTA 
23125f436cfbSKazutaka YOKOTA     default:
23132657f6e9SJung-uk Kim 	return (0);
23145f436cfbSKazutaka YOKOTA     }
23155f436cfbSKazutaka YOKOTA     /*
23165f436cfbSKazutaka YOKOTA      * We don't reset pBufP here yet, as there may be an additional data
23175f436cfbSKazutaka YOKOTA      * byte in some protocols. See above.
23185f436cfbSKazutaka YOKOTA      */
23195f436cfbSKazutaka YOKOTA 
23205f436cfbSKazutaka YOKOTA     /* has something changed? */
23215f436cfbSKazutaka YOKOTA     act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
23225f436cfbSKazutaka YOKOTA 	| (act->obutton ^ act->button);
23235f436cfbSKazutaka YOKOTA 
23242657f6e9SJung-uk Kim     return (act->flags);
2325e3b00983SKazutaka YOKOTA }
2326ab51fa72SSheldon Hearn 
232744bdcfa6SKazutaka YOKOTA static int
232844bdcfa6SKazutaka YOKOTA r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans)
232944bdcfa6SKazutaka YOKOTA {
233044bdcfa6SKazutaka YOKOTA     int changed;
233144bdcfa6SKazutaka YOKOTA     int flags;
233244bdcfa6SKazutaka YOKOTA 
233344bdcfa6SKazutaka YOKOTA     a2->dx = a1->dx;
233444bdcfa6SKazutaka YOKOTA     a2->dy = a1->dy;
233544bdcfa6SKazutaka YOKOTA     a2->dz = a1->dz;
233644bdcfa6SKazutaka YOKOTA     a2->obutton = a2->button;
233744bdcfa6SKazutaka YOKOTA     a2->button = a1->button;
233844bdcfa6SKazutaka YOKOTA     a2->flags = a1->flags;
233944bdcfa6SKazutaka YOKOTA     changed = FALSE;
234044bdcfa6SKazutaka YOKOTA 
234144bdcfa6SKazutaka YOKOTA     if (rodent.flags & Emulate3Button) {
234244bdcfa6SKazutaka YOKOTA 	if (debug > 2)
234344bdcfa6SKazutaka YOKOTA 	    debug("state:%d, trans:%d -> state:%d",
234444bdcfa6SKazutaka YOKOTA 		  mouse_button_state, trans,
234544bdcfa6SKazutaka YOKOTA 		  states[mouse_button_state].s[trans]);
234670ccc8d8SIan Dowse 	/*
234770ccc8d8SIan Dowse 	 * Avoid re-ordering button and movement events. While a button
234870ccc8d8SIan Dowse 	 * event is deferred, throw away up to BUTTON2_MAXMOVE movement
234970ccc8d8SIan Dowse 	 * events to allow for mouse jitter. If more movement events
235070ccc8d8SIan Dowse 	 * occur, then complete the deferred button events immediately.
235170ccc8d8SIan Dowse 	 */
235270ccc8d8SIan Dowse 	if ((a2->dx != 0 || a2->dy != 0) &&
235370ccc8d8SIan Dowse 	    S_DELAYED(states[mouse_button_state].s[trans])) {
235470ccc8d8SIan Dowse 		if (++mouse_move_delayed > BUTTON2_MAXMOVE) {
235570ccc8d8SIan Dowse 			mouse_move_delayed = 0;
235670ccc8d8SIan Dowse 			mouse_button_state =
235770ccc8d8SIan Dowse 			    states[mouse_button_state].s[A_TIMEOUT];
235844bdcfa6SKazutaka YOKOTA 			changed = TRUE;
2359a9b238faSIan Dowse 		} else
236070ccc8d8SIan Dowse 			a2->dx = a2->dy = 0;
236170ccc8d8SIan Dowse 	} else
236270ccc8d8SIan Dowse 		mouse_move_delayed = 0;
236370ccc8d8SIan Dowse 	if (mouse_button_state != states[mouse_button_state].s[trans])
236470ccc8d8SIan Dowse 		changed = TRUE;
236570ccc8d8SIan Dowse 	if (changed)
236613f1c59bSJung-uk Kim 		clock_gettime(CLOCK_MONOTONIC_FAST, &mouse_button_state_ts);
236744bdcfa6SKazutaka YOKOTA 	mouse_button_state = states[mouse_button_state].s[trans];
236844bdcfa6SKazutaka YOKOTA 	a2->button &=
236944bdcfa6SKazutaka YOKOTA 	    ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN);
237044bdcfa6SKazutaka YOKOTA 	a2->button &= states[mouse_button_state].mask;
237144bdcfa6SKazutaka YOKOTA 	a2->button |= states[mouse_button_state].buttons;
237244bdcfa6SKazutaka YOKOTA 	flags = a2->flags & MOUSE_POSCHANGED;
237344bdcfa6SKazutaka YOKOTA 	flags |= a2->obutton ^ a2->button;
237444bdcfa6SKazutaka YOKOTA 	if (flags & MOUSE_BUTTON2DOWN) {
237544bdcfa6SKazutaka YOKOTA 	    a2->flags = flags & MOUSE_BUTTON2DOWN;
237644bdcfa6SKazutaka YOKOTA 	    r_timestamp(a2);
237744bdcfa6SKazutaka YOKOTA 	}
237844bdcfa6SKazutaka YOKOTA 	a2->flags = flags;
237944bdcfa6SKazutaka YOKOTA     }
23802657f6e9SJung-uk Kim     return (changed);
23815f436cfbSKazutaka YOKOTA }
23825f436cfbSKazutaka YOKOTA 
23835f436cfbSKazutaka YOKOTA /* phisical to logical button mapping */
23845f436cfbSKazutaka YOKOTA static int p2l[MOUSE_MAXBUTTON] = {
23855f436cfbSKazutaka YOKOTA     MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
23865f436cfbSKazutaka YOKOTA     MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
23875f436cfbSKazutaka YOKOTA     0x00000100,        0x00000200,        0x00000400,        0x00000800,
23885f436cfbSKazutaka YOKOTA     0x00001000,        0x00002000,        0x00004000,        0x00008000,
23895f436cfbSKazutaka YOKOTA     0x00010000,        0x00020000,        0x00040000,        0x00080000,
23905f436cfbSKazutaka YOKOTA     0x00100000,        0x00200000,        0x00400000,        0x00800000,
23915f436cfbSKazutaka YOKOTA     0x01000000,        0x02000000,        0x04000000,        0x08000000,
23925f436cfbSKazutaka YOKOTA     0x10000000,        0x20000000,        0x40000000,
23935f436cfbSKazutaka YOKOTA };
23945f436cfbSKazutaka YOKOTA 
23955f436cfbSKazutaka YOKOTA static char *
23965f436cfbSKazutaka YOKOTA skipspace(char *s)
23975f436cfbSKazutaka YOKOTA {
23985f436cfbSKazutaka YOKOTA     while(isspace(*s))
23995f436cfbSKazutaka YOKOTA 	++s;
24002657f6e9SJung-uk Kim     return (s);
24015f436cfbSKazutaka YOKOTA }
24025f436cfbSKazutaka YOKOTA 
24035f436cfbSKazutaka YOKOTA static int
24045f436cfbSKazutaka YOKOTA r_installmap(char *arg)
24055f436cfbSKazutaka YOKOTA {
24065f436cfbSKazutaka YOKOTA     int pbutton;
24075f436cfbSKazutaka YOKOTA     int lbutton;
24085f436cfbSKazutaka YOKOTA     char *s;
24095f436cfbSKazutaka YOKOTA 
24105f436cfbSKazutaka YOKOTA     while (*arg) {
24115f436cfbSKazutaka YOKOTA 	arg = skipspace(arg);
24125f436cfbSKazutaka YOKOTA 	s = arg;
24135f436cfbSKazutaka YOKOTA 	while (isdigit(*arg))
24145f436cfbSKazutaka YOKOTA 	    ++arg;
24155f436cfbSKazutaka YOKOTA 	arg = skipspace(arg);
24165f436cfbSKazutaka YOKOTA 	if ((arg <= s) || (*arg != '='))
24172657f6e9SJung-uk Kim 	    return (FALSE);
24185f436cfbSKazutaka YOKOTA 	lbutton = atoi(s);
24195f436cfbSKazutaka YOKOTA 
24205f436cfbSKazutaka YOKOTA 	arg = skipspace(++arg);
24215f436cfbSKazutaka YOKOTA 	s = arg;
24225f436cfbSKazutaka YOKOTA 	while (isdigit(*arg))
24235f436cfbSKazutaka YOKOTA 	    ++arg;
24245f436cfbSKazutaka YOKOTA 	if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
24252657f6e9SJung-uk Kim 	    return (FALSE);
24265f436cfbSKazutaka YOKOTA 	pbutton = atoi(s);
24275f436cfbSKazutaka YOKOTA 
24285f436cfbSKazutaka YOKOTA 	if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
24292657f6e9SJung-uk Kim 	    return (FALSE);
24305f436cfbSKazutaka YOKOTA 	if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
24312657f6e9SJung-uk Kim 	    return (FALSE);
24325f436cfbSKazutaka YOKOTA 	p2l[pbutton - 1] = 1 << (lbutton - 1);
243344bdcfa6SKazutaka YOKOTA 	mstate[lbutton - 1] = &bstate[pbutton - 1];
24345f436cfbSKazutaka YOKOTA     }
24355f436cfbSKazutaka YOKOTA 
24362657f6e9SJung-uk Kim     return (TRUE);
24375f436cfbSKazutaka YOKOTA }
24385f436cfbSKazutaka YOKOTA 
24395f436cfbSKazutaka YOKOTA static void
24405f436cfbSKazutaka YOKOTA r_map(mousestatus_t *act1, mousestatus_t *act2)
24415f436cfbSKazutaka YOKOTA {
24425f436cfbSKazutaka YOKOTA     register int pb;
24435f436cfbSKazutaka YOKOTA     register int pbuttons;
24445f436cfbSKazutaka YOKOTA     int lbuttons;
24455f436cfbSKazutaka YOKOTA 
24465f436cfbSKazutaka YOKOTA     pbuttons = act1->button;
24475f436cfbSKazutaka YOKOTA     lbuttons = 0;
24485f436cfbSKazutaka YOKOTA 
24495f436cfbSKazutaka YOKOTA     act2->obutton = act2->button;
24509fb1d70cSKazutaka YOKOTA     if (pbuttons & rodent.wmode) {
24519fb1d70cSKazutaka YOKOTA 	pbuttons &= ~rodent.wmode;
24529fb1d70cSKazutaka YOKOTA 	act1->dz = act1->dy;
24539fb1d70cSKazutaka YOKOTA 	act1->dx = 0;
24549fb1d70cSKazutaka YOKOTA 	act1->dy = 0;
24559fb1d70cSKazutaka YOKOTA     }
24565f436cfbSKazutaka YOKOTA     act2->dx = act1->dx;
24575f436cfbSKazutaka YOKOTA     act2->dy = act1->dy;
24585f436cfbSKazutaka YOKOTA     act2->dz = act1->dz;
24595f436cfbSKazutaka YOKOTA 
2460fb966343SKazutaka YOKOTA     switch (rodent.zmap[0]) {
24615f436cfbSKazutaka YOKOTA     case 0:	/* do nothing */
24625f436cfbSKazutaka YOKOTA 	break;
24635f436cfbSKazutaka YOKOTA     case MOUSE_XAXIS:
24645f436cfbSKazutaka YOKOTA 	if (act1->dz != 0) {
24655f436cfbSKazutaka YOKOTA 	    act2->dx = act1->dz;
24665f436cfbSKazutaka YOKOTA 	    act2->dz = 0;
24675f436cfbSKazutaka YOKOTA 	}
24685f436cfbSKazutaka YOKOTA 	break;
24695f436cfbSKazutaka YOKOTA     case MOUSE_YAXIS:
24705f436cfbSKazutaka YOKOTA 	if (act1->dz != 0) {
24715f436cfbSKazutaka YOKOTA 	    act2->dy = act1->dz;
24725f436cfbSKazutaka YOKOTA 	    act2->dz = 0;
24735f436cfbSKazutaka YOKOTA 	}
24745f436cfbSKazutaka YOKOTA 	break;
24755f436cfbSKazutaka YOKOTA     default:	/* buttons */
2476fb966343SKazutaka YOKOTA 	pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1]
2477fb966343SKazutaka YOKOTA 		    | rodent.zmap[2] | rodent.zmap[3]);
247844bdcfa6SKazutaka YOKOTA 	if ((act1->dz < -1) && rodent.zmap[2]) {
2479fb966343SKazutaka YOKOTA 	    pbuttons |= rodent.zmap[2];
248044bdcfa6SKazutaka YOKOTA 	    zstate[2].count = 1;
248144bdcfa6SKazutaka YOKOTA 	} else if (act1->dz < 0) {
2482fb966343SKazutaka YOKOTA 	    pbuttons |= rodent.zmap[0];
248344bdcfa6SKazutaka YOKOTA 	    zstate[0].count = 1;
248444bdcfa6SKazutaka YOKOTA 	} else if ((act1->dz > 1) && rodent.zmap[3]) {
2485fb966343SKazutaka YOKOTA 	    pbuttons |= rodent.zmap[3];
248644bdcfa6SKazutaka YOKOTA 	    zstate[3].count = 1;
248744bdcfa6SKazutaka YOKOTA 	} else if (act1->dz > 0) {
2488fb966343SKazutaka YOKOTA 	    pbuttons |= rodent.zmap[1];
248944bdcfa6SKazutaka YOKOTA 	    zstate[1].count = 1;
249044bdcfa6SKazutaka YOKOTA 	}
24915f436cfbSKazutaka YOKOTA 	act2->dz = 0;
24925f436cfbSKazutaka YOKOTA 	break;
24935f436cfbSKazutaka YOKOTA     }
24945f436cfbSKazutaka YOKOTA 
24955f436cfbSKazutaka YOKOTA     for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
24965f436cfbSKazutaka YOKOTA 	lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
24975f436cfbSKazutaka YOKOTA 	pbuttons >>= 1;
24985f436cfbSKazutaka YOKOTA     }
24995f436cfbSKazutaka YOKOTA     act2->button = lbuttons;
25005f436cfbSKazutaka YOKOTA 
25015f436cfbSKazutaka YOKOTA     act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
25025f436cfbSKazutaka YOKOTA 	| (act2->obutton ^ act2->button);
25035f436cfbSKazutaka YOKOTA }
25045f436cfbSKazutaka YOKOTA 
25055f436cfbSKazutaka YOKOTA static void
250644bdcfa6SKazutaka YOKOTA r_timestamp(mousestatus_t *act)
25075f436cfbSKazutaka YOKOTA {
250813f1c59bSJung-uk Kim     struct timespec ts;
250913f1c59bSJung-uk Kim     struct timespec ts1;
251013f1c59bSJung-uk Kim     struct timespec ts2;
251113f1c59bSJung-uk Kim     struct timespec ts3;
251244bdcfa6SKazutaka YOKOTA     int button;
251344bdcfa6SKazutaka YOKOTA     int mask;
251444bdcfa6SKazutaka YOKOTA     int i;
251544bdcfa6SKazutaka YOKOTA 
251644bdcfa6SKazutaka YOKOTA     mask = act->flags & MOUSE_BUTTONS;
251744bdcfa6SKazutaka YOKOTA #if 0
251844bdcfa6SKazutaka YOKOTA     if (mask == 0)
251944bdcfa6SKazutaka YOKOTA 	return;
252044bdcfa6SKazutaka YOKOTA #endif
252144bdcfa6SKazutaka YOKOTA 
252213f1c59bSJung-uk Kim     clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
252313f1c59bSJung-uk Kim     drift_current_ts = ts1;
252444bdcfa6SKazutaka YOKOTA 
252544bdcfa6SKazutaka YOKOTA     /* double click threshold */
252613f1c59bSJung-uk Kim     ts2.tv_sec = rodent.clickthreshold / 1000;
252713f1c59bSJung-uk Kim     ts2.tv_nsec = (rodent.clickthreshold % 1000) * 1000000;
252813f1c59bSJung-uk Kim     tssub(&ts1, &ts2, &ts);
2529f2559616SJung-uk Kim     debug("ts:  %jd %ld", (intmax_t)ts.tv_sec, ts.tv_nsec);
253044bdcfa6SKazutaka YOKOTA 
253144bdcfa6SKazutaka YOKOTA     /* 3 button emulation timeout */
253213f1c59bSJung-uk Kim     ts2.tv_sec = rodent.button2timeout / 1000;
253313f1c59bSJung-uk Kim     ts2.tv_nsec = (rodent.button2timeout % 1000) * 1000000;
253413f1c59bSJung-uk Kim     tssub(&ts1, &ts2, &ts3);
253544bdcfa6SKazutaka YOKOTA 
253644bdcfa6SKazutaka YOKOTA     button = MOUSE_BUTTON1DOWN;
253744bdcfa6SKazutaka YOKOTA     for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
253844bdcfa6SKazutaka YOKOTA 	if (mask & 1) {
253944bdcfa6SKazutaka YOKOTA 	    if (act->button & button) {
254044bdcfa6SKazutaka YOKOTA 		/* the button is down */
2541f2559616SJung-uk Kim 		debug("  :  %jd %ld",
2542f2559616SJung-uk Kim 		    (intmax_t)bstate[i].ts.tv_sec, bstate[i].ts.tv_nsec);
254313f1c59bSJung-uk Kim 		if (tscmp(&ts, &bstate[i].ts, >)) {
254444bdcfa6SKazutaka YOKOTA 		    bstate[i].count = 1;
254544bdcfa6SKazutaka YOKOTA 		} else {
254644bdcfa6SKazutaka YOKOTA 		    ++bstate[i].count;
254744bdcfa6SKazutaka YOKOTA 		}
254813f1c59bSJung-uk Kim 		bstate[i].ts = ts1;
254944bdcfa6SKazutaka YOKOTA 	    } else {
255044bdcfa6SKazutaka YOKOTA 		/* the button is up */
255113f1c59bSJung-uk Kim 		bstate[i].ts = ts1;
255244bdcfa6SKazutaka YOKOTA 	    }
255344bdcfa6SKazutaka YOKOTA 	} else {
255444bdcfa6SKazutaka YOKOTA 	    if (act->button & button) {
255544bdcfa6SKazutaka YOKOTA 		/* the button has been down */
255613f1c59bSJung-uk Kim 		if (tscmp(&ts3, &bstate[i].ts, >)) {
255744bdcfa6SKazutaka YOKOTA 		    bstate[i].count = 1;
255813f1c59bSJung-uk Kim 		    bstate[i].ts = ts1;
255944bdcfa6SKazutaka YOKOTA 		    act->flags |= button;
256044bdcfa6SKazutaka YOKOTA 		    debug("button %d timeout", i + 1);
256144bdcfa6SKazutaka YOKOTA 		}
256244bdcfa6SKazutaka YOKOTA 	    } else {
256344bdcfa6SKazutaka YOKOTA 		/* the button has been up */
256444bdcfa6SKazutaka YOKOTA 	    }
256544bdcfa6SKazutaka YOKOTA 	}
256644bdcfa6SKazutaka YOKOTA 	button <<= 1;
256744bdcfa6SKazutaka YOKOTA 	mask >>= 1;
256844bdcfa6SKazutaka YOKOTA     }
256944bdcfa6SKazutaka YOKOTA }
257044bdcfa6SKazutaka YOKOTA 
257144bdcfa6SKazutaka YOKOTA static int
257244bdcfa6SKazutaka YOKOTA r_timeout(void)
257344bdcfa6SKazutaka YOKOTA {
257413f1c59bSJung-uk Kim     struct timespec ts;
257513f1c59bSJung-uk Kim     struct timespec ts1;
257613f1c59bSJung-uk Kim     struct timespec ts2;
257744bdcfa6SKazutaka YOKOTA 
2578127d54baSKazutaka YOKOTA     if (states[mouse_button_state].timeout)
25792657f6e9SJung-uk Kim 	return (TRUE);
258013f1c59bSJung-uk Kim     clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
258113f1c59bSJung-uk Kim     ts2.tv_sec = rodent.button2timeout / 1000;
258213f1c59bSJung-uk Kim     ts2.tv_nsec = (rodent.button2timeout % 1000) * 1000000;
258313f1c59bSJung-uk Kim     tssub(&ts1, &ts2, &ts);
25842657f6e9SJung-uk Kim     return (tscmp(&ts, &mouse_button_state_ts, >));
258544bdcfa6SKazutaka YOKOTA }
258644bdcfa6SKazutaka YOKOTA 
258744bdcfa6SKazutaka YOKOTA static void
258844bdcfa6SKazutaka YOKOTA r_click(mousestatus_t *act)
258944bdcfa6SKazutaka YOKOTA {
259044bdcfa6SKazutaka YOKOTA     struct mouse_info mouse;
25915f436cfbSKazutaka YOKOTA     int button;
25925f436cfbSKazutaka YOKOTA     int mask;
25935f436cfbSKazutaka YOKOTA     int i;
25945f436cfbSKazutaka YOKOTA 
25955f436cfbSKazutaka YOKOTA     mask = act->flags & MOUSE_BUTTONS;
25965f436cfbSKazutaka YOKOTA     if (mask == 0)
25975f436cfbSKazutaka YOKOTA 	return;
25985f436cfbSKazutaka YOKOTA 
25995f436cfbSKazutaka YOKOTA     button = MOUSE_BUTTON1DOWN;
26005f436cfbSKazutaka YOKOTA     for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
26015f436cfbSKazutaka YOKOTA 	if (mask & 1) {
260244bdcfa6SKazutaka YOKOTA 	    debug("mstate[%d]->count:%d", i, mstate[i]->count);
26035f436cfbSKazutaka YOKOTA 	    if (act->button & button) {
26045f436cfbSKazutaka YOKOTA 		/* the button is down */
260544bdcfa6SKazutaka YOKOTA 		mouse.u.event.value = mstate[i]->count;
2606e3b00983SKazutaka YOKOTA 	    } else {
2607e3b00983SKazutaka YOKOTA 		/* the button is up */
26085f436cfbSKazutaka YOKOTA 		mouse.u.event.value = 0;
26095f436cfbSKazutaka YOKOTA 	    }
26105f436cfbSKazutaka YOKOTA 	    mouse.operation = MOUSE_BUTTON_EVENT;
26115f436cfbSKazutaka YOKOTA 	    mouse.u.event.id = button;
26125f436cfbSKazutaka YOKOTA 	    if (debug < 2)
26139eac5bb9SPhilip Paeps 		if (!paused)
26145f436cfbSKazutaka YOKOTA 		    ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
26155f436cfbSKazutaka YOKOTA 	    debug("button %d  count %d", i + 1, mouse.u.event.value);
26165f436cfbSKazutaka YOKOTA 	}
26175f436cfbSKazutaka YOKOTA 	button <<= 1;
26185f436cfbSKazutaka YOKOTA 	mask >>= 1;
26195f436cfbSKazutaka YOKOTA     }
2620ad771aa1SSøren Schmidt }
262113379e47SPeter Wemm 
262213379e47SPeter Wemm /* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
262313379e47SPeter Wemm /* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
262413379e47SPeter Wemm /*
262513379e47SPeter Wemm  * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
262613379e47SPeter Wemm  *
262713379e47SPeter Wemm  * Permission to use, copy, modify, distribute, and sell this software and its
262813379e47SPeter Wemm  * documentation for any purpose is hereby granted without fee, provided that
262913379e47SPeter Wemm  * the above copyright notice appear in all copies and that both that
263013379e47SPeter Wemm  * copyright notice and this permission notice appear in supporting
263113379e47SPeter Wemm  * documentation, and that the name of David Dawes
263213379e47SPeter Wemm  * not be used in advertising or publicity pertaining to distribution of
263313379e47SPeter Wemm  * the software without specific, written prior permission.
263413379e47SPeter Wemm  * David Dawes makes no representations about the suitability of this
263513379e47SPeter Wemm  * software for any purpose.  It is provided "as is" without express or
263613379e47SPeter Wemm  * implied warranty.
263713379e47SPeter Wemm  *
263813379e47SPeter Wemm  * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
263913379e47SPeter Wemm  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
264013379e47SPeter Wemm  * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
264113379e47SPeter Wemm  * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
264213379e47SPeter Wemm  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
264313379e47SPeter Wemm  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
264413379e47SPeter Wemm  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
264513379e47SPeter Wemm  *
264613379e47SPeter Wemm  */
264713379e47SPeter Wemm 
264813379e47SPeter Wemm 
26495f436cfbSKazutaka YOKOTA static void
26505f436cfbSKazutaka YOKOTA setmousespeed(int old, int new, unsigned cflag)
265113379e47SPeter Wemm {
265213379e47SPeter Wemm 	struct termios tty;
26532657f6e9SJung-uk Kim 	const char *c;
265413379e47SPeter Wemm 
265513379e47SPeter Wemm 	if (tcgetattr(rodent.mfd, &tty) < 0)
265613379e47SPeter Wemm 	{
265762e621e8SIan Dowse 		logwarn("unable to get status of mouse fd");
26585f436cfbSKazutaka YOKOTA 		return;
265913379e47SPeter Wemm 	}
266013379e47SPeter Wemm 
266113379e47SPeter Wemm 	tty.c_iflag = IGNBRK | IGNPAR;
266213379e47SPeter Wemm 	tty.c_oflag = 0;
266313379e47SPeter Wemm 	tty.c_lflag = 0;
266413379e47SPeter Wemm 	tty.c_cflag = (tcflag_t)cflag;
266513379e47SPeter Wemm 	tty.c_cc[VTIME] = 0;
266613379e47SPeter Wemm 	tty.c_cc[VMIN] = 1;
266713379e47SPeter Wemm 
266813379e47SPeter Wemm 	switch (old)
266913379e47SPeter Wemm 	{
267013379e47SPeter Wemm 	case 9600:
267113379e47SPeter Wemm 		cfsetispeed(&tty, B9600);
267213379e47SPeter Wemm 		cfsetospeed(&tty, B9600);
267313379e47SPeter Wemm 		break;
267413379e47SPeter Wemm 	case 4800:
267513379e47SPeter Wemm 		cfsetispeed(&tty, B4800);
267613379e47SPeter Wemm 		cfsetospeed(&tty, B4800);
267713379e47SPeter Wemm 		break;
267813379e47SPeter Wemm 	case 2400:
267913379e47SPeter Wemm 		cfsetispeed(&tty, B2400);
268013379e47SPeter Wemm 		cfsetospeed(&tty, B2400);
268113379e47SPeter Wemm 		break;
268213379e47SPeter Wemm 	case 1200:
268313379e47SPeter Wemm 	default:
268413379e47SPeter Wemm 		cfsetispeed(&tty, B1200);
268513379e47SPeter Wemm 		cfsetospeed(&tty, B1200);
268613379e47SPeter Wemm 	}
268713379e47SPeter Wemm 
268813379e47SPeter Wemm 	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
268913379e47SPeter Wemm 	{
269062e621e8SIan Dowse 		logwarn("unable to set status of mouse fd");
26915f436cfbSKazutaka YOKOTA 		return;
269213379e47SPeter Wemm 	}
269313379e47SPeter Wemm 
269413379e47SPeter Wemm 	switch (new)
269513379e47SPeter Wemm 	{
269613379e47SPeter Wemm 	case 9600:
269713379e47SPeter Wemm 		c = "*q";
269813379e47SPeter Wemm 		cfsetispeed(&tty, B9600);
269913379e47SPeter Wemm 		cfsetospeed(&tty, B9600);
270013379e47SPeter Wemm 		break;
270113379e47SPeter Wemm 	case 4800:
270213379e47SPeter Wemm 		c = "*p";
270313379e47SPeter Wemm 		cfsetispeed(&tty, B4800);
270413379e47SPeter Wemm 		cfsetospeed(&tty, B4800);
270513379e47SPeter Wemm 		break;
270613379e47SPeter Wemm 	case 2400:
270713379e47SPeter Wemm 		c = "*o";
270813379e47SPeter Wemm 		cfsetispeed(&tty, B2400);
270913379e47SPeter Wemm 		cfsetospeed(&tty, B2400);
271013379e47SPeter Wemm 		break;
271113379e47SPeter Wemm 	case 1200:
271213379e47SPeter Wemm 	default:
271313379e47SPeter Wemm 		c = "*n";
271413379e47SPeter Wemm 		cfsetispeed(&tty, B1200);
271513379e47SPeter Wemm 		cfsetospeed(&tty, B1200);
271613379e47SPeter Wemm 	}
271713379e47SPeter Wemm 
27185f436cfbSKazutaka YOKOTA 	if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN
27195f436cfbSKazutaka YOKOTA 	    || rodent.rtype == MOUSE_PROTO_LOGI)
272013379e47SPeter Wemm 	{
272113379e47SPeter Wemm 		if (write(rodent.mfd, c, 2) != 2)
272213379e47SPeter Wemm 		{
272362e621e8SIan Dowse 			logwarn("unable to write to mouse fd");
27245f436cfbSKazutaka YOKOTA 			return;
272513379e47SPeter Wemm 		}
272613379e47SPeter Wemm 	}
272713379e47SPeter Wemm 	usleep(100000);
272813379e47SPeter Wemm 
272913379e47SPeter Wemm 	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
273062e621e8SIan Dowse 		logwarn("unable to set status of mouse fd");
273113379e47SPeter Wemm }
27325f436cfbSKazutaka YOKOTA 
27335f436cfbSKazutaka YOKOTA /*
27345f436cfbSKazutaka YOKOTA  * PnP COM device support
27355f436cfbSKazutaka YOKOTA  *
27365f436cfbSKazutaka YOKOTA  * It's a simplistic implementation, but it works :-)
27375f436cfbSKazutaka YOKOTA  * KY, 31/7/97.
27385f436cfbSKazutaka YOKOTA  */
27395f436cfbSKazutaka YOKOTA 
27405f436cfbSKazutaka YOKOTA /*
27415f436cfbSKazutaka YOKOTA  * Try to elicit a PnP ID as described in
27425f436cfbSKazutaka YOKOTA  * Microsoft, Hayes: "Plug and Play External COM Device Specification,
27435f436cfbSKazutaka YOKOTA  * rev 1.00", 1995.
27445f436cfbSKazutaka YOKOTA  *
27455f436cfbSKazutaka YOKOTA  * The routine does not fully implement the COM Enumerator as par Section
27465f436cfbSKazutaka YOKOTA  * 2.1 of the document.  In particular, we don't have idle state in which
27475f436cfbSKazutaka YOKOTA  * the driver software monitors the com port for dynamic connection or
27485f436cfbSKazutaka YOKOTA  * removal of a device at the port, because `moused' simply quits if no
27495f436cfbSKazutaka YOKOTA  * device is found.
27505f436cfbSKazutaka YOKOTA  *
27515f436cfbSKazutaka YOKOTA  * In addition, as PnP COM device enumeration procedure slightly has
27525f436cfbSKazutaka YOKOTA  * changed since its first publication, devices which follow earlier
27535f436cfbSKazutaka YOKOTA  * revisions of the above spec. may fail to respond if the rev 1.0
27545f436cfbSKazutaka YOKOTA  * procedure is used. XXX
27555f436cfbSKazutaka YOKOTA  */
27565f436cfbSKazutaka YOKOTA static int
2757f41621f9SKazutaka YOKOTA pnpwakeup1(void)
27585f436cfbSKazutaka YOKOTA {
27595f436cfbSKazutaka YOKOTA     struct timeval timeout;
27605f436cfbSKazutaka YOKOTA     fd_set fds;
27615f436cfbSKazutaka YOKOTA     int i;
27625f436cfbSKazutaka YOKOTA 
27635f436cfbSKazutaka YOKOTA     /*
27645f436cfbSKazutaka YOKOTA      * This is the procedure described in rev 1.0 of PnP COM device spec.
27655f436cfbSKazutaka YOKOTA      * Unfortunately, some devices which comform to earlier revisions of
27665f436cfbSKazutaka YOKOTA      * the spec gets confused and do not return the ID string...
27675f436cfbSKazutaka YOKOTA      */
2768f41621f9SKazutaka YOKOTA     debug("PnP COM device rev 1.0 probe...");
27695f436cfbSKazutaka YOKOTA 
27705f436cfbSKazutaka YOKOTA     /* port initialization (2.1.2) */
27715f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMGET, &i);
27725f436cfbSKazutaka YOKOTA     i |= TIOCM_DTR;		/* DTR = 1 */
27735f436cfbSKazutaka YOKOTA     i &= ~TIOCM_RTS;		/* RTS = 0 */
27745f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMSET, &i);
2775f41621f9SKazutaka YOKOTA     usleep(240000);
2776f41621f9SKazutaka YOKOTA 
2777f41621f9SKazutaka YOKOTA     /*
2778f41621f9SKazutaka YOKOTA      * The PnP COM device spec. dictates that the mouse must set DSR
2779f41621f9SKazutaka YOKOTA      * in response to DTR (by hardware or by software) and that if DSR is
2780f41621f9SKazutaka YOKOTA      * not asserted, the host computer should think that there is no device
2781c49f79b7SKazutaka YOKOTA      * at this serial port.  But some mice just don't do that...
2782f41621f9SKazutaka YOKOTA      */
2783f41621f9SKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMGET, &i);
2784f41621f9SKazutaka YOKOTA     debug("modem status 0%o", i);
2785f41621f9SKazutaka YOKOTA     if ((i & TIOCM_DSR) == 0)
27862657f6e9SJung-uk Kim 	return (FALSE);
27875f436cfbSKazutaka YOKOTA 
27885f436cfbSKazutaka YOKOTA     /* port setup, 1st phase (2.1.3) */
27895f436cfbSKazutaka YOKOTA     setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
27905f436cfbSKazutaka YOKOTA     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
27915f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMBIC, &i);
2792f41621f9SKazutaka YOKOTA     usleep(240000);
27935f436cfbSKazutaka YOKOTA     i = TIOCM_DTR;		/* DTR = 1, RTS = 0 */
27945f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMBIS, &i);
2795f41621f9SKazutaka YOKOTA     usleep(240000);
27965f436cfbSKazutaka YOKOTA 
27975f436cfbSKazutaka YOKOTA     /* wait for response, 1st phase (2.1.4) */
27985f436cfbSKazutaka YOKOTA     i = FREAD;
27995f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCFLUSH, &i);
28005f436cfbSKazutaka YOKOTA     i = TIOCM_RTS;		/* DTR = 1, RTS = 1 */
28015f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMBIS, &i);
28025f436cfbSKazutaka YOKOTA 
28035f436cfbSKazutaka YOKOTA     /* try to read something */
28045f436cfbSKazutaka YOKOTA     FD_ZERO(&fds);
28055f436cfbSKazutaka YOKOTA     FD_SET(rodent.mfd, &fds);
28065f436cfbSKazutaka YOKOTA     timeout.tv_sec = 0;
2807f41621f9SKazutaka YOKOTA     timeout.tv_usec = 240000;
2808f41621f9SKazutaka YOKOTA     if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2809f41621f9SKazutaka YOKOTA 	debug("pnpwakeup1(): valid response in first phase.");
28102657f6e9SJung-uk Kim 	return (TRUE);
2811c49f79b7SKazutaka YOKOTA     }
28125f436cfbSKazutaka YOKOTA 
28135f436cfbSKazutaka YOKOTA     /* port setup, 2nd phase (2.1.5) */
28145f436cfbSKazutaka YOKOTA     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
28155f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMBIC, &i);
2816f41621f9SKazutaka YOKOTA     usleep(240000);
28175f436cfbSKazutaka YOKOTA 
28185f436cfbSKazutaka YOKOTA     /* wait for respose, 2nd phase (2.1.6) */
28195f436cfbSKazutaka YOKOTA     i = FREAD;
28205f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCFLUSH, &i);
28215f436cfbSKazutaka YOKOTA     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
28225f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMBIS, &i);
28235f436cfbSKazutaka YOKOTA 
28245f436cfbSKazutaka YOKOTA     /* try to read something */
28255f436cfbSKazutaka YOKOTA     FD_ZERO(&fds);
28265f436cfbSKazutaka YOKOTA     FD_SET(rodent.mfd, &fds);
28275f436cfbSKazutaka YOKOTA     timeout.tv_sec = 0;
2828f41621f9SKazutaka YOKOTA     timeout.tv_usec = 240000;
2829f41621f9SKazutaka YOKOTA     if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2830f41621f9SKazutaka YOKOTA 	debug("pnpwakeup1(): valid response in second phase.");
28312657f6e9SJung-uk Kim 	return (TRUE);
28325f436cfbSKazutaka YOKOTA     }
2833c49f79b7SKazutaka YOKOTA 
28342657f6e9SJung-uk Kim     return (FALSE);
2835f41621f9SKazutaka YOKOTA }
2836f41621f9SKazutaka YOKOTA 
2837f41621f9SKazutaka YOKOTA static int
2838f41621f9SKazutaka YOKOTA pnpwakeup2(void)
2839f41621f9SKazutaka YOKOTA {
2840f41621f9SKazutaka YOKOTA     struct timeval timeout;
2841f41621f9SKazutaka YOKOTA     fd_set fds;
2842f41621f9SKazutaka YOKOTA     int i;
2843f41621f9SKazutaka YOKOTA 
28445f436cfbSKazutaka YOKOTA     /*
28455f436cfbSKazutaka YOKOTA      * This is a simplified procedure; it simply toggles RTS.
28465f436cfbSKazutaka YOKOTA      */
2847c49f79b7SKazutaka YOKOTA     debug("alternate probe...");
28485f436cfbSKazutaka YOKOTA 
28495f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMGET, &i);
28505f436cfbSKazutaka YOKOTA     i |= TIOCM_DTR;		/* DTR = 1 */
28515f436cfbSKazutaka YOKOTA     i &= ~TIOCM_RTS;		/* RTS = 0 */
28525f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMSET, &i);
2853f41621f9SKazutaka YOKOTA     usleep(240000);
28545f436cfbSKazutaka YOKOTA 
28555f436cfbSKazutaka YOKOTA     setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
28565f436cfbSKazutaka YOKOTA 
28575f436cfbSKazutaka YOKOTA     /* wait for respose */
28585f436cfbSKazutaka YOKOTA     i = FREAD;
28595f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCFLUSH, &i);
28605f436cfbSKazutaka YOKOTA     i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
28615f436cfbSKazutaka YOKOTA     ioctl(rodent.mfd, TIOCMBIS, &i);
28625f436cfbSKazutaka YOKOTA 
28635f436cfbSKazutaka YOKOTA     /* try to read something */
28645f436cfbSKazutaka YOKOTA     FD_ZERO(&fds);
28655f436cfbSKazutaka YOKOTA     FD_SET(rodent.mfd, &fds);
28665f436cfbSKazutaka YOKOTA     timeout.tv_sec = 0;
2867f41621f9SKazutaka YOKOTA     timeout.tv_usec = 240000;
2868f41621f9SKazutaka YOKOTA     if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2869f41621f9SKazutaka YOKOTA 	debug("pnpwakeup2(): valid response.");
28702657f6e9SJung-uk Kim 	return (TRUE);
28715f436cfbSKazutaka YOKOTA     }
2872c49f79b7SKazutaka YOKOTA 
28732657f6e9SJung-uk Kim     return (FALSE);
28745f436cfbSKazutaka YOKOTA }
28755f436cfbSKazutaka YOKOTA 
2876f41621f9SKazutaka YOKOTA static int
2877f41621f9SKazutaka YOKOTA pnpgets(char *buf)
2878f41621f9SKazutaka YOKOTA {
2879f41621f9SKazutaka YOKOTA     struct timeval timeout;
2880f41621f9SKazutaka YOKOTA     fd_set fds;
2881f41621f9SKazutaka YOKOTA     int begin;
2882f41621f9SKazutaka YOKOTA     int i;
2883f41621f9SKazutaka YOKOTA     char c;
28845f436cfbSKazutaka YOKOTA 
2885f41621f9SKazutaka YOKOTA     if (!pnpwakeup1() && !pnpwakeup2()) {
28865f436cfbSKazutaka YOKOTA 	/*
28875f436cfbSKazutaka YOKOTA 	 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
28885f436cfbSKazutaka YOKOTA 	 * in idle state.  But, `moused' shall set DTR = RTS = 1 and proceed,
28895f436cfbSKazutaka YOKOTA 	 * assuming there is something at the port even if it didn't
28905f436cfbSKazutaka YOKOTA 	 * respond to the PnP enumeration procedure.
28915f436cfbSKazutaka YOKOTA 	 */
28925f436cfbSKazutaka YOKOTA 	i = TIOCM_DTR | TIOCM_RTS;		/* DTR = 1, RTS = 1 */
28935f436cfbSKazutaka YOKOTA 	ioctl(rodent.mfd, TIOCMBIS, &i);
28942657f6e9SJung-uk Kim 	return (0);
28955f436cfbSKazutaka YOKOTA     }
28965f436cfbSKazutaka YOKOTA 
2897f41621f9SKazutaka YOKOTA     /* collect PnP COM device ID (2.1.7) */
2898f41621f9SKazutaka YOKOTA     begin = -1;
2899f41621f9SKazutaka YOKOTA     i = 0;
2900f41621f9SKazutaka YOKOTA     usleep(240000);	/* the mouse must send `Begin ID' within 200msec */
2901f41621f9SKazutaka YOKOTA     while (read(rodent.mfd, &c, 1) == 1) {
2902f41621f9SKazutaka YOKOTA 	/* we may see "M", or "M3..." before `Begin ID' */
2903f41621f9SKazutaka YOKOTA 	buf[i++] = c;
2904f41621f9SKazutaka YOKOTA 	if ((c == 0x08) || (c == 0x28)) {	/* Begin ID */
2905f41621f9SKazutaka YOKOTA 	    debug("begin-id %02x", c);
2906f41621f9SKazutaka YOKOTA 	    begin = i - 1;
2907f41621f9SKazutaka YOKOTA 	    break;
2908f41621f9SKazutaka YOKOTA 	}
2909f41621f9SKazutaka YOKOTA 	debug("%c %02x", c, c);
2910f41621f9SKazutaka YOKOTA 	if (i >= 256)
2911f41621f9SKazutaka YOKOTA 	    break;
2912f41621f9SKazutaka YOKOTA     }
2913f41621f9SKazutaka YOKOTA     if (begin < 0) {
2914f41621f9SKazutaka YOKOTA 	/* we haven't seen `Begin ID' in time... */
2915f41621f9SKazutaka YOKOTA 	goto connect_idle;
2916f41621f9SKazutaka YOKOTA     }
2917f41621f9SKazutaka YOKOTA 
2918f41621f9SKazutaka YOKOTA     ++c;			/* make it `End ID' */
2919f41621f9SKazutaka YOKOTA     for (;;) {
2920f41621f9SKazutaka YOKOTA 	FD_ZERO(&fds);
2921f41621f9SKazutaka YOKOTA 	FD_SET(rodent.mfd, &fds);
2922f41621f9SKazutaka YOKOTA 	timeout.tv_sec = 0;
2923f41621f9SKazutaka YOKOTA 	timeout.tv_usec = 240000;
2924f41621f9SKazutaka YOKOTA 	if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
2925f41621f9SKazutaka YOKOTA 	    break;
2926f41621f9SKazutaka YOKOTA 
2927f41621f9SKazutaka YOKOTA 	read(rodent.mfd, &buf[i], 1);
2928f41621f9SKazutaka YOKOTA 	if (buf[i++] == c)	/* End ID */
2929f41621f9SKazutaka YOKOTA 	    break;
2930f41621f9SKazutaka YOKOTA 	if (i >= 256)
2931f41621f9SKazutaka YOKOTA 	    break;
2932f41621f9SKazutaka YOKOTA     }
2933f41621f9SKazutaka YOKOTA     if (begin > 0) {
2934f41621f9SKazutaka YOKOTA 	i -= begin;
2935f41621f9SKazutaka YOKOTA 	bcopy(&buf[begin], &buf[0], i);
2936f41621f9SKazutaka YOKOTA     }
2937f41621f9SKazutaka YOKOTA     /* string may not be human readable... */
2938f41621f9SKazutaka YOKOTA     debug("len:%d, '%-*.*s'", i, i, i, buf);
2939f41621f9SKazutaka YOKOTA 
2940f41621f9SKazutaka YOKOTA     if (buf[i - 1] == c)
29412657f6e9SJung-uk Kim 	return (i);		/* a valid PnP string */
2942f41621f9SKazutaka YOKOTA 
2943f41621f9SKazutaka YOKOTA     /*
2944f41621f9SKazutaka YOKOTA      * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2945f41621f9SKazutaka YOKOTA      * in idle state.  But, `moused' shall leave the modem control lines
2946f41621f9SKazutaka YOKOTA      * as they are. See above.
2947f41621f9SKazutaka YOKOTA      */
2948f41621f9SKazutaka YOKOTA connect_idle:
2949f41621f9SKazutaka YOKOTA 
2950f41621f9SKazutaka YOKOTA     /* we may still have something in the buffer */
29515d6026c2SMarcelo Araujo     return (MAX(i, 0));
2952f41621f9SKazutaka YOKOTA }
2953f41621f9SKazutaka YOKOTA 
29545f436cfbSKazutaka YOKOTA static int
29555f436cfbSKazutaka YOKOTA pnpparse(pnpid_t *id, char *buf, int len)
29565f436cfbSKazutaka YOKOTA {
29575f436cfbSKazutaka YOKOTA     char s[3];
29585f436cfbSKazutaka YOKOTA     int offset;
29595f436cfbSKazutaka YOKOTA     int sum = 0;
29605f436cfbSKazutaka YOKOTA     int i, j;
29615f436cfbSKazutaka YOKOTA 
29625f436cfbSKazutaka YOKOTA     id->revision = 0;
29635f436cfbSKazutaka YOKOTA     id->eisaid = NULL;
29645f436cfbSKazutaka YOKOTA     id->serial = NULL;
29655f436cfbSKazutaka YOKOTA     id->class = NULL;
29665f436cfbSKazutaka YOKOTA     id->compat = NULL;
29675f436cfbSKazutaka YOKOTA     id->description = NULL;
29685f436cfbSKazutaka YOKOTA     id->neisaid = 0;
29695f436cfbSKazutaka YOKOTA     id->nserial = 0;
29705f436cfbSKazutaka YOKOTA     id->nclass = 0;
29715f436cfbSKazutaka YOKOTA     id->ncompat = 0;
29725f436cfbSKazutaka YOKOTA     id->ndescription = 0;
29735f436cfbSKazutaka YOKOTA 
2974f41621f9SKazutaka YOKOTA     if ((buf[0] != 0x28) && (buf[0] != 0x08)) {
2975f41621f9SKazutaka YOKOTA 	/* non-PnP mice */
2976f41621f9SKazutaka YOKOTA 	switch(buf[0]) {
2977f41621f9SKazutaka YOKOTA 	default:
29782657f6e9SJung-uk Kim 	    return (FALSE);
2979f41621f9SKazutaka YOKOTA 	case 'M': /* Microsoft */
2980f41621f9SKazutaka YOKOTA 	    id->eisaid = "PNP0F01";
2981f41621f9SKazutaka YOKOTA 	    break;
2982f41621f9SKazutaka YOKOTA 	case 'H': /* MouseSystems */
2983f41621f9SKazutaka YOKOTA 	    id->eisaid = "PNP0F04";
2984f41621f9SKazutaka YOKOTA 	    break;
2985f41621f9SKazutaka YOKOTA 	}
2986f41621f9SKazutaka YOKOTA 	id->neisaid = strlen(id->eisaid);
2987f41621f9SKazutaka YOKOTA 	id->class = "MOUSE";
2988f41621f9SKazutaka YOKOTA 	id->nclass = strlen(id->class);
2989f41621f9SKazutaka YOKOTA 	debug("non-PnP mouse '%c'", buf[0]);
29902657f6e9SJung-uk Kim 	return (TRUE);
2991f41621f9SKazutaka YOKOTA     }
2992f41621f9SKazutaka YOKOTA 
2993f41621f9SKazutaka YOKOTA     /* PnP mice */
29945f436cfbSKazutaka YOKOTA     offset = 0x28 - buf[0];
29955f436cfbSKazutaka YOKOTA 
29965f436cfbSKazutaka YOKOTA     /* calculate checksum */
29975f436cfbSKazutaka YOKOTA     for (i = 0; i < len - 3; ++i) {
29985f436cfbSKazutaka YOKOTA 	sum += buf[i];
29995f436cfbSKazutaka YOKOTA 	buf[i] += offset;
30005f436cfbSKazutaka YOKOTA     }
30015f436cfbSKazutaka YOKOTA     sum += buf[len - 1];
30025f436cfbSKazutaka YOKOTA     for (; i < len; ++i)
30035f436cfbSKazutaka YOKOTA 	buf[i] += offset;
30045f436cfbSKazutaka YOKOTA     debug("PnP ID string: '%*.*s'", len, len, buf);
30055f436cfbSKazutaka YOKOTA 
30065f436cfbSKazutaka YOKOTA     /* revision */
30075f436cfbSKazutaka YOKOTA     buf[1] -= offset;
30085f436cfbSKazutaka YOKOTA     buf[2] -= offset;
30095f436cfbSKazutaka YOKOTA     id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
30105f436cfbSKazutaka YOKOTA     debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100);
30115f436cfbSKazutaka YOKOTA 
3012de1a17dbSElyes Haouas     /* EISA vendor and product ID */
30135f436cfbSKazutaka YOKOTA     id->eisaid = &buf[3];
30145f436cfbSKazutaka YOKOTA     id->neisaid = 7;
30155f436cfbSKazutaka YOKOTA 
30165f436cfbSKazutaka YOKOTA     /* option strings */
30175f436cfbSKazutaka YOKOTA     i = 10;
30185f436cfbSKazutaka YOKOTA     if (buf[i] == '\\') {
30195f436cfbSKazutaka YOKOTA 	/* device serial # */
30205f436cfbSKazutaka YOKOTA 	for (j = ++i; i < len; ++i) {
30215f436cfbSKazutaka YOKOTA 	    if (buf[i] == '\\')
30225f436cfbSKazutaka YOKOTA 		break;
30235f436cfbSKazutaka YOKOTA 	}
30245f436cfbSKazutaka YOKOTA 	if (i >= len)
30255f436cfbSKazutaka YOKOTA 	    i -= 3;
30265f436cfbSKazutaka YOKOTA 	if (i - j == 8) {
30275f436cfbSKazutaka YOKOTA 	    id->serial = &buf[j];
30285f436cfbSKazutaka YOKOTA 	    id->nserial = 8;
30295f436cfbSKazutaka YOKOTA 	}
30305f436cfbSKazutaka YOKOTA     }
30315f436cfbSKazutaka YOKOTA     if (buf[i] == '\\') {
30325f436cfbSKazutaka YOKOTA 	/* PnP class */
30335f436cfbSKazutaka YOKOTA 	for (j = ++i; i < len; ++i) {
30345f436cfbSKazutaka YOKOTA 	    if (buf[i] == '\\')
30355f436cfbSKazutaka YOKOTA 		break;
30365f436cfbSKazutaka YOKOTA 	}
30375f436cfbSKazutaka YOKOTA 	if (i >= len)
30385f436cfbSKazutaka YOKOTA 	    i -= 3;
30395f436cfbSKazutaka YOKOTA 	if (i > j + 1) {
30405f436cfbSKazutaka YOKOTA 	    id->class = &buf[j];
30415f436cfbSKazutaka YOKOTA 	    id->nclass = i - j;
30425f436cfbSKazutaka YOKOTA 	}
30435f436cfbSKazutaka YOKOTA     }
30445f436cfbSKazutaka YOKOTA     if (buf[i] == '\\') {
30455f436cfbSKazutaka YOKOTA 	/* compatible driver */
30465f436cfbSKazutaka YOKOTA 	for (j = ++i; i < len; ++i) {
30475f436cfbSKazutaka YOKOTA 	    if (buf[i] == '\\')
30485f436cfbSKazutaka YOKOTA 		break;
30495f436cfbSKazutaka YOKOTA 	}
30505f436cfbSKazutaka YOKOTA 	/*
30515f436cfbSKazutaka YOKOTA 	 * PnP COM spec prior to v0.96 allowed '*' in this field,
3052de1a17dbSElyes Haouas 	 * it's not allowed now; just ignore it.
30535f436cfbSKazutaka YOKOTA 	 */
30545f436cfbSKazutaka YOKOTA 	if (buf[j] == '*')
30555f436cfbSKazutaka YOKOTA 	    ++j;
30565f436cfbSKazutaka YOKOTA 	if (i >= len)
30575f436cfbSKazutaka YOKOTA 	    i -= 3;
30585f436cfbSKazutaka YOKOTA 	if (i > j + 1) {
30595f436cfbSKazutaka YOKOTA 	    id->compat = &buf[j];
30605f436cfbSKazutaka YOKOTA 	    id->ncompat = i - j;
30615f436cfbSKazutaka YOKOTA 	}
30625f436cfbSKazutaka YOKOTA     }
30635f436cfbSKazutaka YOKOTA     if (buf[i] == '\\') {
30645f436cfbSKazutaka YOKOTA 	/* product description */
30655f436cfbSKazutaka YOKOTA 	for (j = ++i; i < len; ++i) {
30665f436cfbSKazutaka YOKOTA 	    if (buf[i] == ';')
30675f436cfbSKazutaka YOKOTA 		break;
30685f436cfbSKazutaka YOKOTA 	}
30695f436cfbSKazutaka YOKOTA 	if (i >= len)
30705f436cfbSKazutaka YOKOTA 	    i -= 3;
30715f436cfbSKazutaka YOKOTA 	if (i > j + 1) {
30725f436cfbSKazutaka YOKOTA 	    id->description = &buf[j];
30735f436cfbSKazutaka YOKOTA 	    id->ndescription = i - j;
30745f436cfbSKazutaka YOKOTA 	}
30755f436cfbSKazutaka YOKOTA     }
30765f436cfbSKazutaka YOKOTA 
30775f436cfbSKazutaka YOKOTA     /* checksum exists if there are any optional fields */
30785f436cfbSKazutaka YOKOTA     if ((id->nserial > 0) || (id->nclass > 0)
30795f436cfbSKazutaka YOKOTA 	|| (id->ncompat > 0) || (id->ndescription > 0)) {
30805f436cfbSKazutaka YOKOTA 	debug("PnP checksum: 0x%X", sum);
30815f436cfbSKazutaka YOKOTA 	sprintf(s, "%02X", sum & 0x0ff);
30825f436cfbSKazutaka YOKOTA 	if (strncmp(s, &buf[len - 3], 2) != 0) {
30835f436cfbSKazutaka YOKOTA #if 0
30845f436cfbSKazutaka YOKOTA 	    /*
30855f436cfbSKazutaka YOKOTA 	     * I found some mice do not comply with the PnP COM device
30865f436cfbSKazutaka YOKOTA 	     * spec regarding checksum... XXX
30875f436cfbSKazutaka YOKOTA 	     */
30885f436cfbSKazutaka YOKOTA 	    logwarnx("PnP checksum error", 0);
30892657f6e9SJung-uk Kim 	    return (FALSE);
30905f436cfbSKazutaka YOKOTA #endif
30915f436cfbSKazutaka YOKOTA 	}
30925f436cfbSKazutaka YOKOTA     }
30935f436cfbSKazutaka YOKOTA 
30942657f6e9SJung-uk Kim     return (TRUE);
30955f436cfbSKazutaka YOKOTA }
30965f436cfbSKazutaka YOKOTA 
30975f436cfbSKazutaka YOKOTA static symtab_t *
30985f436cfbSKazutaka YOKOTA pnpproto(pnpid_t *id)
30995f436cfbSKazutaka YOKOTA {
31005f436cfbSKazutaka YOKOTA     symtab_t *t;
31015f436cfbSKazutaka YOKOTA     int i, j;
31025f436cfbSKazutaka YOKOTA 
31035f436cfbSKazutaka YOKOTA     if (id->nclass > 0)
31041b11ca6cSKazutaka YOKOTA 	if (strncmp(id->class, "MOUSE", id->nclass) != 0 &&
31051b11ca6cSKazutaka YOKOTA 	    strncmp(id->class, "TABLET", id->nclass) != 0)
31065f436cfbSKazutaka YOKOTA 	    /* this is not a mouse! */
31072657f6e9SJung-uk Kim 	    return (NULL);
31085f436cfbSKazutaka YOKOTA 
31095f436cfbSKazutaka YOKOTA     if (id->neisaid > 0) {
31105f436cfbSKazutaka YOKOTA 	t = gettoken(pnpprod, id->eisaid, id->neisaid);
31115f436cfbSKazutaka YOKOTA 	if (t->val != MOUSE_PROTO_UNKNOWN)
31122657f6e9SJung-uk Kim 	    return (t);
31135f436cfbSKazutaka YOKOTA     }
31145f436cfbSKazutaka YOKOTA 
31155f436cfbSKazutaka YOKOTA     /*
31165f436cfbSKazutaka YOKOTA      * The 'Compatible drivers' field may contain more than one
31175f436cfbSKazutaka YOKOTA      * ID separated by ','.
31185f436cfbSKazutaka YOKOTA      */
31195f436cfbSKazutaka YOKOTA     if (id->ncompat <= 0)
31202657f6e9SJung-uk Kim 	return (NULL);
31215f436cfbSKazutaka YOKOTA     for (i = 0; i < id->ncompat; ++i) {
31225f436cfbSKazutaka YOKOTA 	for (j = i; id->compat[i] != ','; ++i)
31235f436cfbSKazutaka YOKOTA 	    if (i >= id->ncompat)
31245f436cfbSKazutaka YOKOTA 		break;
31255f436cfbSKazutaka YOKOTA 	if (i > j) {
31265f436cfbSKazutaka YOKOTA 	    t = gettoken(pnpprod, id->compat + j, i - j);
31275f436cfbSKazutaka YOKOTA 	    if (t->val != MOUSE_PROTO_UNKNOWN)
31282657f6e9SJung-uk Kim 		return (t);
31295f436cfbSKazutaka YOKOTA 	}
31305f436cfbSKazutaka YOKOTA     }
31315f436cfbSKazutaka YOKOTA 
31322657f6e9SJung-uk Kim     return (NULL);
31335f436cfbSKazutaka YOKOTA }
31345f436cfbSKazutaka YOKOTA 
31355f436cfbSKazutaka YOKOTA /* name/val mapping */
31365f436cfbSKazutaka YOKOTA 
31375f436cfbSKazutaka YOKOTA static symtab_t *
31382657f6e9SJung-uk Kim gettoken(symtab_t *tab, const char *s, int len)
31395f436cfbSKazutaka YOKOTA {
31405f436cfbSKazutaka YOKOTA     int i;
31415f436cfbSKazutaka YOKOTA 
31425f436cfbSKazutaka YOKOTA     for (i = 0; tab[i].name != NULL; ++i) {
31435f436cfbSKazutaka YOKOTA 	if (strncmp(tab[i].name, s, len) == 0)
31445f436cfbSKazutaka YOKOTA 	    break;
31455f436cfbSKazutaka YOKOTA     }
31462657f6e9SJung-uk Kim     return (&tab[i]);
31475f436cfbSKazutaka YOKOTA }
31485f436cfbSKazutaka YOKOTA 
31492657f6e9SJung-uk Kim static const char *
31505f436cfbSKazutaka YOKOTA gettokenname(symtab_t *tab, int val)
31515f436cfbSKazutaka YOKOTA {
31522657f6e9SJung-uk Kim     static const char unknown[] = "unknown";
31535f436cfbSKazutaka YOKOTA     int i;
31545f436cfbSKazutaka YOKOTA 
31555f436cfbSKazutaka YOKOTA     for (i = 0; tab[i].name != NULL; ++i) {
31565f436cfbSKazutaka YOKOTA 	if (tab[i].val == val)
31572657f6e9SJung-uk Kim 	    return (tab[i].name);
31585f436cfbSKazutaka YOKOTA     }
31592657f6e9SJung-uk Kim     return (unknown);
316013379e47SPeter Wemm }
316167978692SAmancio Hasty 
31621b11ca6cSKazutaka YOKOTA 
31631b11ca6cSKazutaka YOKOTA /*
31641b11ca6cSKazutaka YOKOTA  * code to read from the Genius Kidspad tablet.
31651b11ca6cSKazutaka YOKOTA 
31661b11ca6cSKazutaka YOKOTA The tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005,
31671b11ca6cSKazutaka YOKOTA and to pre-pnp probes (RTS toggle) with 'T' (tablet ?)
31681b11ca6cSKazutaka YOKOTA 9600, 8 bit, parity odd.
31691b11ca6cSKazutaka YOKOTA 
31701b11ca6cSKazutaka YOKOTA The tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains
31711b11ca6cSKazutaka YOKOTA the proximity, tip and button info:
31721b11ca6cSKazutaka YOKOTA    (byte0 & 0x1)	true = tip pressed
31731b11ca6cSKazutaka YOKOTA    (byte0 & 0x2)	true = button pressed
31741b11ca6cSKazutaka YOKOTA    (byte0 & 0x40)	false = pen in proximity of tablet.
31751b11ca6cSKazutaka YOKOTA 
31761b11ca6cSKazutaka YOKOTA The next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid).
31771b11ca6cSKazutaka YOKOTA 
31781b11ca6cSKazutaka YOKOTA Only absolute coordinates are returned, so we use the following approach:
31791b11ca6cSKazutaka YOKOTA we store the last coordinates sent when the pen went out of the tablet,
31801b11ca6cSKazutaka YOKOTA 
31811b11ca6cSKazutaka YOKOTA 
31821b11ca6cSKazutaka YOKOTA  *
31831b11ca6cSKazutaka YOKOTA  */
31841b11ca6cSKazutaka YOKOTA 
31851b11ca6cSKazutaka YOKOTA typedef enum {
31861b11ca6cSKazutaka YOKOTA     S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP
31871b11ca6cSKazutaka YOKOTA } k_status;
31881b11ca6cSKazutaka YOKOTA 
31891b11ca6cSKazutaka YOKOTA static int
31901b11ca6cSKazutaka YOKOTA kidspad(u_char rxc, mousestatus_t *act)
31911b11ca6cSKazutaka YOKOTA {
319262e621e8SIan Dowse     static int buf[5];
31931b11ca6cSKazutaka YOKOTA     static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1;
31941b11ca6cSKazutaka YOKOTA     static k_status status = S_IDLE;
31956240691aSEitan Adler     static struct timespec now;
31961b11ca6cSKazutaka YOKOTA 
31977309915eSDima Dorfman     int x, y;
31981b11ca6cSKazutaka YOKOTA 
31991b11ca6cSKazutaka YOKOTA     if (buflen > 0 && (rxc & 0x80)) {
32001b11ca6cSKazutaka YOKOTA 	fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc);
32011b11ca6cSKazutaka YOKOTA 	buflen = 0;
32021b11ca6cSKazutaka YOKOTA     }
32031b11ca6cSKazutaka YOKOTA     if (buflen == 0 && (rxc & 0xb8) != 0xb8) {
32041b11ca6cSKazutaka YOKOTA 	fprintf(stderr, "invalid code 0 0x%x\n", rxc);
32052657f6e9SJung-uk Kim 	return (0);	/* invalid code, no action */
32061b11ca6cSKazutaka YOKOTA     }
32071b11ca6cSKazutaka YOKOTA     buf[buflen++] = rxc;
32081b11ca6cSKazutaka YOKOTA     if (buflen < 5)
32092657f6e9SJung-uk Kim 	return (0);
32101b11ca6cSKazutaka YOKOTA 
32111b11ca6cSKazutaka YOKOTA     buflen = 0;	/* for next time... */
32121b11ca6cSKazutaka YOKOTA 
32131b11ca6cSKazutaka YOKOTA     x = buf[1]+128*(buf[2] - 7);
32141b11ca6cSKazutaka YOKOTA     if (x < 0) x = 0;
32151b11ca6cSKazutaka YOKOTA     y = 28*128 - (buf[3] + 128* (buf[4] - 7));
32161b11ca6cSKazutaka YOKOTA     if (y < 0) y = 0;
32171b11ca6cSKazutaka YOKOTA 
32181b11ca6cSKazutaka YOKOTA     x /= 8;
32191b11ca6cSKazutaka YOKOTA     y /= 8;
32201b11ca6cSKazutaka YOKOTA 
32211b11ca6cSKazutaka YOKOTA     act->flags = 0;
32221b11ca6cSKazutaka YOKOTA     act->obutton = act->button;
32231b11ca6cSKazutaka YOKOTA     act->dx = act->dy = act->dz = 0;
322413f1c59bSJung-uk Kim     clock_gettime(CLOCK_MONOTONIC_FAST, &now);
32251b11ca6cSKazutaka YOKOTA     if (buf[0] & 0x40) /* pen went out of reach */
32261b11ca6cSKazutaka YOKOTA 	status = S_IDLE;
32271b11ca6cSKazutaka YOKOTA     else if (status == S_IDLE) { /* pen is newly near the tablet */
32281b11ca6cSKazutaka YOKOTA 	act->flags |= MOUSE_POSCHANGED;	/* force update */
32291b11ca6cSKazutaka YOKOTA 	status = S_PROXY;
32301b11ca6cSKazutaka YOKOTA 	x_prev = x;
32311b11ca6cSKazutaka YOKOTA 	y_prev = y;
32321b11ca6cSKazutaka YOKOTA     }
32331b11ca6cSKazutaka YOKOTA     act->dx = x - x_prev;
32341b11ca6cSKazutaka YOKOTA     act->dy = y - y_prev;
32351b11ca6cSKazutaka YOKOTA     if (act->dx || act->dy)
32361b11ca6cSKazutaka YOKOTA 	act->flags |= MOUSE_POSCHANGED;
32371b11ca6cSKazutaka YOKOTA     x_prev = x;
32381b11ca6cSKazutaka YOKOTA     y_prev = y;
32391b11ca6cSKazutaka YOKOTA     if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */
32401b11ca6cSKazutaka YOKOTA 	act->button = 0;
32411b11ca6cSKazutaka YOKOTA 	if (buf[0] & 0x01) /* tip pressed */
32421b11ca6cSKazutaka YOKOTA 	    act->button |= MOUSE_BUTTON1DOWN;
32431b11ca6cSKazutaka YOKOTA 	if (buf[0] & 0x02) /* button pressed */
32441b11ca6cSKazutaka YOKOTA 	    act->button |= MOUSE_BUTTON2DOWN;
32451b11ca6cSKazutaka YOKOTA 	act->flags |= MOUSE_BUTTONSCHANGED;
32461b11ca6cSKazutaka YOKOTA     }
32471b11ca6cSKazutaka YOKOTA     b_prev = buf[0];
32482657f6e9SJung-uk Kim     return (act->flags);
32491b11ca6cSKazutaka YOKOTA }
32501b11ca6cSKazutaka YOKOTA 
3251ce99e877SMatthew N. Dodd static int
3252ce99e877SMatthew N. Dodd gtco_digipad (u_char rxc, mousestatus_t *act)
3253ce99e877SMatthew N. Dodd {
3254ce99e877SMatthew N. Dodd 	static u_char buf[5];
3255ce99e877SMatthew N. Dodd  	static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1;
3256ce99e877SMatthew N. Dodd 	static k_status status = S_IDLE;
3257ce99e877SMatthew N. Dodd 	int x, y;
3258ce99e877SMatthew N. Dodd 
3259ce99e877SMatthew N. Dodd #define	GTCO_HEADER	0x80
3260ce99e877SMatthew N. Dodd #define	GTCO_PROXIMITY	0x40
3261ce99e877SMatthew N. Dodd #define	GTCO_START	(GTCO_HEADER|GTCO_PROXIMITY)
3262ce99e877SMatthew N. Dodd #define	GTCO_BUTTONMASK	0x3c
3263ce99e877SMatthew N. Dodd 
3264ce99e877SMatthew N. Dodd 
3265ce99e877SMatthew N. Dodd 	if (buflen > 0 && ((rxc & GTCO_HEADER) != GTCO_HEADER)) {
3266ce99e877SMatthew N. Dodd 		fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc);
3267ce99e877SMatthew N. Dodd 		buflen = 0;
3268ce99e877SMatthew N. Dodd 	}
3269ce99e877SMatthew N. Dodd 	if (buflen == 0 && (rxc & GTCO_START) != GTCO_START) {
3270ce99e877SMatthew N. Dodd 		fprintf(stderr, "invalid code 0 0x%x\n", rxc);
32712657f6e9SJung-uk Kim 		return (0);	/* invalid code, no action */
3272ce99e877SMatthew N. Dodd 	}
3273ce99e877SMatthew N. Dodd 
3274ce99e877SMatthew N. Dodd 	buf[buflen++] = rxc;
3275ce99e877SMatthew N. Dodd 	if (buflen < 5)
32762657f6e9SJung-uk Kim 		return (0);
3277ce99e877SMatthew N. Dodd 
3278ce99e877SMatthew N. Dodd 	buflen = 0;	/* for next time... */
3279ce99e877SMatthew N. Dodd 
3280ce99e877SMatthew N. Dodd 	x = ((buf[2] & ~GTCO_START) << 6 | (buf[1] & ~GTCO_START));
3281ce99e877SMatthew N. Dodd 	y = 4768 - ((buf[4] & ~GTCO_START) << 6 | (buf[3] & ~GTCO_START));
3282ce99e877SMatthew N. Dodd 
3283ce99e877SMatthew N. Dodd 	x /= 2.5;
3284ce99e877SMatthew N. Dodd 	y /= 2.5;
3285ce99e877SMatthew N. Dodd 
3286ce99e877SMatthew N. Dodd 	act->flags = 0;
3287ce99e877SMatthew N. Dodd 	act->obutton = act->button;
3288ce99e877SMatthew N. Dodd 	act->dx = act->dy = act->dz = 0;
3289ce99e877SMatthew N. Dodd 
3290ce99e877SMatthew N. Dodd 	if ((buf[0] & 0x40) == 0) /* pen went out of reach */
3291ce99e877SMatthew N. Dodd 		status = S_IDLE;
3292ce99e877SMatthew N. Dodd 	else if (status == S_IDLE) { /* pen is newly near the tablet */
3293ce99e877SMatthew N. Dodd 		act->flags |= MOUSE_POSCHANGED;	/* force update */
3294ce99e877SMatthew N. Dodd 		status = S_PROXY;
3295ce99e877SMatthew N. Dodd 		x_prev = x;
3296ce99e877SMatthew N. Dodd 		y_prev = y;
3297ce99e877SMatthew N. Dodd 	}
3298ce99e877SMatthew N. Dodd 
3299ce99e877SMatthew N. Dodd 	act->dx = x - x_prev;
3300ce99e877SMatthew N. Dodd 	act->dy = y - y_prev;
3301ce99e877SMatthew N. Dodd 	if (act->dx || act->dy)
3302ce99e877SMatthew N. Dodd 		act->flags |= MOUSE_POSCHANGED;
3303ce99e877SMatthew N. Dodd 	x_prev = x;
3304ce99e877SMatthew N. Dodd 	y_prev = y;
3305ce99e877SMatthew N. Dodd 
3306ce99e877SMatthew N. Dodd 	/* possibly record button change */
3307ce99e877SMatthew N. Dodd 	if (b_prev != 0 && b_prev != buf[0]) {
3308ce99e877SMatthew N. Dodd 		act->button = 0;
33092657f6e9SJung-uk Kim 		if (buf[0] & 0x04) {
33102657f6e9SJung-uk Kim 			/* tip pressed/yellow */
3311ce99e877SMatthew N. Dodd 			act->button |= MOUSE_BUTTON1DOWN;
33122657f6e9SJung-uk Kim 		}
33132657f6e9SJung-uk Kim 		if (buf[0] & 0x08) {
33142657f6e9SJung-uk Kim 			/* grey/white */
3315ce99e877SMatthew N. Dodd 			act->button |= MOUSE_BUTTON2DOWN;
33162657f6e9SJung-uk Kim 		}
33172657f6e9SJung-uk Kim 		if (buf[0] & 0x10) {
33182657f6e9SJung-uk Kim 			/* black/green */
3319ce99e877SMatthew N. Dodd 			act->button |= MOUSE_BUTTON3DOWN;
33202657f6e9SJung-uk Kim 		}
33212657f6e9SJung-uk Kim 		if (buf[0] & 0x20) {
33222657f6e9SJung-uk Kim 			/* tip+grey/blue */
3323ce99e877SMatthew N. Dodd 			act->button |= MOUSE_BUTTON4DOWN;
33242657f6e9SJung-uk Kim 		}
3325ce99e877SMatthew N. Dodd 		act->flags |= MOUSE_BUTTONSCHANGED;
3326ce99e877SMatthew N. Dodd 	}
3327ce99e877SMatthew N. Dodd 	b_prev = buf[0];
33282657f6e9SJung-uk Kim 	return (act->flags);
3329ce99e877SMatthew N. Dodd }
3330ce99e877SMatthew N. Dodd 
333167978692SAmancio Hasty static void
33322657f6e9SJung-uk Kim mremote_serversetup(void)
333367978692SAmancio Hasty {
333467978692SAmancio Hasty     struct sockaddr_un ad;
333567978692SAmancio Hasty 
333667978692SAmancio Hasty     /* Open a UNIX domain stream socket to listen for mouse remote clients */
333767978692SAmancio Hasty     unlink(_PATH_MOUSEREMOTE);
333867978692SAmancio Hasty 
333967978692SAmancio Hasty     if ((rodent.mremsfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
334067978692SAmancio Hasty 	logerrx(1, "unable to create unix domain socket %s",_PATH_MOUSEREMOTE);
334167978692SAmancio Hasty 
334267978692SAmancio Hasty     umask(0111);
334367978692SAmancio Hasty 
334467978692SAmancio Hasty     bzero(&ad, sizeof(ad));
334567978692SAmancio Hasty     ad.sun_family = AF_UNIX;
334667978692SAmancio Hasty     strcpy(ad.sun_path, _PATH_MOUSEREMOTE);
334767978692SAmancio Hasty #ifndef SUN_LEN
334867978692SAmancio Hasty #define SUN_LEN(unp) (((char *)(unp)->sun_path - (char *)(unp)) + \
334967978692SAmancio Hasty 		       strlen((unp)->path))
335067978692SAmancio Hasty #endif
335167978692SAmancio Hasty     if (bind(rodent.mremsfd, (struct sockaddr *) &ad, SUN_LEN(&ad)) < 0)
335267978692SAmancio Hasty 	logerrx(1, "unable to bind unix domain socket %s", _PATH_MOUSEREMOTE);
335367978692SAmancio Hasty 
335467978692SAmancio Hasty     listen(rodent.mremsfd, 1);
335567978692SAmancio Hasty }
335667978692SAmancio Hasty 
335767978692SAmancio Hasty static void
335867978692SAmancio Hasty mremote_clientchg(int add)
335967978692SAmancio Hasty {
336067978692SAmancio Hasty     struct sockaddr_un ad;
33612657f6e9SJung-uk Kim     socklen_t ad_len;
33622657f6e9SJung-uk Kim     int fd;
336367978692SAmancio Hasty 
336467978692SAmancio Hasty     if (rodent.rtype != MOUSE_PROTO_X10MOUSEREM)
336567978692SAmancio Hasty 	return;
336667978692SAmancio Hasty 
336767978692SAmancio Hasty     if (add) {
336867978692SAmancio Hasty 	/*  Accept client connection, if we don't already have one  */
336967978692SAmancio Hasty 	ad_len = sizeof(ad);
337067978692SAmancio Hasty 	fd = accept(rodent.mremsfd, (struct sockaddr *) &ad, &ad_len);
337167978692SAmancio Hasty 	if (fd < 0)
337267978692SAmancio Hasty 	    logwarnx("failed accept on mouse remote socket");
337367978692SAmancio Hasty 
337467978692SAmancio Hasty 	if (rodent.mremcfd < 0) {
337567978692SAmancio Hasty 	    rodent.mremcfd = fd;
337667978692SAmancio Hasty 	    debug("remote client connect...accepted");
337767978692SAmancio Hasty 	}
337867978692SAmancio Hasty 	else {
337967978692SAmancio Hasty 	    close(fd);
338067978692SAmancio Hasty 	    debug("another remote client connect...disconnected");
338167978692SAmancio Hasty 	}
338267978692SAmancio Hasty     }
338367978692SAmancio Hasty     else {
338467978692SAmancio Hasty 	/* Client disconnected */
338567978692SAmancio Hasty 	debug("remote client disconnected");
338667978692SAmancio Hasty 	close(rodent.mremcfd);
338767978692SAmancio Hasty 	rodent.mremcfd = -1;
338867978692SAmancio Hasty     }
338967978692SAmancio Hasty }
3390