moused.c revision 31726
116566Ssos/**
216566Ssos ** Copyright (c) 1995 Michael Smith, All rights reserved.
316566Ssos **
416566Ssos ** Redistribution and use in source and binary forms, with or without
516566Ssos ** modification, are permitted provided that the following conditions
616566Ssos ** are met:
716566Ssos ** 1. Redistributions of source code must retain the above copyright
816566Ssos **    notice, this list of conditions and the following disclaimer as
916566Ssos **    the first lines of this file unmodified.
1016566Ssos ** 2. Redistributions in binary form must reproduce the above copyright
1116566Ssos **    notice, this list of conditions and the following disclaimer in the
1216566Ssos **    documentation and/or other materials provided with the distribution.
1316566Ssos ** 3. All advertising materials mentioning features or use of this software
1416566Ssos **    must display the following acknowledgment:
1516566Ssos **      This product includes software developed by Michael Smith.
1616566Ssos ** 4. The name of the author may not be used to endorse or promote products
1716566Ssos **    derived from this software without specific prior written permission.
1816566Ssos **
1916566Ssos **
2016566Ssos ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY
2116566Ssos ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2216566Ssos ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2316566Ssos ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR
2416566Ssos ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2516566Ssos ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2616566Ssos ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2716566Ssos ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2816566Ssos ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
2916566Ssos ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
3016566Ssos ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3116566Ssos **
3216566Ssos **/
3316566Ssos
3416566Ssos/**
3516566Ssos ** MOUSED.C
3616566Ssos **
3731604Syokota ** Mouse daemon : listens to a serial port, the bus mouse interface, or
3831604Syokota ** the PS/2 mouse port for mouse data stream, interprets data and passes
3931604Syokota ** ioctls off to the console driver.
4016566Ssos **
4116566Ssos ** The mouse interface functions are derived closely from the mouse
4216566Ssos ** handler in the XFree86 X server.  Many thanks to the XFree86 people
4316566Ssos ** for their great work!
4416566Ssos **
4516566Ssos **/
4616566Ssos
4729849Scharnier#ifndef lint
4829849Scharnierstatic const char rcsid[] =
4931726Syokota	"$Id: moused.c,v 1.11 1997/12/07 08:11:16 yokota Exp $";
5029849Scharnier#endif /* not lint */
5129849Scharnier
5229849Scharnier#include <err.h>
5329849Scharnier#include <errno.h>
5429849Scharnier#include <fcntl.h>
5529849Scharnier#include <limits.h>
5616566Ssos#include <stdio.h>
5716566Ssos#include <stdlib.h>
5831604Syokota#include <stdarg.h>
5916566Ssos#include <string.h>
6031604Syokota#include <ctype.h>
6131604Syokota#include <signal.h>
6231604Syokota#include <setjmp.h>
6316566Ssos#include <termios.h>
6431604Syokota#include <syslog.h>
6531604Syokota
6616566Ssos#include <machine/console.h>
6731604Syokota#include <machine/mouse.h>
6831604Syokota
6921885Ssos#include <sys/types.h>
7021885Ssos#include <sys/time.h>
7121885Ssos#include <unistd.h>
7216566Ssos
7331604Syokota#define MAX_CLICKTHRESHOLD	2000	/* 2 seconds */
7431604Syokota
7531604Syokota#define TRUE		1
7631604Syokota#define FALSE		0
7731604Syokota
7831604Syokota#define MOUSE_XAXIS	(-1)
7931604Syokota#define MOUSE_YAXIS	(-2)
8031604Syokota
8131604Syokota#define	ChordMiddle	0x0001
8231604Syokota#define Emulate3Button	0x0002
8331604Syokota#define ClearDTR	0x0004
8431604Syokota#define ClearRTS	0x0008
8531604Syokota#define NoPnP		0x0010
8631604Syokota
8731604Syokota#define ID_NONE		0
8831604Syokota#define ID_PORT		1
8931604Syokota#define ID_IF		2
9031604Syokota#define ID_TYPE 	4
9131604Syokota#define ID_MODEL	8
9231604Syokota#define ID_ALL		(ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
9331604Syokota
9416566Ssos#define debug(fmt,args...) \
9529849Scharnier	if (debug&&nodaemon) warnx(fmt, ##args)
9616566Ssos
9731604Syokota#define logerr(e, fmt, args...) {				\
9831604Syokota	if (background) {					\
9931604Syokota	    syslog(LOG_DAEMON | LOG_ERR, fmt ": %m", ##args);	\
10031604Syokota	    exit(e);						\
10131604Syokota	} else							\
10231604Syokota	    err(e, fmt, ##args);				\
10331604Syokota}
10431604Syokota
10531604Syokota#define logerrx(e, fmt, args...) {				\
10631604Syokota	if (background) {					\
10731604Syokota	    syslog(LOG_DAEMON | LOG_ERR, fmt, ##args);		\
10831604Syokota	    exit(e);						\
10931604Syokota	} else							\
11031604Syokota	    errx(e, fmt, ##args);				\
11131604Syokota}
11231604Syokota
11331604Syokota#define logwarn(fmt, args...) {					\
11431604Syokota	if (background)						\
11531604Syokota	    syslog(LOG_DAEMON | LOG_WARNING, fmt ": %m", ##args); \
11631604Syokota	else							\
11731604Syokota	    warn(fmt, ##args);					\
11831604Syokota}
11931604Syokota
12031604Syokota#define logwarnx(fmt, args...) {				\
12131604Syokota	if (background)						\
12231604Syokota	    syslog(LOG_DAEMON | LOG_WARNING, fmt, ##args);	\
12331604Syokota	else							\
12431604Syokota	    warnx(fmt, ##args);					\
12531604Syokota}
12631604Syokota
12731604Syokota/* structures */
12831604Syokota
12931604Syokota/* symbol table entry */
13031604Syokotatypedef struct {
13131604Syokota    char *name;
13231604Syokota    int val;
13331604Syokota    int val2;
13431604Syokota} symtab_t;
13531604Syokota
13631604Syokota/* serial PnP ID string */
13731604Syokotatypedef struct {
13831604Syokota    int revision;	/* PnP revision, 100 for 1.00 */
13931604Syokota    char *eisaid;	/* EISA ID including mfr ID and product ID */
14031604Syokota    char *serial;	/* serial No, optional */
14131604Syokota    char *class;	/* device class, optional */
14231604Syokota    char *compat;	/* list of compatible drivers, optional */
14331604Syokota    char *description;	/* product description, optional */
14431604Syokota    int neisaid;	/* length of the above fields... */
14531604Syokota    int nserial;
14631604Syokota    int nclass;
14731604Syokota    int ncompat;
14831604Syokota    int ndescription;
14931604Syokota} pnpid_t;
15031604Syokota
15131604Syokota/* global variables */
15231604Syokota
15316566Ssosint	debug = 0;
15431604Syokotaint	nodaemon = FALSE;
15531604Syokotaint	background = FALSE;
15631604Syokotaint	identify = ID_NONE;
15731604Syokotaint	extioctl = FALSE;
15816566Ssos
15931604Syokota/* local variables */
16016566Ssos
16131604Syokota/* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
16231604Syokotastatic symtab_t rifs[] = {
16331604Syokota    { "serial",		MOUSE_IF_SERIAL },
16431604Syokota    { "bus",		MOUSE_IF_BUS },
16531604Syokota    { "inport",		MOUSE_IF_INPORT },
16631604Syokota    { "ps/2",		MOUSE_IF_PS2 },
16731604Syokota    { "sysmouse",	MOUSE_IF_SYSMOUSE },
16831604Syokota    { NULL,		MOUSE_IF_UNKNOWN },
16931604Syokota};
17016566Ssos
17131604Syokota/* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */
17231604Syokotastatic char *rnames[] = {
17316566Ssos    "microsoft",
17416566Ssos    "mousesystems",
17531604Syokota    "logitech",
17616566Ssos    "mmseries",
17731604Syokota    "mouseman",
17816566Ssos    "busmouse",
17931604Syokota    "inportmouse",
18016566Ssos    "ps/2",
18118222Speter    "mmhitab",
18231604Syokota    "glidepoint",
18331604Syokota    "intellimouse",
18431604Syokota    "thinkingmouse",
18531604Syokota    "sysmouse",
18631604Syokota#if notyet
18731604Syokota    "mariqua",
18831604Syokota#endif
18916566Ssos    NULL
19016566Ssos};
19116566Ssos
19231604Syokota/* models */
19331604Syokotastatic symtab_t	rmodels[] = {
19431604Syokota    { "NetScroll",	MOUSE_MODEL_NETSCROLL },
19531604Syokota    { "NetMouse",	MOUSE_MODEL_NET },
19631604Syokota    { "GlidePoint",	MOUSE_MODEL_GLIDEPOINT },
19731604Syokota    { "ThinkingMouse",	MOUSE_MODEL_THINK },
19831604Syokota    { "IntelliMouse",	MOUSE_MODEL_INTELLI },
19931604Syokota    { "EasyScroll",	MOUSE_MODEL_EASYSCROLL },
20031604Syokota    { "MouseMan+",	MOUSE_MODEL_MOUSEMANPLUS },
20131604Syokota    { "generic",	MOUSE_MODEL_GENERIC },
20231604Syokota    { NULL, 		MOUSE_MODEL_UNKNOWN },
20331604Syokota};
20431604Syokota
20531604Syokota/* PnP EISA/product IDs */
20631604Syokotastatic symtab_t pnpprod[] = {
20731604Syokota    /* Kensignton ThinkingMouse */
20831604Syokota    { "KML0001",	MOUSE_PROTO_THINK,	MOUSE_MODEL_THINK },
20931604Syokota    /* MS IntelliMouse */
21031604Syokota    { "MSH0001",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
21131604Syokota    /* MS IntelliMouse TrackBall */
21231604Syokota    { "MSH0004",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_INTELLI },
21331604Syokota    /* Genius EZScroll */
21431604Syokota    { "KYEEZ00",	MOUSE_PROTO_MS,		MOUSE_MODEL_EASYSCROLL },
21531604Syokota    /* Genius NetMouse */
21631604Syokota    { "KYE0003",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_NET },
21731604Syokota    /* Logitech MouseMan+ */
21831604Syokota    { "LGI8050",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
21931604Syokota    /* Logitech FirstMouse+ */
22031604Syokota    { "LGI8051",	MOUSE_PROTO_INTELLI,	MOUSE_MODEL_MOUSEMANPLUS },
22131604Syokota
22231604Syokota    /* MS bus */
22331604Syokota    { "PNP0F00",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
22431604Syokota    /* MS serial */
22531604Syokota    { "PNP0F01",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
22631604Syokota    /* MS InPort */
22731604Syokota    { "PNP0F02",	MOUSE_PROTO_INPORT,	MOUSE_MODEL_GENERIC },
22831604Syokota    /* MS PS/2 */
22931604Syokota    { "PNP0F03",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
23031604Syokota    /*
23131604Syokota     * EzScroll returns PNP0F04 in the compatible device field; but it
23231604Syokota     * doesn't look compatible... XXX
23331604Syokota     */
23431604Syokota    /* MouseSystems */
23531604Syokota    { "PNP0F04",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
23631604Syokota    /* MouseSystems */
23731604Syokota    { "PNP0F05",	MOUSE_PROTO_MSC,	MOUSE_MODEL_GENERIC },
23831604Syokota#if notyet
23931604Syokota    /* Genius Mouse */
24031604Syokota    { "PNP0F06",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
24131604Syokota    /* Genius Mouse */
24231604Syokota    { "PNP0F07",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
24331604Syokota#endif
24431604Syokota    /* Logitech serial */
24531604Syokota    { "PNP0F08",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
24631604Syokota    /* MS BallPoint serial */
24731604Syokota    { "PNP0F09",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
24831604Syokota    /* MS PnP serial */
24931604Syokota    { "PNP0F0A",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
25031604Syokota    /* MS PnP BallPoint serial */
25131604Syokota    { "PNP0F0B",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
25231604Syokota    /* MS serial comatible */
25331604Syokota    { "PNP0F0C",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
25431604Syokota    /* MS InPort comatible */
25531604Syokota    { "PNP0F0D",	MOUSE_PROTO_INPORT,	MOUSE_MODEL_GENERIC },
25631604Syokota    /* MS PS/2 comatible */
25731604Syokota    { "PNP0F0E",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
25831604Syokota    /* MS BallPoint comatible */
25931604Syokota    { "PNP0F0F",	MOUSE_PROTO_MS,		MOUSE_MODEL_GENERIC },
26031604Syokota#if notyet
26131604Syokota    /* TI QuickPort */
26231604Syokota    { "PNP0F10",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
26331604Syokota#endif
26431604Syokota    /* MS bus comatible */
26531604Syokota    { "PNP0F11",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
26631604Syokota    /* Logitech PS/2 */
26731604Syokota    { "PNP0F12",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
26831604Syokota    /* PS/2 */
26931604Syokota    { "PNP0F13",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
27031604Syokota#if notyet
27131604Syokota    /* MS Kids Mouse */
27231604Syokota    { "PNP0F14",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
27331604Syokota#endif
27431604Syokota    /* Logitech bus */
27531604Syokota    { "PNP0F15",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
27631604Syokota#if notyet
27731604Syokota    /* Logitech SWIFT */
27831604Syokota    { "PNP0F16",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
27931604Syokota#endif
28031604Syokota    /* Logitech serial compat */
28131604Syokota    { "PNP0F17",	MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
28231604Syokota    /* Logitech bus compatible */
28331604Syokota    { "PNP0F18",	MOUSE_PROTO_BUS,	MOUSE_MODEL_GENERIC },
28431604Syokota    /* Logitech PS/2 compatible */
28531604Syokota    { "PNP0F19",	MOUSE_PROTO_PS2,	MOUSE_MODEL_GENERIC },
28631604Syokota#if notyet
28731604Syokota    /* Logitech SWIFT compatible */
28831604Syokota    { "PNP0F1A",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
28931604Syokota    /* HP Omnibook */
29031604Syokota    { "PNP0F1B",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
29131604Syokota    /* Compaq LTE TrackBall PS/2 */
29231604Syokota    { "PNP0F1C",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
29331604Syokota    /* Compaq LTE TrackBall serial */
29431604Syokota    { "PNP0F1D",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
29531604Syokota    /* MS Kidts Trackball */
29631604Syokota    { "PNP0F1E",	MOUSE_PROTO_???,	MOUSE_MODEL_GENERIC },
29731604Syokota#endif
29831604Syokota
29931604Syokota    { NULL,		MOUSE_PROTO_UNKNOWN,	MOUSE_MODEL_GENERIC },
30031604Syokota};
30131604Syokota
30231604Syokota/* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */
30331604Syokotastatic unsigned short rodentcflags[] =
30416566Ssos{
30516566Ssos    (CS7	           | CREAD | CLOCAL | HUPCL ),	/* MicroSoft */
30616566Ssos    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* MouseSystems */
30731604Syokota    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* Logitech */
30816566Ssos    (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ),	/* MMSeries */
30916566Ssos    (CS7		   | CREAD | CLOCAL | HUPCL ),	/* MouseMan */
31031604Syokota    0,							/* Bus */
31131604Syokota    0,							/* InPort */
31218222Speter    0,							/* PS/2 */
31331604Syokota    (CS8		   | CREAD | CLOCAL | HUPCL ),	/* MM HitTablet */
31431604Syokota    (CS7	           | CREAD | CLOCAL | HUPCL ),	/* GlidePoint */
31531604Syokota    (CS7                   | CREAD | CLOCAL | HUPCL ),	/* IntelliMouse */
31631604Syokota    (CS7                   | CREAD | CLOCAL | HUPCL ),	/* Thinking Mouse */
31731726Syokota    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* sysmouse */
31831604Syokota#if notyet
31931604Syokota    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* Mariqua */
32031604Syokota#endif
32116566Ssos};
32216566Ssos
32331604Syokotastatic struct rodentparam {
32431604Syokota    int flags;
32531604Syokota    char *portname;		/* /dev/XXX */
32631604Syokota    int rtype;			/* MOUSE_PROTO_XXX */
32731604Syokota    int level;			/* operation level: 0 or greater */
32831604Syokota    int baudrate;
32931604Syokota    int rate;			/* report rate */
33031604Syokota    int resolution;		/* MOUSE_RES_XXX or a positive number */
33131604Syokota    int zmap;			/* MOUSE_{X|Y}AXIS or a button number */
33231604Syokota    int mfd;			/* mouse file descriptor */
33331604Syokota    int cfd;			/* /dev/consolectl file descriptor */
33431604Syokota    long clickthreshold;	/* double click speed in msec */
33531604Syokota    mousehw_t hw;		/* mouse device hardware information */
33631604Syokota    mousemode_t mode;		/* protocol information */
33731604Syokota} rodent = {
33831604Syokota    flags : 0,
33931604Syokota    portname : NULL,
34031604Syokota    rtype : MOUSE_PROTO_UNKNOWN,
34131604Syokota    level : -1,
34231604Syokota    baudrate : 1200,
34331604Syokota    rate : 0,
34431604Syokota    resolution : MOUSE_RES_UNKNOWN,
34531604Syokota    zmap: 0,
34631604Syokota    mfd : -1,
34731604Syokota    cfd : -1,
34831604Syokota    clickthreshold : 500,	/* 0.5 sec */
34931604Syokota};
35016566Ssos
35131604Syokota/* button status */
35231604Syokotastatic struct {
35331604Syokota    int count;		/* 0: up, 1: single click, 2: double click,... */
35431604Syokota    struct timeval tv;	/* timestamp on the last `up' event */
35531604Syokota} buttonstate[MOUSE_MAXBUTTON];
35616566Ssos
35731604Syokotastatic jmp_buf env;
35816566Ssos
35931604Syokota/* function prototypes */
36016566Ssos
36131604Syokotastatic void	moused(void);
36231604Syokotastatic void	hup(int sig);
36331604Syokotastatic void	usage(void);
36431604Syokota
36531604Syokotastatic int	r_identify(void);
36631604Syokotastatic char	*r_if(int type);
36731604Syokotastatic char	*r_name(int type);
36831604Syokotastatic char	*r_model(int model);
36931604Syokotastatic void	r_init(void);
37031604Syokotastatic int	r_protocol(u_char b, mousestatus_t *act);
37131604Syokotastatic int	r_installmap(char *arg);
37231604Syokotastatic void	r_map(mousestatus_t *act1, mousestatus_t *act2);
37331604Syokotastatic void	r_click(mousestatus_t *act);
37431604Syokotastatic void	setmousespeed(int old, int new, unsigned cflag);
37531604Syokota
37631604Syokotastatic int	pnpgets(char *buf);
37731604Syokotastatic int	pnpparse(pnpid_t *id, char *buf, int len);
37831604Syokotastatic symtab_t	*pnpproto(pnpid_t *id);
37931604Syokota
38031604Syokotastatic symtab_t	*gettoken(symtab_t *tab, char *s, int len);
38131604Syokotastatic char	*gettokenname(symtab_t *tab, int val);
38231604Syokota
38316566Ssosvoid
38416566Ssosmain(int argc, char *argv[])
38516566Ssos{
38631604Syokota    int c;
38731604Syokota    int	i;
38816566Ssos
38931604Syokota    while((c = getopt(argc,argv,"3C:DF:PRS:cdfhi:l:m:p:r:st:z:")) != -1)
39031604Syokota	switch(c) {
39131604Syokota
39231604Syokota	case '3':
39331604Syokota	    rodent.flags |= Emulate3Button;
39431604Syokota	    break;
39531604Syokota
39616566Ssos	case 'c':
39716566Ssos	    rodent.flags |= ChordMiddle;
39816566Ssos	    break;
39916566Ssos
40016566Ssos	case 'd':
40131604Syokota	    ++debug;
40216566Ssos	    break;
40316566Ssos
40416566Ssos	case 'f':
40531604Syokota	    nodaemon = TRUE;
40616566Ssos	    break;
40716566Ssos
40831604Syokota	case 'i':
40931604Syokota	    if (strcmp(optarg, "all") == 0)
41031604Syokota	        identify = ID_ALL;
41131604Syokota	    else if (strcmp(optarg, "port") == 0)
41231604Syokota	        identify = ID_PORT;
41331604Syokota	    else if (strcmp(optarg, "if") == 0)
41431604Syokota	        identify = ID_IF;
41531604Syokota	    else if (strcmp(optarg, "type") == 0)
41631604Syokota	        identify = ID_TYPE;
41731604Syokota	    else if (strcmp(optarg, "model") == 0)
41831604Syokota	        identify = ID_MODEL;
41931604Syokota	    else {
42031604Syokota	        warnx("invalid argument `%s'", optarg);
42131604Syokota	        usage();
42231604Syokota	    }
42331604Syokota	    nodaemon = TRUE;
42431604Syokota	    break;
42531604Syokota
42631604Syokota	case 'l':
42731604Syokota	    rodent.level = atoi(optarg);
42831604Syokota	    if ((rodent.level < 0) || (rodent.level > 4)) {
42931604Syokota	        warnx("invalid argument `%s'", optarg);
43031604Syokota	        usage();
43131604Syokota	    }
43231604Syokota	    break;
43331604Syokota
43431604Syokota	case 'm':
43531604Syokota	    if (!r_installmap(optarg)) {
43631604Syokota	        warnx("invalid argument `%s'", optarg);
43731604Syokota	        usage();
43831604Syokota	    }
43931604Syokota	    break;
44031604Syokota
44116566Ssos	case 'p':
44216566Ssos	    rodent.portname = optarg;
44316566Ssos	    break;
44416566Ssos
44524377Speter	case 'r':
44631604Syokota	    if (strcmp(optarg, "high") == 0)
44731604Syokota	        rodent.resolution = MOUSE_RES_HIGH;
44831604Syokota	    else if (strcmp(optarg, "medium-high") == 0)
44931604Syokota	        rodent.resolution = MOUSE_RES_HIGH;
45031604Syokota	    else if (strcmp(optarg, "medium-low") == 0)
45131604Syokota	        rodent.resolution = MOUSE_RES_MEDIUMLOW;
45231604Syokota	    else if (strcmp(optarg, "low") == 0)
45331604Syokota	        rodent.resolution = MOUSE_RES_LOW;
45431604Syokota	    else if (strcmp(optarg, "default") == 0)
45531604Syokota	        rodent.resolution = MOUSE_RES_DEFAULT;
45631604Syokota	    else {
45731604Syokota	        rodent.resolution = atoi(optarg);
45831604Syokota	        if (rodent.resolution <= 0) {
45931604Syokota	            warnx("invalid argument `%s'", optarg);
46031604Syokota	            usage();
46131604Syokota	        }
46231604Syokota	    }
46324377Speter	    break;
46424377Speter
46516566Ssos	case 's':
46616566Ssos	    rodent.baudrate = 9600;
46718222Speter	    break;
46816566Ssos
46931604Syokota	case 'z':
47031604Syokota	    if (strcmp(optarg, "x") == 0)
47131604Syokota		rodent.zmap = MOUSE_XAXIS;
47231604Syokota	    else if (strcmp(optarg, "y") == 0)
47331604Syokota		rodent.zmap = MOUSE_YAXIS;
47431604Syokota            else {
47531604Syokota		i = atoi(optarg);
47631604Syokota		/*
47731604Syokota		 * Use button i for negative Z axis movement and
47831604Syokota		 * button (i + 1) for positive Z axis movement.
47931604Syokota		 */
48031604Syokota		if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
48131604Syokota	            warnx("invalid argument `%s'", optarg);
48231604Syokota	            usage();
48331604Syokota		}
48431604Syokota		rodent.zmap = 1 << (i - 1);
48531604Syokota	    }
48618222Speter	    break;
48718222Speter
48831604Syokota	case 'C':
48931604Syokota	    rodent.clickthreshold = atoi(optarg);
49031604Syokota	    if ((rodent.clickthreshold < 0) ||
49131604Syokota	        (rodent.clickthreshold > MAX_CLICKTHRESHOLD)) {
49231604Syokota	        warnx("invalid argument `%s'", optarg);
49331604Syokota	        usage();
49431604Syokota	    }
49531604Syokota	    break;
49631604Syokota
49718222Speter	case 'D':
49831604Syokota	    rodent.flags |= ClearDTR;
49918222Speter	    break;
50018222Speter
50131604Syokota	case 'F':
50231604Syokota	    rodent.rate = atoi(optarg);
50331604Syokota	    if (rodent.rate <= 0) {
50431604Syokota	        warnx("invalid argument `%s'", optarg);
50531604Syokota	        usage();
50631604Syokota	    }
50731604Syokota	    break;
50831604Syokota
50931604Syokota	case 'P':
51031604Syokota	    rodent.flags |= NoPnP;
51131604Syokota	    break;
51231604Syokota
51331604Syokota	case 'R':
51431604Syokota	    rodent.flags |= ClearRTS;
51531604Syokota	    break;
51631604Syokota
51718222Speter	case 'S':
51818222Speter	    rodent.baudrate = atoi(optarg);
51931604Syokota	    if (rodent.baudrate <= 0) {
52031604Syokota	        warnx("invalid argument `%s'", optarg);
52131604Syokota	        usage();
52231604Syokota	    }
52318222Speter	    debug("rodent baudrate %d", rodent.baudrate);
52418222Speter	    break;
52518222Speter
52616566Ssos	case 't':
52716566Ssos	    for (i = 0; rnames[i]; i++)
52831604Syokota		if (!strcmp(optarg,rnames[i])) {
52916566Ssos		    rodent.rtype = i;
53016566Ssos		    break;
53116566Ssos		}
53216566Ssos	    if (rnames[i])
53316566Ssos		break;
53431604Syokota	    warnx("no such mouse type `%s'", optarg);
53516566Ssos	    usage();
53616566Ssos
53716566Ssos	case 'h':
53816566Ssos	case '?':
53916566Ssos	default:
54016566Ssos	    usage();
54116566Ssos	}
54216566Ssos
54331604Syokota    /* the default port name */
54431604Syokota    switch(rodent.rtype) {
54531604Syokota
54631604Syokota    case MOUSE_PROTO_INPORT:
54731604Syokota        /* INPORT and BUS are the same... */
54831604Syokota	rodent.rtype = MOUSE_PROTO_BUS;
54931604Syokota	/* FALL THROUGH */
55031604Syokota    case MOUSE_PROTO_BUS:
55116566Ssos	if (!rodent.portname)
55216566Ssos	    rodent.portname = "/dev/mse0";
55316566Ssos	break;
55431604Syokota
55531604Syokota    case MOUSE_PROTO_PS2:
55616566Ssos	if (!rodent.portname)
55716566Ssos	    rodent.portname = "/dev/psm0";
55816566Ssos	break;
55931604Syokota
56016566Ssos    default:
56116566Ssos	if (rodent.portname)
56216566Ssos	    break;
56329849Scharnier	warnx("no port name specified");
56416566Ssos	usage();
56516566Ssos    }
56616566Ssos
56731604Syokota    for (;;) {
56831604Syokota	if (setjmp(env) == 0) {
56931604Syokota	    signal(SIGHUP, hup);
57031604Syokota            if ((rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK, 0))
57131604Syokota		== -1)
57231604Syokota	        logerr(1, "unable to open %s", rodent.portname);
57331604Syokota            if (r_identify() == MOUSE_PROTO_UNKNOWN) {
57431604Syokota	        logwarnx("cannot determine mouse type on %s", rodent.portname);
57531604Syokota	        close(rodent.mfd);
57631604Syokota	        rodent.mfd = -1;
57731604Syokota            }
57831604Syokota
57931604Syokota	    /* print some information */
58031604Syokota            if (identify != ID_NONE) {
58131604Syokota		if (identify == ID_ALL)
58231604Syokota                    printf("%s %s %s %s\n",
58331604Syokota		        rodent.portname, r_if(rodent.hw.iftype),
58431604Syokota		        r_name(rodent.rtype), r_model(rodent.hw.model));
58531604Syokota		else if (identify & ID_PORT)
58631604Syokota		    printf("%s\n", rodent.portname);
58731604Syokota		else if (identify & ID_IF)
58831604Syokota		    printf("%s\n", r_if(rodent.hw.iftype));
58931604Syokota		else if (identify & ID_TYPE)
59031604Syokota		    printf("%s\n", r_name(rodent.rtype));
59131604Syokota		else if (identify & ID_MODEL)
59231604Syokota		    printf("%s\n", r_model(rodent.hw.model));
59331604Syokota		exit(0);
59431604Syokota	    } else {
59531604Syokota                debug("port: %s  interface: %s  type: %s  model: %s",
59631604Syokota		    rodent.portname, r_if(rodent.hw.iftype),
59731604Syokota		    r_name(rodent.rtype), r_model(rodent.hw.model));
59831604Syokota	    }
59931604Syokota
60031604Syokota	    if (rodent.mfd == -1) {
60131604Syokota	        /*
60231604Syokota	         * We cannot continue because of error.  Exit if the
60331604Syokota		 * program has not become a daemon.  Otherwise, block
60431604Syokota		 * until the the user corrects the problem and issues SIGHUP.
60531604Syokota	         */
60631604Syokota	        if (!background)
60731604Syokota		    exit(1);
60831604Syokota	        sigpause(0);
60931604Syokota	    }
61031604Syokota
61131604Syokota            r_init();			/* call init function */
61231604Syokota	    moused();
61331604Syokota	}
61431604Syokota
61531604Syokota	if (rodent.mfd != -1)
61631604Syokota	    close(rodent.mfd);
61731604Syokota	if (rodent.cfd != -1)
61831604Syokota	    close(rodent.cfd);
61931604Syokota	rodent.mfd = rodent.cfd = -1;
62016566Ssos    }
62131604Syokota    /* NOT REACHED */
62216566Ssos
62331604Syokota    exit(0);
62431604Syokota}
62516566Ssos
62631604Syokotastatic void
62731604Syokotamoused(void)
62831604Syokota{
62931604Syokota    struct mouse_info mouse;
63031604Syokota    mousestatus_t action;		/* original mouse action */
63131604Syokota    mousestatus_t action2;		/* mapped action */
63231604Syokota    fd_set fds;
63331604Syokota    u_char b;
63431604Syokota
63531604Syokota    if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
63631604Syokota	logerr(1, "cannot open /dev/consolectl", 0);
63731604Syokota
63831604Syokota    if (!nodaemon && !background)
63931604Syokota	if (daemon(0, 0)) {
64031604Syokota	    logerr(1, "failed to become a daemon", 0);
64131604Syokota	} else {
64231604Syokota	    background = TRUE;
64316566Ssos	}
64416566Ssos
64531604Syokota    /* clear mouse data */
64631604Syokota    bzero(&action, sizeof(action));
64731604Syokota    bzero(&action2, sizeof(action2));
64831604Syokota    bzero(&buttonstate, sizeof(buttonstate));
64931604Syokota    bzero(&mouse, sizeof(mouse));
65031604Syokota
65131604Syokota    /* choose which ioctl command to use */
65231604Syokota    mouse.operation = MOUSE_MOTION_EVENT;
65331604Syokota    extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0);
65431604Syokota
65531604Syokota    /* process mouse data */
65631604Syokota    for (;;) {
65731604Syokota
65821885Ssos	FD_ZERO(&fds);
65931604Syokota	FD_SET(rodent.mfd, &fds);
66031604Syokota	if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
66131604Syokota	    logwarn("failed to read from mouse", 0);
66231604Syokota
66331604Syokota	read(rodent.mfd, &b, 1);
66431604Syokota	if (r_protocol(b, &action)) {	/* handler detected action */
66531604Syokota	    r_map(&action, &action2);
66631604Syokota	    debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
66731604Syokota		action2.button, action2.dx, action2.dy, action2.dz);
66831604Syokota
66931604Syokota	    if (extioctl) {
67031604Syokota	        r_click(&action2);
67131604Syokota	        if (action2.flags & MOUSE_POSCHANGED) {
67231604Syokota    		    mouse.operation = MOUSE_MOTION_EVENT;
67331604Syokota	            mouse.u.data.buttons = action2.button;
67431604Syokota	            mouse.u.data.x = action2.dx;
67531604Syokota	            mouse.u.data.y = action2.dy;
67631604Syokota	            mouse.u.data.z = action2.dz;
67731604Syokota		    if (debug < 2)
67831604Syokota	                ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
67931604Syokota	        }
68031604Syokota	    } else {
68131604Syokota	        mouse.operation = MOUSE_ACTION;
68231604Syokota	        mouse.u.data.buttons = action2.button;
68331604Syokota	        mouse.u.data.x = action2.dx;
68431604Syokota	        mouse.u.data.y = action2.dy;
68531604Syokota	        mouse.u.data.z = action2.dz;
68631604Syokota		if (debug < 2)
68731604Syokota	            ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
68831604Syokota	    }
68931604Syokota
69031604Syokota            /*
69131604Syokota	     * If the Z axis movement is mapped to a imaginary physical
69231604Syokota	     * button, we need to cook up a corresponding button `up' event
69331604Syokota	     * after sending a button `down' event.
69431604Syokota	     */
69531604Syokota            if ((rodent.zmap > 0) && (action.dz != 0)) {
69631604Syokota		action.obutton = action.button;
69731604Syokota		action.dx = action.dy = action.dz = 0;
69831604Syokota	        r_map(&action, &action2);
69931604Syokota	        debug("activity : buttons 0x%08x  dx %d  dy %d  dz %d",
70031604Syokota		    action2.button, action2.dx, action2.dy, action2.dz);
70131604Syokota
70231604Syokota	        if (extioctl) {
70331604Syokota	            r_click(&action2);
70431604Syokota	        } else {
70531604Syokota	            mouse.operation = MOUSE_ACTION;
70631604Syokota	            mouse.u.data.buttons = action2.button;
70731604Syokota		    mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
70831604Syokota		    if (debug < 2)
70931604Syokota	                ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
71031604Syokota	        }
71131604Syokota	    }
71216566Ssos	}
71316566Ssos    }
71431604Syokota    /* NOT REACHED */
71516566Ssos}
71616566Ssos
71731604Syokotastatic void
71831604Syokotahup(int sig)
71931604Syokota{
72031604Syokota    longjmp(env, 1);
72131604Syokota}
72216566Ssos
72316566Ssos/**
72416566Ssos ** usage
72516566Ssos **
72616566Ssos ** Complain, and free the CPU for more worthy tasks
72716566Ssos **/
72831604Syokotastatic void
72916566Ssosusage(void)
73016566Ssos{
73131604Syokota    fprintf(stderr, "%s\n%s\n%s\n",
73231604Syokota        "usage: moused [-3DRcdfs] [-F rate] [-r resolution] [-S baudrate] [-C threshold]",
73331604Syokota        "              [-m N=M] [-z N] [-t <mousetype>] -p <port>",
73431604Syokota	"       moused [-d] -i -p <port>");
73516566Ssos    exit(1);
73616566Ssos}
73716566Ssos
73816566Ssos/**
73916566Ssos ** Mouse interface code, courtesy of XFree86 3.1.2.
74016566Ssos **
74116566Ssos ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
74216566Ssos ** to clean, reformat and rationalise naming, it's quite possible that
74316566Ssos ** some things in here have been broken.
74416566Ssos **
74516566Ssos ** I hope not 8)
74616566Ssos **
74716566Ssos ** The following code is derived from a module marked :
74816566Ssos **/
74916566Ssos
75016566Ssos/* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
75116566Ssos/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
75216566Ssos 17:03:40 dawes Exp $ */
75316566Ssos/*
75416566Ssos *
75516566Ssos * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
75616566Ssos * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
75716566Ssos *
75816566Ssos * Permission to use, copy, modify, distribute, and sell this software and its
75916566Ssos * documentation for any purpose is hereby granted without fee, provided that
76016566Ssos * the above copyright notice appear in all copies and that both that
76116566Ssos * copyright notice and this permission notice appear in supporting
76216566Ssos * documentation, and that the names of Thomas Roell and David Dawes not be
76316566Ssos * used in advertising or publicity pertaining to distribution of the
76416566Ssos * software without specific, written prior permission.  Thomas Roell
76516566Ssos * and David Dawes makes no representations about the suitability of this
76616566Ssos * software for any purpose.  It is provided "as is" without express or
76716566Ssos * implied warranty.
76816566Ssos *
76916566Ssos * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
77016566Ssos * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
77116566Ssos * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
77216566Ssos * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
77316566Ssos * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
77416566Ssos * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
77516566Ssos * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
77616566Ssos *
77716566Ssos */
77816566Ssos
77931604Syokota/**
78031604Syokota ** GlidePoint support from XFree86 3.2.
78131604Syokota ** Derived from the module:
78231604Syokota **/
78316566Ssos
78431604Syokota/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
78531604Syokota/* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
78631604Syokota
78731604Syokota/* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
78831604Syokotastatic unsigned char proto[][7] = {
78931604Syokota    /*  hd_mask hd_id   dp_mask dp_id   bytes b4_mask b4_id */
79031604Syokota    { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* MicroSoft */
79131604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* MouseSystems */
79231604Syokota    {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* Logitech */
79331604Syokota    {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MMSeries */
79431604Syokota    { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x23,  0x00 }, /* MouseMan */
79531604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* Bus */
79631604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* InPort */
79731604Syokota    {	0xc0,	0x00,	0x00,	0x00,	3,    0x00,  0xff }, /* PS/2 mouse */
79831604Syokota    {	0xe0,	0x80,	0x80,	0x00,	3,    0x00,  0xff }, /* MM HitTablet */
79931604Syokota    { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* GlidePoint */
80031604Syokota    { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x3f,  0x00 }, /* IntelliMouse */
80131604Syokota    { 	0x40,	0x40,	0x40,	0x00,	3,   ~0x33,  0x00 }, /* ThinkingMouse */
80231604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,    0x00,  0xff }, /* sysmouse */
80331604Syokota#if notyet
80431604Syokota    {	0xf8,	0x80,	0x00,	0x00,	5,   ~0x2f,  0x10 }, /* Mariqua */
80531604Syokota#endif
80631604Syokota};
80731604Syokotastatic unsigned char cur_proto[7];
80831604Syokota
80931604Syokotastatic int
81031604Syokotar_identify(void)
81131604Syokota{
81231604Syokota    char pnpbuf[256];	/* PnP identifier string may be up to 256 bytes long */
81331604Syokota    pnpid_t pnpid;
81431604Syokota    symtab_t *t;
81531604Syokota    int level;
81631604Syokota    int len;
81731604Syokota
81831604Syokota    /* set the driver operation level, if applicable */
81931604Syokota    if (rodent.level < 0)
82031604Syokota	rodent.level = 1;
82131604Syokota    ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level);
82231604Syokota    rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0;
82331604Syokota
82431604Syokota    /*
82531604Syokota     * Interrogate the driver and get some intelligence on the device...
82631604Syokota     * The following ioctl functions are not always supported by device
82731604Syokota     * drivers.  When the driver doesn't support them, we just trust the
82831604Syokota     * user to supply valid information.
82931604Syokota     */
83031604Syokota    rodent.hw.iftype = MOUSE_IF_UNKNOWN;
83131604Syokota    rodent.hw.model = MOUSE_MODEL_GENERIC;
83231604Syokota    ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw);
83331604Syokota
83431604Syokota    if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
83531604Syokota        bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
83631604Syokota    rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
83731604Syokota    rodent.mode.rate = -1;
83831604Syokota    rodent.mode.resolution = MOUSE_RES_UNKNOWN;
83931604Syokota    rodent.mode.accelfactor = 0;
84031604Syokota    rodent.mode.level = 0;
84131604Syokota    if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) {
84231604Syokota        if ((rodent.mode.protocol == MOUSE_PROTO_UNKNOWN)
84331604Syokota	    || (rodent.mode.protocol >= sizeof(proto)/sizeof(proto[0]))) {
84431604Syokota	    logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol);
84531604Syokota	    return MOUSE_PROTO_UNKNOWN;
84631604Syokota        } else {
84731604Syokota	    /* INPORT and BUS are the same... */
84831604Syokota	    if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
84931604Syokota	        rodent.mode.protocol = MOUSE_PROTO_BUS;
85031604Syokota	    if (rodent.mode.protocol != rodent.rtype) {
85131604Syokota		/* Hmm, the driver doesn't agree with the user... */
85231604Syokota                if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
85331604Syokota	            logwarnx("mouse type mismatch (%s != %s), %s is assumed",
85431604Syokota		        r_name(rodent.mode.protocol), r_name(rodent.rtype),
85531604Syokota		        r_name(rodent.mode.protocol));
85631604Syokota	        rodent.rtype = rodent.mode.protocol;
85731604Syokota                bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
85831604Syokota	    }
85931604Syokota        }
86031604Syokota        cur_proto[4] = rodent.mode.packetsize;
86131604Syokota        cur_proto[0] = rodent.mode.syncmask[0];	/* header byte bit mask */
86231604Syokota        cur_proto[1] = rodent.mode.syncmask[1];	/* header bit pattern */
86331604Syokota    }
86431604Syokota
86531604Syokota    /* maybe this is an PnP mouse... */
86631604Syokota    if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) {
86731604Syokota
86831604Syokota        if (rodent.flags & NoPnP)
86931604Syokota            return rodent.rtype;
87031604Syokota	if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len))
87131604Syokota            return rodent.rtype;
87231604Syokota
87331604Syokota        debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
87431604Syokota	    pnpid.neisaid, pnpid.neisaid, pnpid.eisaid,
87531604Syokota	    pnpid.ncompat, pnpid.ncompat, pnpid.compat,
87631604Syokota	    pnpid.ndescription, pnpid.ndescription, pnpid.description);
87731604Syokota
87831604Syokota	/* we have a valid PnP serial device ID */
87931604Syokota        rodent.hw.iftype = MOUSE_IF_SERIAL;
88031604Syokota	t = pnpproto(&pnpid);
88131604Syokota	if (t != NULL) {
88231604Syokota            rodent.mode.protocol = t->val;
88331604Syokota            rodent.hw.model = t->val2;
88431604Syokota	} else {
88531604Syokota            rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
88631604Syokota	}
88731604Syokota	if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
88831604Syokota	    rodent.mode.protocol = MOUSE_PROTO_BUS;
88931604Syokota
89031604Syokota        /* make final adjustment */
89131604Syokota	if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) {
89231604Syokota	    if (rodent.mode.protocol != rodent.rtype) {
89331604Syokota		/* Hmm, the device doesn't agree with the user... */
89431604Syokota                if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
89531604Syokota	            logwarnx("mouse type mismatch (%s != %s), %s is assumed",
89631604Syokota		        r_name(rodent.mode.protocol), r_name(rodent.rtype),
89731604Syokota		        r_name(rodent.mode.protocol));
89831604Syokota	        rodent.rtype = rodent.mode.protocol;
89931604Syokota                bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
90031604Syokota	    }
90131604Syokota	}
90231604Syokota    }
90331604Syokota
90431604Syokota    debug("proto params: %02x %02x %02x %02x %d %02x %02x",
90531604Syokota	cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3],
90631604Syokota	cur_proto[4], cur_proto[5], cur_proto[6]);
90731604Syokota
90831604Syokota    return rodent.rtype;
90931604Syokota}
91031604Syokota
91131604Syokotastatic char *
91231604Syokotar_if(int iftype)
91331604Syokota{
91431604Syokota    char *s;
91531604Syokota
91631604Syokota    s = gettokenname(rifs, iftype);
91731604Syokota    return (s == NULL) ? "unknown" : s;
91831604Syokota}
91931604Syokota
92031604Syokotastatic char *
92131604Syokotar_name(int type)
92231604Syokota{
92331604Syokota    return ((type == MOUSE_PROTO_UNKNOWN)
92431604Syokota	|| (type > sizeof(rnames)/sizeof(rnames[0]) - 1))
92531604Syokota	? "unknown" : rnames[type];
92631604Syokota}
92731604Syokota
92831604Syokotastatic char *
92931604Syokotar_model(int model)
93031604Syokota{
93131604Syokota    char *s;
93231604Syokota
93331604Syokota    s = gettokenname(rmodels, model);
93431604Syokota    return (s == NULL) ? "unknown" : s;
93531604Syokota}
93631604Syokota
93731604Syokotastatic void
93816566Ssosr_init(void)
93916566Ssos{
94031604Syokota    fd_set fds;
94131604Syokota    char *s;
94231604Syokota    char c;
94331604Syokota    int i;
94431604Syokota
94516566Ssos    /**
94616566Ssos     ** This comment is a little out of context here, but it contains
94716566Ssos     ** some useful information...
94816566Ssos     ********************************************************************
94916566Ssos     **
95016566Ssos     ** The following lines take care of the Logitech MouseMan protocols.
95116566Ssos     **
95216566Ssos     ** NOTE: There are different versions of both MouseMan and TrackMan!
95316566Ssos     **       Hence I add another protocol P_LOGIMAN, which the user can
95416566Ssos     **       specify as MouseMan in his XF86Config file. This entry was
95516566Ssos     **       formerly handled as a special case of P_MS. However, people
95616566Ssos     **       who don't have the middle button problem, can still specify
95716566Ssos     **       Microsoft and use P_MS.
95816566Ssos     **
95916566Ssos     ** By default, these mice should use a 3 byte Microsoft protocol
96016566Ssos     ** plus a 4th byte for the middle button. However, the mouse might
96116566Ssos     ** have switched to a different protocol before we use it, so I send
96216566Ssos     ** the proper sequence just in case.
96316566Ssos     **
96416566Ssos     ** NOTE: - all commands to (at least the European) MouseMan have to
96516566Ssos     **         be sent at 1200 Baud.
96616566Ssos     **       - each command starts with a '*'.
96716566Ssos     **       - whenever the MouseMan receives a '*', it will switch back
96816566Ssos     **	 to 1200 Baud. Hence I have to select the desired protocol
96916566Ssos     **	 first, then select the baud rate.
97016566Ssos     **
97116566Ssos     ** The protocols supported by the (European) MouseMan are:
97216566Ssos     **   -  5 byte packed binary protocol, as with the Mouse Systems
97316566Ssos     **      mouse. Selected by sequence "*U".
97416566Ssos     **   -  2 button 3 byte MicroSoft compatible protocol. Selected
97516566Ssos     **      by sequence "*V".
97616566Ssos     **   -  3 button 3+1 byte MicroSoft compatible protocol (default).
97716566Ssos     **      Selected by sequence "*X".
97816566Ssos     **
97916566Ssos     ** The following baud rates are supported:
98016566Ssos     **   -  1200 Baud (default). Selected by sequence "*n".
98116566Ssos     **   -  9600 Baud. Selected by sequence "*q".
98216566Ssos     **
98316566Ssos     ** Selecting a sample rate is no longer supported with the MouseMan!
98416566Ssos     ** Some additional lines in xf86Config.c take care of ill configured
98516566Ssos     ** baud rates and sample rates. (The user will get an error.)
98616566Ssos     */
98716566Ssos
98831604Syokota    switch (rodent.rtype) {
98931604Syokota
99031604Syokota    case MOUSE_PROTO_LOGI:
99131604Syokota	/*
99231604Syokota	 * The baud rate selection command must be sent at the current
99331604Syokota	 * baud rate; try all likely settings
99431604Syokota	 */
99531604Syokota	setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
99631604Syokota	setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
99731604Syokota	setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
99831604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
99931604Syokota	/* select MM series data format */
100031604Syokota	write(rodent.mfd, "S", 1);
100131604Syokota	setmousespeed(rodent.baudrate, rodent.baudrate,
100231604Syokota		      rodentcflags[MOUSE_PROTO_MM]);
100331604Syokota	/* select report rate/frequency */
100431604Syokota	if      (rodent.rate <= 0)   write(rodent.mfd, "O", 1);
100531604Syokota	else if (rodent.rate <= 15)  write(rodent.mfd, "J", 1);
100631604Syokota	else if (rodent.rate <= 27)  write(rodent.mfd, "K", 1);
100731604Syokota	else if (rodent.rate <= 42)  write(rodent.mfd, "L", 1);
100831604Syokota	else if (rodent.rate <= 60)  write(rodent.mfd, "R", 1);
100931604Syokota	else if (rodent.rate <= 85)  write(rodent.mfd, "M", 1);
101031604Syokota	else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1);
101131604Syokota	else			     write(rodent.mfd, "N", 1);
101231604Syokota	break;
101331604Syokota
101431604Syokota    case MOUSE_PROTO_LOGIMOUSEMAN:
101531604Syokota	/* The command must always be sent at 1200 baud */
101631604Syokota	setmousespeed(1200, 1200, rodentcflags[rodent.rtype]);
101716566Ssos	write(rodent.mfd, "*X", 2);
101831604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
101931604Syokota	break;
102018222Speter
102131604Syokota    case MOUSE_PROTO_HITTAB:
102231604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
102318222Speter
102431604Syokota	/*
102531604Syokota	 * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
102631604Syokota	 * The tablet must be configured to be in MM mode, NO parity,
102731604Syokota	 * Binary Format.  xf86Info.sampleRate controls the sensativity
102831604Syokota	 * of the tablet.  We only use this tablet for it's 4-button puck
102931604Syokota	 * so we don't run in "Absolute Mode"
103031604Syokota	 */
103131604Syokota	write(rodent.mfd, "z8", 2);	/* Set Parity = "NONE" */
103231604Syokota	usleep(50000);
103331604Syokota	write(rodent.mfd, "zb", 2);	/* Set Format = "Binary" */
103431604Syokota	usleep(50000);
103531604Syokota	write(rodent.mfd, "@", 1);	/* Set Report Mode = "Stream" */
103631604Syokota	usleep(50000);
103731604Syokota	write(rodent.mfd, "R", 1);	/* Set Output Rate = "45 rps" */
103831604Syokota	usleep(50000);
103931604Syokota	write(rodent.mfd, "I\x20", 2);	/* Set Incrememtal Mode "20" */
104031604Syokota	usleep(50000);
104131604Syokota	write(rodent.mfd, "E", 1);	/* Set Data Type = "Relative */
104231604Syokota	usleep(50000);
104318222Speter
104431604Syokota	/* Resolution is in 'lines per inch' on the Hitachi tablet */
104531604Syokota	if      (rodent.resolution == MOUSE_RES_LOW) 		c = 'g';
104631604Syokota	else if (rodent.resolution == MOUSE_RES_MEDIUMLOW)	c = 'e';
104731604Syokota	else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH)	c = 'h';
104831604Syokota	else if (rodent.resolution == MOUSE_RES_HIGH)		c = 'd';
104931604Syokota	else if (rodent.resolution <=   40) 			c = 'g';
105031604Syokota	else if (rodent.resolution <=  100) 			c = 'd';
105131604Syokota	else if (rodent.resolution <=  200) 			c = 'e';
105231604Syokota	else if (rodent.resolution <=  500) 			c = 'h';
105331604Syokota	else if (rodent.resolution <= 1000) 			c = 'j';
105431604Syokota	else                                			c = 'd';
105531604Syokota	write(rodent.mfd, &c, 1);
105631604Syokota	usleep(50000);
105718222Speter
105831604Syokota	write(rodent.mfd, "\021", 1);	/* Resume DATA output */
105931604Syokota	break;
106031604Syokota
106131604Syokota    case MOUSE_PROTO_THINK:
106231604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
106331604Syokota	/* the PnP ID string may be sent again, discard it */
106431604Syokota	usleep(200000);
106531604Syokota	i = FREAD;
106631604Syokota	ioctl(rodent.mfd, TIOCFLUSH, &i);
106731604Syokota	/* send the command to initialize the beast */
106831604Syokota	for (s = "E5E5"; *s; ++s) {
106931604Syokota	    write(rodent.mfd, s, 1);
107031604Syokota	    FD_ZERO(&fds);
107131604Syokota	    FD_SET(rodent.mfd, &fds);
107231604Syokota	    if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
107331604Syokota		break;
107431604Syokota	    read(rodent.mfd, &c, 1);
107531604Syokota	    debug("%c", c);
107631604Syokota	    if (c != *s)
107731604Syokota	        break;
107818222Speter	}
107931604Syokota	break;
108031604Syokota
108131604Syokota    case MOUSE_PROTO_MSC:
108231604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
108331604Syokota	if (rodent.flags & ClearDTR) {
108431604Syokota	   i = TIOCM_DTR;
108531604Syokota	   ioctl(rodent.mfd, TIOCMBIC, &i);
108631604Syokota        }
108731604Syokota        if (rodent.flags & ClearRTS) {
108831604Syokota	   i = TIOCM_RTS;
108931604Syokota	   ioctl(rodent.mfd, TIOCMBIC, &i);
109031604Syokota        }
109131604Syokota	break;
109231604Syokota
109331726Syokota    case MOUSE_PROTO_SYSMOUSE:
109431726Syokota	if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE)
109531726Syokota	    setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
109631726Syokota	/* fall through */
109731726Syokota
109831604Syokota    case MOUSE_PROTO_BUS:
109931604Syokota    case MOUSE_PROTO_INPORT:
110031604Syokota    case MOUSE_PROTO_PS2:
110131604Syokota	if (rodent.rate >= 0)
110231604Syokota	    rodent.mode.rate = rodent.rate;
110331604Syokota	if (rodent.resolution != MOUSE_RES_UNKNOWN)
110431604Syokota	    rodent.mode.resolution = rodent.resolution;
110531604Syokota	ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode);
110631604Syokota	break;
110731604Syokota
110831604Syokota    default:
110931604Syokota	setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
111031604Syokota	break;
111116566Ssos    }
111216566Ssos}
111316566Ssos
111431604Syokotastatic int
111531604Syokotar_protocol(u_char rBuf, mousestatus_t *act)
111616566Ssos{
111731604Syokota    /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
111831604Syokota    static int butmapmss[4] = {	/* Microsoft, MouseMan, GlidePoint,
111931604Syokota				   IntelliMouse, Thinking Mouse */
112031604Syokota	0,
112131604Syokota	MOUSE_BUTTON3DOWN,
112231604Syokota	MOUSE_BUTTON1DOWN,
112331604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
112431604Syokota    };
112531604Syokota    static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint,
112631604Syokota				    Thinking Mouse */
112731604Syokota	0,
112831604Syokota	MOUSE_BUTTON4DOWN,
112931604Syokota	MOUSE_BUTTON2DOWN,
113031604Syokota	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
113131604Syokota    };
113231604Syokota    /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
113331604Syokota    static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
113431604Syokota				       MouseMan+ */
113531604Syokota	0,
113631604Syokota	MOUSE_BUTTON2DOWN,
113731604Syokota	MOUSE_BUTTON4DOWN,
113831604Syokota	MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
113931604Syokota    };
114031604Syokota    /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
114131604Syokota    static int butmapmsc[8] = {	/* MouseSystems, MMSeries, Logitech,
114231604Syokota				   Bus, sysmouse */
114331604Syokota	0,
114431604Syokota	MOUSE_BUTTON3DOWN,
114531604Syokota	MOUSE_BUTTON2DOWN,
114631604Syokota	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
114731604Syokota	MOUSE_BUTTON1DOWN,
114831604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
114931604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
115031604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
115131604Syokota    };
115231604Syokota    /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
115331604Syokota    static int butmapps2[8] = {	/* PS/2 */
115431604Syokota	0,
115531604Syokota	MOUSE_BUTTON1DOWN,
115631604Syokota	MOUSE_BUTTON3DOWN,
115731604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
115831604Syokota	MOUSE_BUTTON2DOWN,
115931604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
116031604Syokota	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
116131604Syokota	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
116231604Syokota    };
116331604Syokota    /* for Hitachi tablet */
116431604Syokota    static int butmaphit[8] = {	/* MM HitTablet */
116531604Syokota	0,
116631604Syokota	MOUSE_BUTTON3DOWN,
116731604Syokota	MOUSE_BUTTON2DOWN,
116831604Syokota	MOUSE_BUTTON1DOWN,
116931604Syokota	MOUSE_BUTTON4DOWN,
117031604Syokota	MOUSE_BUTTON5DOWN,
117131604Syokota	MOUSE_BUTTON6DOWN,
117231604Syokota	MOUSE_BUTTON7DOWN,
117331604Syokota    };
117416566Ssos    static int           pBufP = 0;
117516566Ssos    static unsigned char pBuf[8];
117616566Ssos
117716566Ssos    debug("received char 0x%x",(int)rBuf);
117816566Ssos
117916566Ssos    /*
118016566Ssos     * Hack for resyncing: We check here for a package that is:
118116566Ssos     *  a) illegal (detected by wrong data-package header)
118216566Ssos     *  b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
118316566Ssos     *  c) bad header-package
118416566Ssos     *
118516566Ssos     * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
118616566Ssos     *       -128 are allowed, but since they are very seldom we can easily
118716566Ssos     *       use them as package-header with no button pressed.
118816566Ssos     * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
118916566Ssos     *         0x80 is not valid as a header byte. For a PS/2 mouse we skip
119016566Ssos     *         checking data bytes.
119116566Ssos     *         For resyncing a PS/2 mouse we require the two most significant
119216566Ssos     *         bits in the header byte to be 0. These are the overflow bits,
119316566Ssos     *         and in case of an overflow we actually lose sync. Overflows
119416566Ssos     *         are very rare, however, and we quickly gain sync again after
119516566Ssos     *         an overflow condition. This is the best we can do. (Actually,
119616566Ssos     *         we could use bit 0x08 in the header byte for resyncing, since
119716566Ssos     *         that bit is supposed to be always on, but nobody told
119816566Ssos     *         Microsoft...)
119916566Ssos     */
120016566Ssos
120131604Syokota    if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 &&
120231604Syokota	((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80))
120316566Ssos    {
120416566Ssos	pBufP = 0;		/* skip package */
120516566Ssos    }
120616566Ssos
120731604Syokota    if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1])
120831604Syokota	return 0;
120931604Syokota
121031604Syokota    /* is there an extra data byte? */
121131604Syokota    if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1])
121216566Ssos    {
121316566Ssos	/*
121416566Ssos	 * Hack for Logitech MouseMan Mouse - Middle button
121516566Ssos	 *
121616566Ssos	 * Unfortunately this mouse has variable length packets: the standard
121716566Ssos	 * Microsoft 3 byte packet plus an optional 4th byte whenever the
121816566Ssos	 * middle button status changes.
121916566Ssos	 *
122016566Ssos	 * We have already processed the standard packet with the movement
122116566Ssos	 * and button info.  Now post an event message with the old status
122216566Ssos	 * of the left and right buttons and the updated middle button.
122316566Ssos	 */
122416566Ssos
122516566Ssos	/*
122616566Ssos	 * Even worse, different MouseMen and TrackMen differ in the 4th
122716566Ssos	 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
122816566Ssos	 * 0x02/0x22, so I have to strip off the lower bits.
122931604Syokota         *
123031604Syokota         * [JCH-96/01/21]
123131604Syokota         * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
123231604Syokota         * and it is activated by tapping the glidepad with the finger! 8^)
123331604Syokota         * We map it to bit bit3, and the reverse map in xf86Events just has
123431604Syokota         * to be extended so that it is identified as Button 4. The lower
123531604Syokota         * half of the reverse-map may remain unchanged.
123616566Ssos	 */
123731604Syokota
123831604Syokota        /*
123931604Syokota	 * [KY-97/08/03]
124031604Syokota	 * Receive the fourth byte only when preceeding three bytes have
124131604Syokota	 * been detected (pBufP >= cur_proto[4]).  In the previous
124231604Syokota	 * versions, the test was pBufP == 0; thus, we may have mistakingly
124331604Syokota	 * received a byte even if we didn't see anything preceeding
124431604Syokota	 * the byte.
124531604Syokota	 */
124631604Syokota
124731604Syokota	if ((rBuf & cur_proto[5]) != cur_proto[6]) {
124831604Syokota            pBufP = 0;
124931604Syokota	    return 0;
125016566Ssos	}
125116566Ssos
125231604Syokota	switch (rodent.rtype) {
125331604Syokota#if notyet
125431604Syokota	case MOUSE_PROTO_MARIQUA:
125531604Syokota	    /*
125631604Syokota	     * This mouse has 16! buttons in addition to the standard
125731604Syokota	     * three of them.  They return 0x10 though 0x1f in the
125831604Syokota	     * so-called `ten key' mode and 0x30 though 0x3f in the
125931604Syokota	     * `function key' mode.  As there are only 31 bits for
126031604Syokota	     * button state (including the standard three), we ignore
126131604Syokota	     * the bit 0x20 and don't distinguish the two modes.
126231604Syokota	     */
126331604Syokota	    act->dx = act->dy = act->dz = 0;
126431604Syokota	    act->obutton = act->button;
126531604Syokota	    rBuf &= 0x1f;
126631604Syokota	    act->button = (1 << (rBuf - 13))
126731604Syokota                | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
126831604Syokota	    /*
126931604Syokota	     * FIXME: this is a button "down" event. There needs to be
127031604Syokota	     * a corresponding button "up" event... XXX
127131604Syokota	     */
127231604Syokota	    break;
127331604Syokota#endif /* notyet */
127431604Syokota
127531604Syokota	/*
127631604Syokota	 * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
127731604Syokota	 * always send the fourth byte, whereas the fourth byte is
127831604Syokota	 * optional for GlidePoint and ThinkingMouse. The fourth byte
127931604Syokota	 * is also optional for MouseMan+ and FirstMouse+ in their
128031604Syokota	 * native mode. It is always sent if they are in the IntelliMouse
128131604Syokota	 * compatible mode.
128231604Syokota	 */
128331604Syokota	case MOUSE_PROTO_INTELLI:	/* IntelliMouse, NetMouse, Mie Mouse,
128431604Syokota					   MouseMan+ */
128531604Syokota	    act->dx = act->dy = 0;
128631604Syokota	    act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f);
128731604Syokota	    act->obutton = act->button;
128831604Syokota	    act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
128931604Syokota		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
129031604Syokota	    break;
129131604Syokota
129231604Syokota	default:
129331604Syokota	    act->dx = act->dy = act->dz = 0;
129431604Syokota	    act->obutton = act->button;
129531604Syokota	    act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
129631604Syokota		| (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
129731604Syokota	    break;
129831604Syokota	}
129931604Syokota
130031604Syokota	act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
130131604Syokota	    | (act->obutton ^ act->button);
130231604Syokota        pBufP = 0;
130331604Syokota	return act->flags;
130416566Ssos    }
130516566Ssos
130631604Syokota    if (pBufP >= cur_proto[4])
130731604Syokota	pBufP = 0;
130816566Ssos    pBuf[pBufP++] = rBuf;
130931604Syokota    if (pBufP != cur_proto[4])
131031604Syokota	return 0;
131116566Ssos
131216566Ssos    /*
131316566Ssos     * assembly full package
131416566Ssos     */
131516566Ssos
131631604Syokota    debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
131731604Syokota	cur_proto[4],
131831604Syokota	pBuf[0], pBuf[1], pBuf[2], pBuf[3],
131931604Syokota	pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
132016566Ssos
132131604Syokota    act->dz = 0;
132231604Syokota    act->obutton = act->button;
132331604Syokota    switch (rodent.rtype)
132416566Ssos    {
132531604Syokota    case MOUSE_PROTO_MS:		/* Microsoft */
132631604Syokota    case MOUSE_PROTO_LOGIMOUSEMAN:	/* MouseMan/TrackMan */
132716566Ssos	if (rodent.flags & ChordMiddle)
132831604Syokota	    act->button = ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS)
132931604Syokota		? MOUSE_BUTTON2DOWN
133031604Syokota		: butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
133116566Ssos	else
133231604Syokota	    act->button = (act->obutton & MOUSE_BUTTON2DOWN)
133331604Syokota		| butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
133431604Syokota	act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
133531604Syokota	act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
133616566Ssos	break;
133731604Syokota
133831604Syokota    case MOUSE_PROTO_GLIDEPOINT:	/* GlidePoint */
133931604Syokota    case MOUSE_PROTO_THINK:		/* ThinkingMouse */
134031604Syokota    case MOUSE_PROTO_INTELLI:		/* IntelliMouse, NetMouse, Mie Mouse,
134131604Syokota					   MouseMan+ */
134231604Syokota	act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN))
134331604Syokota            | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
134431604Syokota	act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
134531604Syokota	act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
134631604Syokota	break;
134716566Ssos
134831604Syokota    case MOUSE_PROTO_MSC:		/* MouseSystems Corp */
134931604Syokota#if notyet
135031604Syokota    case MOUSE_PROTO_MARIQUA:		/* Mariqua */
135131604Syokota#endif
135231604Syokota	act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
135331604Syokota	act->dx =    (char)(pBuf[1]) + (char)(pBuf[3]);
135431604Syokota	act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
135516566Ssos	break;
135616566Ssos
135731604Syokota    case MOUSE_PROTO_HITTAB:		/* MM HitTablet */
135831604Syokota	act->button = butmaphit[pBuf[0] & 0x07];
135931604Syokota	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
136031604Syokota	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
136118222Speter	break;
136218222Speter
136331604Syokota    case MOUSE_PROTO_MM:		/* MM Series */
136431604Syokota    case MOUSE_PROTO_LOGI:		/* Logitech Mice */
136531604Syokota	act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS];
136631604Syokota	act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ?   pBuf[1] : - pBuf[1];
136731604Syokota	act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] :   pBuf[2];
136816566Ssos	break;
136916566Ssos
137031604Syokota    case MOUSE_PROTO_BUS:		/* Bus */
137131604Syokota    case MOUSE_PROTO_INPORT:		/* InPort */
137231604Syokota	act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
137331604Syokota	act->dx =   (char)pBuf[1];
137431604Syokota	act->dy = - (char)pBuf[2];
137516566Ssos	break;
137616566Ssos
137731604Syokota    case MOUSE_PROTO_PS2:		/* PS/2 */
137831604Syokota	act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS];
137931604Syokota	act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ?    pBuf[1] - 256  :  pBuf[1];
138031604Syokota	act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ?  -(pBuf[2] - 256) : -pBuf[2];
138131604Syokota	/*
138231604Syokota	 * Moused usually operates the psm driver at the operation level 1
138331604Syokota	 * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
138431604Syokota	 * The following code takes effect only when the user explicitly
138531604Syokota	 * requets the level 2 at which wheel movement and additional button
138631604Syokota	 * actions are encoded in model-dependent formats. At the level 0
138731604Syokota	 * the following code is no-op because the psm driver says the model
138831604Syokota	 * is MOUSE_MODEL_GENERIC.
138931604Syokota	 */
139031604Syokota	switch (rodent.hw.model) {
139131604Syokota	case MOUSE_MODEL_INTELLI:
139231604Syokota	case MOUSE_MODEL_NET:
139331604Syokota	    /* wheel data is in the fourth byte */
139431604Syokota	    act->dz = (char)pBuf[3];
139531604Syokota	    break;
139631604Syokota	case MOUSE_MODEL_MOUSEMANPLUS:
139731604Syokota	    if ((pBuf[0] & ~MOUSE_PS2_BUTTONS) == 0xc8) {
139831604Syokota		/* the extended data packet encodes button and wheel events */
139931604Syokota		act->dx = act->dy = 0;
140031604Syokota		act->dz = (pBuf[1] & MOUSE_PS2PLUS_ZNEG)
140131604Syokota		    ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
140231604Syokota		act->button |= ((pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
140331604Syokota		    ? MOUSE_BUTTON4DOWN : 0);
140431604Syokota	    } else {
140531604Syokota		/* preserve button states */
140631604Syokota		act->button |= act->obutton & MOUSE_EXTBUTTONS;
140731604Syokota	    }
140831604Syokota	    break;
140931604Syokota	case MOUSE_MODEL_GLIDEPOINT:
141031604Syokota	    /* `tapping' action */
141131604Syokota	    act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
141231604Syokota	    break;
141331604Syokota	case MOUSE_MODEL_NETSCROLL:
141431604Syokota	    /* three addtional bytes encode button and wheel events */
141531604Syokota	    act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN)
141631604Syokota		? MOUSE_BUTTON4DOWN : 0;
141731604Syokota	    act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4];
141831604Syokota	    break;
141931604Syokota	case MOUSE_MODEL_THINK:
142031604Syokota	    /* the fourth button state in the first byte */
142131604Syokota	    act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
142231604Syokota	    break;
142331604Syokota	case MOUSE_MODEL_GENERIC:
142431604Syokota	default:
142531604Syokota	    break;
142631604Syokota	}
142716566Ssos	break;
142831604Syokota
142931604Syokota    case MOUSE_PROTO_SYSMOUSE:		/* sysmouse */
143031604Syokota	act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
143131604Syokota	act->dx =    (char)(pBuf[1]) + (char)(pBuf[3]);
143231604Syokota	act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
143331604Syokota	if (rodent.level == 1) {
143431604Syokota	    act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1))/2;
143531604Syokota	    act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
143631604Syokota	}
143731604Syokota	break;
143831604Syokota
143931604Syokota    default:
144031604Syokota	return 0;
144116566Ssos    }
144231604Syokota    /*
144331604Syokota     * We don't reset pBufP here yet, as there may be an additional data
144431604Syokota     * byte in some protocols. See above.
144531604Syokota     */
144631604Syokota
144731604Syokota    /* has something changed? */
144831604Syokota    act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
144931604Syokota	| (act->obutton ^ act->button);
145031604Syokota
145131604Syokota    if (rodent.flags & Emulate3Button) {
145231604Syokota	if (((act->flags & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
145331604Syokota	        == (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
145431604Syokota	    && ((act->button & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
145531604Syokota	        == (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))) {
145631604Syokota	    act->button &= ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN);
145731604Syokota	    act->button |= MOUSE_BUTTON2DOWN;
145831604Syokota	} else if ((act->obutton & MOUSE_BUTTON2DOWN)
145931604Syokota	    && ((act->button & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
146031604Syokota	        != (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))) {
146131604Syokota	    act->button &= ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN
146231604Syokota			       | MOUSE_BUTTON3DOWN);
146331604Syokota	}
146431604Syokota	act->flags &= MOUSE_POSCHANGED;
146531604Syokota	act->flags |= act->obutton ^ act->button;
146631604Syokota    }
146731604Syokota
146831604Syokota    return act->flags;
146916566Ssos}
147018222Speter
147131604Syokota/* phisical to logical button mapping */
147231604Syokotastatic int p2l[MOUSE_MAXBUTTON] = {
147331604Syokota    MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
147431604Syokota    MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
147531604Syokota    0x00000100,        0x00000200,        0x00000400,        0x00000800,
147631604Syokota    0x00001000,        0x00002000,        0x00004000,        0x00008000,
147731604Syokota    0x00010000,        0x00020000,        0x00040000,        0x00080000,
147831604Syokota    0x00100000,        0x00200000,        0x00400000,        0x00800000,
147931604Syokota    0x01000000,        0x02000000,        0x04000000,        0x08000000,
148031604Syokota    0x10000000,        0x20000000,        0x40000000,
148131604Syokota};
148231604Syokota
148331604Syokotastatic char *
148431604Syokotaskipspace(char *s)
148531604Syokota{
148631604Syokota    while(isspace(*s))
148731604Syokota	++s;
148831604Syokota    return s;
148931604Syokota}
149031604Syokota
149131604Syokotastatic int
149231604Syokotar_installmap(char *arg)
149331604Syokota{
149431604Syokota    int pbutton;
149531604Syokota    int lbutton;
149631604Syokota    char *s;
149731604Syokota
149831604Syokota    while (*arg) {
149931604Syokota	arg = skipspace(arg);
150031604Syokota	s = arg;
150131604Syokota	while (isdigit(*arg))
150231604Syokota	    ++arg;
150331604Syokota	arg = skipspace(arg);
150431604Syokota	if ((arg <= s) || (*arg != '='))
150531604Syokota	    return FALSE;
150631604Syokota	lbutton = atoi(s);
150731604Syokota
150831604Syokota	arg = skipspace(++arg);
150931604Syokota	s = arg;
151031604Syokota	while (isdigit(*arg))
151131604Syokota	    ++arg;
151231604Syokota	if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
151331604Syokota	    return FALSE;
151431604Syokota	pbutton = atoi(s);
151531604Syokota
151631604Syokota	if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
151731604Syokota	    return FALSE;
151831604Syokota	if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
151931604Syokota	    return FALSE;
152031604Syokota	p2l[pbutton - 1] = 1 << (lbutton - 1);
152131604Syokota    }
152231604Syokota
152331604Syokota    return TRUE;
152431604Syokota}
152531604Syokota
152631604Syokotastatic void
152731604Syokotar_map(mousestatus_t *act1, mousestatus_t *act2)
152831604Syokota{
152931604Syokota    register int pb;
153031604Syokota    register int pbuttons;
153131604Syokota    int lbuttons;
153231604Syokota
153331604Syokota    pbuttons = act1->button;
153431604Syokota    lbuttons = 0;
153531604Syokota
153631604Syokota    act2->obutton = act2->button;
153731604Syokota    act2->dx = act1->dx;
153831604Syokota    act2->dy = act1->dy;
153931604Syokota    act2->dz = act1->dz;
154031604Syokota
154131604Syokota    switch (rodent.zmap) {
154231604Syokota    case 0:	/* do nothing */
154331604Syokota	break;
154431604Syokota    case MOUSE_XAXIS:
154531604Syokota	if (act1->dz != 0) {
154631604Syokota	    act2->dx = act1->dz;
154731604Syokota	    act2->dz = 0;
154831604Syokota	}
154931604Syokota	break;
155031604Syokota    case MOUSE_YAXIS:
155131604Syokota	if (act1->dz != 0) {
155231604Syokota	    act2->dy = act1->dz;
155331604Syokota	    act2->dz = 0;
155431604Syokota	}
155531604Syokota	break;
155631604Syokota    default:	/* buttons */
155731604Syokota	pbuttons &= ~(rodent.zmap | (rodent.zmap << 1));
155831604Syokota	if (act1->dz < 0)
155931604Syokota	    pbuttons |= rodent.zmap;
156031604Syokota	else if (act1->dz > 0)
156131604Syokota	    pbuttons |= (rodent.zmap << 1);
156231604Syokota	act2->dz = 0;
156331604Syokota	break;
156431604Syokota    }
156531604Syokota
156631604Syokota    for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
156731604Syokota	lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
156831604Syokota	pbuttons >>= 1;
156931604Syokota    }
157031604Syokota    act2->button = lbuttons;
157131604Syokota
157231604Syokota    act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
157331604Syokota	| (act2->obutton ^ act2->button);
157431604Syokota}
157531604Syokota
157631604Syokotastatic void
157731604Syokotar_click(mousestatus_t *act)
157831604Syokota{
157931604Syokota    struct mouse_info mouse;
158031604Syokota    struct timeval tv;
158131604Syokota    struct timeval tv1;
158231604Syokota    struct timeval tv2;
158331604Syokota    struct timezone tz;
158431604Syokota    int button;
158531604Syokota    int mask;
158631604Syokota    int i;
158731604Syokota
158831604Syokota    mask = act->flags & MOUSE_BUTTONS;
158931604Syokota    if (mask == 0)
159031604Syokota	return;
159131604Syokota
159231604Syokota    gettimeofday(&tv1, &tz);
159331604Syokota    tv2.tv_sec = rodent.clickthreshold/1000;
159431604Syokota    tv2.tv_usec = (rodent.clickthreshold%1000)*1000;
159531604Syokota    timersub(&tv1, &tv2, &tv);
159631604Syokota    debug("tv:  %ld %ld", tv.tv_sec, tv.tv_usec);
159731604Syokota    button = MOUSE_BUTTON1DOWN;
159831604Syokota    for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
159931604Syokota        if (mask & 1) {
160031604Syokota            if (act->button & button) {
160131604Syokota                /* the button is down */
160231604Syokota    		debug("  :  %ld %ld",
160331604Syokota		    buttonstate[i].tv.tv_sec, buttonstate[i].tv.tv_usec);
160431604Syokota		if (timercmp(&tv, &buttonstate[i].tv, >)) {
160531604Syokota                    buttonstate[i].tv.tv_sec = 0;
160631604Syokota                    buttonstate[i].tv.tv_usec = 0;
160731604Syokota                    buttonstate[i].count = 1;
160831604Syokota                } else {
160931604Syokota                    ++buttonstate[i].count;
161031604Syokota                }
161131604Syokota	        mouse.u.event.value = buttonstate[i].count;
161231604Syokota            } else {
161331604Syokota                /* the button is up */
161431604Syokota                buttonstate[i].tv = tv1;
161531604Syokota	        mouse.u.event.value = 0;
161631604Syokota            }
161731604Syokota	    mouse.operation = MOUSE_BUTTON_EVENT;
161831604Syokota	    mouse.u.event.id = button;
161931604Syokota	    if (debug < 2)
162031604Syokota	        ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
162131604Syokota	    debug("button %d  count %d", i + 1, mouse.u.event.value);
162231604Syokota        }
162331604Syokota	button <<= 1;
162431604Syokota	mask >>= 1;
162531604Syokota    }
162631604Syokota}
162731604Syokota
162818222Speter/* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
162918222Speter/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
163018222Speter/*
163118222Speter * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
163218222Speter *
163318222Speter * Permission to use, copy, modify, distribute, and sell this software and its
163418222Speter * documentation for any purpose is hereby granted without fee, provided that
163518222Speter * the above copyright notice appear in all copies and that both that
163618222Speter * copyright notice and this permission notice appear in supporting
163718222Speter * documentation, and that the name of David Dawes
163818222Speter * not be used in advertising or publicity pertaining to distribution of
163918222Speter * the software without specific, written prior permission.
164018222Speter * David Dawes makes no representations about the suitability of this
164118222Speter * software for any purpose.  It is provided "as is" without express or
164218222Speter * implied warranty.
164318222Speter *
164418222Speter * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
164518222Speter * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
164618222Speter * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
164718222Speter * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
164818222Speter * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
164918222Speter * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
165018222Speter * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165118222Speter *
165218222Speter */
165318222Speter
165418222Speter
165531604Syokotastatic void
165631604Syokotasetmousespeed(int old, int new, unsigned cflag)
165718222Speter{
165818222Speter	struct termios tty;
165918222Speter	char *c;
166018222Speter
166118222Speter	if (tcgetattr(rodent.mfd, &tty) < 0)
166218222Speter	{
166331604Syokota		logwarn("unable to get status of mouse fd", 0);
166431604Syokota		return;
166518222Speter	}
166618222Speter
166718222Speter	tty.c_iflag = IGNBRK | IGNPAR;
166818222Speter	tty.c_oflag = 0;
166918222Speter	tty.c_lflag = 0;
167018222Speter	tty.c_cflag = (tcflag_t)cflag;
167118222Speter	tty.c_cc[VTIME] = 0;
167218222Speter	tty.c_cc[VMIN] = 1;
167318222Speter
167418222Speter	switch (old)
167518222Speter	{
167618222Speter	case 9600:
167718222Speter		cfsetispeed(&tty, B9600);
167818222Speter		cfsetospeed(&tty, B9600);
167918222Speter		break;
168018222Speter	case 4800:
168118222Speter		cfsetispeed(&tty, B4800);
168218222Speter		cfsetospeed(&tty, B4800);
168318222Speter		break;
168418222Speter	case 2400:
168518222Speter		cfsetispeed(&tty, B2400);
168618222Speter		cfsetospeed(&tty, B2400);
168718222Speter		break;
168818222Speter	case 1200:
168918222Speter	default:
169018222Speter		cfsetispeed(&tty, B1200);
169118222Speter		cfsetospeed(&tty, B1200);
169218222Speter	}
169318222Speter
169418222Speter	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
169518222Speter	{
169631604Syokota		logwarn("unable to set status of mouse fd", 0);
169731604Syokota		return;
169818222Speter	}
169918222Speter
170018222Speter	switch (new)
170118222Speter	{
170218222Speter	case 9600:
170318222Speter		c = "*q";
170418222Speter		cfsetispeed(&tty, B9600);
170518222Speter		cfsetospeed(&tty, B9600);
170618222Speter		break;
170718222Speter	case 4800:
170818222Speter		c = "*p";
170918222Speter		cfsetispeed(&tty, B4800);
171018222Speter		cfsetospeed(&tty, B4800);
171118222Speter		break;
171218222Speter	case 2400:
171318222Speter		c = "*o";
171418222Speter		cfsetispeed(&tty, B2400);
171518222Speter		cfsetospeed(&tty, B2400);
171618222Speter		break;
171718222Speter	case 1200:
171818222Speter	default:
171918222Speter		c = "*n";
172018222Speter		cfsetispeed(&tty, B1200);
172118222Speter		cfsetospeed(&tty, B1200);
172218222Speter	}
172318222Speter
172431604Syokota	if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN
172531604Syokota	    || rodent.rtype == MOUSE_PROTO_LOGI)
172618222Speter	{
172718222Speter		if (write(rodent.mfd, c, 2) != 2)
172818222Speter		{
172931604Syokota			logwarn("unable to write to mouse fd", 0);
173031604Syokota			return;
173118222Speter		}
173218222Speter	}
173318222Speter	usleep(100000);
173418222Speter
173518222Speter	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
173631604Syokota		logwarn("unable to set status of mouse fd", 0);
173731604Syokota}
173831604Syokota
173931604Syokota/*
174031604Syokota * PnP COM device support
174131604Syokota *
174231604Syokota * It's a simplistic implementation, but it works :-)
174331604Syokota * KY, 31/7/97.
174431604Syokota */
174531604Syokota
174631604Syokota/*
174731604Syokota * Try to elicit a PnP ID as described in
174831604Syokota * Microsoft, Hayes: "Plug and Play External COM Device Specification,
174931604Syokota * rev 1.00", 1995.
175031604Syokota *
175131604Syokota * The routine does not fully implement the COM Enumerator as par Section
175231604Syokota * 2.1 of the document.  In particular, we don't have idle state in which
175331604Syokota * the driver software monitors the com port for dynamic connection or
175431604Syokota * removal of a device at the port, because `moused' simply quits if no
175531604Syokota * device is found.
175631604Syokota *
175731604Syokota * In addition, as PnP COM device enumeration procedure slightly has
175831604Syokota * changed since its first publication, devices which follow earlier
175931604Syokota * revisions of the above spec. may fail to respond if the rev 1.0
176031604Syokota * procedure is used. XXX
176131604Syokota */
176231604Syokotastatic int
176331604Syokotapnpgets(char *buf)
176431604Syokota{
176531604Syokota    struct timeval timeout;
176631604Syokota    fd_set fds;
176731604Syokota    int i;
176831604Syokota    char c;
176931604Syokota
177031604Syokota#if 0
177131604Syokota    /*
177231604Syokota     * This is the procedure described in rev 1.0 of PnP COM device spec.
177331604Syokota     * Unfortunately, some devices which comform to earlier revisions of
177431604Syokota     * the spec gets confused and do not return the ID string...
177531604Syokota     */
177631604Syokota
177731604Syokota    /* port initialization (2.1.2) */
177831604Syokota    ioctl(rodent.mfd, TIOCMGET, &i);
177931604Syokota    i |= TIOCM_DTR;		/* DTR = 1 */
178031604Syokota    i &= ~TIOCM_RTS;		/* RTS = 0 */
178131604Syokota    ioctl(rodent.mfd, TIOCMSET, &i);
178231604Syokota    usleep(200000);
178331604Syokota    if ((ioctl(rodent.mfd, TIOCMGET, &i) == -1) || ((i & TIOCM_DSR) == 0))
178431604Syokota	goto disconnect_idle;
178531604Syokota
178631604Syokota    /* port setup, 1st phase (2.1.3) */
178731604Syokota    setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
178831604Syokota    i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
178931604Syokota    ioctl(rodent.mfd, TIOCMBIC, &i);
179031604Syokota    usleep(200000);
179131604Syokota    i = TIOCM_DTR;		/* DTR = 1, RTS = 0 */
179231604Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
179331604Syokota    usleep(200000);
179431604Syokota
179531604Syokota    /* wait for response, 1st phase (2.1.4) */
179631604Syokota    i = FREAD;
179731604Syokota    ioctl(rodent.mfd, TIOCFLUSH, &i);
179831604Syokota    i = TIOCM_RTS;		/* DTR = 1, RTS = 1 */
179931604Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
180031604Syokota
180131604Syokota    /* try to read something */
180231604Syokota    FD_ZERO(&fds);
180331604Syokota    FD_SET(rodent.mfd, &fds);
180431604Syokota    timeout.tv_sec = 0;
180531604Syokota    timeout.tv_usec = 200000;
180631604Syokota    if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0) {
180731604Syokota
180831604Syokota	/* port setup, 2nd phase (2.1.5) */
180931604Syokota        i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 0, RTS = 0 */
181031604Syokota        ioctl(rodent.mfd, TIOCMBIC, &i);
181131604Syokota        usleep(200000);
181231604Syokota
181331604Syokota	/* wait for respose, 2nd phase (2.1.6) */
181431604Syokota        i = FREAD;
181531604Syokota        ioctl(rodent.mfd, TIOCFLUSH, &i);
181631604Syokota        i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
181731604Syokota        ioctl(rodent.mfd, TIOCMBIS, &i);
181831604Syokota
181931604Syokota        /* try to read something */
182031604Syokota        FD_ZERO(&fds);
182131604Syokota        FD_SET(rodent.mfd, &fds);
182231604Syokota        timeout.tv_sec = 0;
182331604Syokota        timeout.tv_usec = 200000;
182431604Syokota        if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
182531604Syokota	    goto connect_idle;
182631604Syokota    }
182731604Syokota#else
182831604Syokota    /*
182931604Syokota     * This is a simplified procedure; it simply toggles RTS.
183031604Syokota     */
183131604Syokota
183231604Syokota    ioctl(rodent.mfd, TIOCMGET, &i);
183331604Syokota    i |= TIOCM_DTR;		/* DTR = 1 */
183431604Syokota    i &= ~TIOCM_RTS;		/* RTS = 0 */
183531604Syokota    ioctl(rodent.mfd, TIOCMSET, &i);
183631604Syokota    usleep(200000);
183731604Syokota
183831604Syokota    setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
183931604Syokota
184031604Syokota    /* wait for respose */
184131604Syokota    i = FREAD;
184231604Syokota    ioctl(rodent.mfd, TIOCFLUSH, &i);
184331604Syokota    i = TIOCM_DTR | TIOCM_RTS;	/* DTR = 1, RTS = 1 */
184431604Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
184531604Syokota
184631604Syokota    /* try to read something */
184731604Syokota    FD_ZERO(&fds);
184831604Syokota    FD_SET(rodent.mfd, &fds);
184931604Syokota    timeout.tv_sec = 0;
185031604Syokota    timeout.tv_usec = 200000;
185131604Syokota    if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
185231604Syokota        goto connect_idle;
185331604Syokota#endif
185431604Syokota
185531604Syokota    /* collect PnP COM device ID (2.1.7) */
185631604Syokota    i = 0;
185731604Syokota    usleep(200000);	/* the mouse must send `Begin ID' within 200msec */
185831604Syokota    while (read(rodent.mfd, &c, 1) == 1) {
185931604Syokota	/* we may see "M", or "M3..." before `Begin ID' */
186031604Syokota        if ((c == 0x08) || (c == 0x28)) {	/* Begin ID */
186131604Syokota	    buf[i++] = c;
186231604Syokota	    break;
186331604Syokota        }
186431604Syokota        debug("%c %02x", c, c);
186531604Syokota    }
186631604Syokota    if (i <= 0) {
186731604Syokota	/* we haven't seen `Begin ID' in time... */
186831604Syokota	goto connect_idle;
186931604Syokota    }
187031604Syokota
187131604Syokota    ++c;			/* make it `End ID' */
187231604Syokota    for (;;) {
187331604Syokota        FD_ZERO(&fds);
187431604Syokota        FD_SET(rodent.mfd, &fds);
187531604Syokota        timeout.tv_sec = 0;
187631604Syokota        timeout.tv_usec = 200000;
187731604Syokota        if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
187831604Syokota	    break;
187931604Syokota
188031604Syokota	read(rodent.mfd, &buf[i], 1);
188131604Syokota        if (buf[i++] == c)	/* End ID */
188231604Syokota	    break;
188331604Syokota	if (i >= 256)
188431604Syokota	    break;
188531604Syokota    }
188631604Syokota    /* string may not be human readable... */
188731604Syokota    debug("'%-*.*s'", i, i, buf);
188831604Syokota    if (buf[i - 1] != c)
188931604Syokota	goto connect_idle;
189031604Syokota    return i;
189131604Syokota
189231604Syokota    /*
189331604Syokota     * According to PnP spec, we should set DTR = 1 and RTS = 0 while
189431604Syokota     * in idle state.  But, `moused' shall set DTR = RTS = 1 and proceed,
189531604Syokota     * assuming there is something at the port even if it didn't
189631604Syokota     * respond to the PnP enumeration procedure.
189731604Syokota     */
189831604Syokotadisconnect_idle:
189931604Syokota    i = TIOCM_DTR | TIOCM_RTS;		/* DTR = 1, RTS = 1 */
190031604Syokota    ioctl(rodent.mfd, TIOCMBIS, &i);
190131604Syokotaconnect_idle:
190231604Syokota    return 0;
190331604Syokota}
190431604Syokota
190531604Syokotastatic int
190631604Syokotapnpparse(pnpid_t *id, char *buf, int len)
190731604Syokota{
190831604Syokota    char s[3];
190931604Syokota    int offset;
191031604Syokota    int sum = 0;
191131604Syokota    int i, j;
191231604Syokota
191331604Syokota    id->revision = 0;
191431604Syokota    id->eisaid = NULL;
191531604Syokota    id->serial = NULL;
191631604Syokota    id->class = NULL;
191731604Syokota    id->compat = NULL;
191831604Syokota    id->description = NULL;
191931604Syokota    id->neisaid = 0;
192031604Syokota    id->nserial = 0;
192131604Syokota    id->nclass = 0;
192231604Syokota    id->ncompat = 0;
192331604Syokota    id->ndescription = 0;
192431604Syokota
192531604Syokota    offset = 0x28 - buf[0];
192631604Syokota
192731604Syokota    /* calculate checksum */
192831604Syokota    for (i = 0; i < len - 3; ++i) {
192931604Syokota	sum += buf[i];
193031604Syokota	buf[i] += offset;
193131604Syokota    }
193231604Syokota    sum += buf[len - 1];
193331604Syokota    for (; i < len; ++i)
193431604Syokota	buf[i] += offset;
193531604Syokota    debug("PnP ID string: '%*.*s'", len, len, buf);
193631604Syokota
193731604Syokota    /* revision */
193831604Syokota    buf[1] -= offset;
193931604Syokota    buf[2] -= offset;
194031604Syokota    id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
194131604Syokota    debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100);
194231604Syokota
194331604Syokota    /* EISA vender and product ID */
194431604Syokota    id->eisaid = &buf[3];
194531604Syokota    id->neisaid = 7;
194631604Syokota
194731604Syokota    /* option strings */
194831604Syokota    i = 10;
194931604Syokota    if (buf[i] == '\\') {
195031604Syokota        /* device serial # */
195131604Syokota        for (j = ++i; i < len; ++i) {
195231604Syokota            if (buf[i] == '\\')
195331604Syokota		break;
195431604Syokota        }
195531604Syokota	if (i >= len)
195631604Syokota	    i -= 3;
195731604Syokota	if (i - j == 8) {
195831604Syokota            id->serial = &buf[j];
195931604Syokota            id->nserial = 8;
196018222Speter	}
196131604Syokota    }
196231604Syokota    if (buf[i] == '\\') {
196331604Syokota        /* PnP class */
196431604Syokota        for (j = ++i; i < len; ++i) {
196531604Syokota            if (buf[i] == '\\')
196631604Syokota		break;
196731604Syokota        }
196831604Syokota	if (i >= len)
196931604Syokota	    i -= 3;
197031604Syokota	if (i > j + 1) {
197131604Syokota            id->class = &buf[j];
197231604Syokota            id->nclass = i - j;
197331604Syokota        }
197431604Syokota    }
197531604Syokota    if (buf[i] == '\\') {
197631604Syokota	/* compatible driver */
197731604Syokota        for (j = ++i; i < len; ++i) {
197831604Syokota            if (buf[i] == '\\')
197931604Syokota		break;
198031604Syokota        }
198131604Syokota	/*
198231604Syokota	 * PnP COM spec prior to v0.96 allowed '*' in this field,
198331604Syokota	 * it's not allowed now; just igore it.
198431604Syokota	 */
198531604Syokota	if (buf[j] == '*')
198631604Syokota	    ++j;
198731604Syokota	if (i >= len)
198831604Syokota	    i -= 3;
198931604Syokota	if (i > j + 1) {
199031604Syokota            id->compat = &buf[j];
199131604Syokota            id->ncompat = i - j;
199231604Syokota        }
199331604Syokota    }
199431604Syokota    if (buf[i] == '\\') {
199531604Syokota	/* product description */
199631604Syokota        for (j = ++i; i < len; ++i) {
199731604Syokota            if (buf[i] == ';')
199831604Syokota		break;
199931604Syokota        }
200031604Syokota	if (i >= len)
200131604Syokota	    i -= 3;
200231604Syokota	if (i > j + 1) {
200331604Syokota            id->description = &buf[j];
200431604Syokota            id->ndescription = i - j;
200531604Syokota        }
200631604Syokota    }
200731604Syokota
200831604Syokota    /* checksum exists if there are any optional fields */
200931604Syokota    if ((id->nserial > 0) || (id->nclass > 0)
201031604Syokota	|| (id->ncompat > 0) || (id->ndescription > 0)) {
201131604Syokota        debug("PnP checksum: 0x%X", sum);
201231604Syokota        sprintf(s, "%02X", sum & 0x0ff);
201331604Syokota        if (strncmp(s, &buf[len - 3], 2) != 0) {
201431604Syokota#if 0
201531604Syokota            /*
201631604Syokota	     * I found some mice do not comply with the PnP COM device
201731604Syokota	     * spec regarding checksum... XXX
201831604Syokota	     */
201931604Syokota            logwarnx("PnP checksum error", 0);
202031604Syokota	    return FALSE;
202131604Syokota#endif
202231604Syokota        }
202331604Syokota    }
202431604Syokota
202531604Syokota    return TRUE;
202618222Speter}
202731604Syokota
202831604Syokotastatic symtab_t *
202931604Syokotapnpproto(pnpid_t *id)
203031604Syokota{
203131604Syokota    symtab_t *t;
203231604Syokota    int i, j;
203331604Syokota
203431604Syokota    if (id->nclass > 0)
203531604Syokota	if (strncmp(id->class, "MOUSE", id->nclass) != 0)
203631604Syokota	    /* this is not a mouse! */
203731604Syokota	    return NULL;
203831604Syokota
203931604Syokota    if (id->neisaid > 0) {
204031604Syokota        t = gettoken(pnpprod, id->eisaid, id->neisaid);
204131604Syokota	if (t->val != MOUSE_PROTO_UNKNOWN)
204231604Syokota            return t;
204331604Syokota    }
204431604Syokota
204531604Syokota    /*
204631604Syokota     * The 'Compatible drivers' field may contain more than one
204731604Syokota     * ID separated by ','.
204831604Syokota     */
204931604Syokota    if (id->ncompat <= 0)
205031604Syokota	return NULL;
205131604Syokota    for (i = 0; i < id->ncompat; ++i) {
205231604Syokota        for (j = i; id->compat[i] != ','; ++i)
205331604Syokota            if (i >= id->ncompat)
205431604Syokota		break;
205531604Syokota        if (i > j) {
205631604Syokota            t = gettoken(pnpprod, id->compat + j, i - j);
205731604Syokota	    if (t->val != MOUSE_PROTO_UNKNOWN)
205831604Syokota                return t;
205931604Syokota	}
206031604Syokota    }
206131604Syokota
206231604Syokota    return NULL;
206331604Syokota}
206431604Syokota
206531604Syokota/* name/val mapping */
206631604Syokota
206731604Syokotastatic symtab_t *
206831604Syokotagettoken(symtab_t *tab, char *s, int len)
206931604Syokota{
207031604Syokota    int i;
207131604Syokota
207231604Syokota    for (i = 0; tab[i].name != NULL; ++i) {
207331604Syokota	if (strncmp(tab[i].name, s, len) == 0)
207431604Syokota	    break;
207531604Syokota    }
207631604Syokota    return &tab[i];
207731604Syokota}
207831604Syokota
207931604Syokotastatic char *
208031604Syokotagettokenname(symtab_t *tab, int val)
208131604Syokota{
208231604Syokota    int i;
208331604Syokota
208431604Syokota    for (i = 0; tab[i].name != NULL; ++i) {
208531604Syokota	if (tab[i].val == val)
208631604Syokota	    return tab[i].name;
208731604Syokota    }
208831604Syokota    return NULL;
208931604Syokota}
2090