moused.c revision 29849
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 **
3716566Ssos ** Mouse daemon : listens to serial port for mouse data stream,
3816566Ssos ** interprets same and passes ioctls off to the console driver.
3916566Ssos **
4016566Ssos ** The mouse interface functions are derived closely from the mouse
4116566Ssos ** handler in the XFree86 X server.  Many thanks to the XFree86 people
4216566Ssos ** for their great work!
4316566Ssos **
4416566Ssos **/
4516566Ssos
4629849Scharnier#ifndef lint
4729849Scharnierstatic const char rcsid[] =
4829849Scharnier	"$Id$";
4929849Scharnier#endif /* not lint */
5029849Scharnier
5129849Scharnier#include <err.h>
5229849Scharnier#include <errno.h>
5329849Scharnier#include <fcntl.h>
5429849Scharnier#include <limits.h>
5516566Ssos#include <stdio.h>
5616566Ssos#include <stdlib.h>
5716566Ssos#include <string.h>
5816566Ssos#include <termios.h>
5916566Ssos#include <machine/console.h>
6021885Ssos#include <sys/types.h>
6121885Ssos#include <sys/time.h>
6221885Ssos#include <unistd.h>
6316566Ssos
6416566Ssos#define debug(fmt,args...) \
6529849Scharnier	if (debug&&nodaemon) warnx(fmt, ##args)
6616566Ssos
6716566Ssosint	debug = 0;
6816566Ssosint	nodaemon = 0;
6916566Ssos
7016566Ssosvoid	usage(void);
7116566Ssos
7216566Ssos#define	R_UNKNOWN	0
7316566Ssos#define R_MICROSOFT	1
7416566Ssos#define R_MOUSESYS	2
7516566Ssos#define R_MMSERIES	3
7616566Ssos#define R_LOGITECH	4
7716566Ssos#define R_BUSMOUSE	5
7816566Ssos#define R_LOGIMAN	6
7916566Ssos#define R_PS_2		7
8018222Speter#define R_MMHITAB	8
8116566Ssos
8216566Ssoschar	*rnames[] = {
8316566Ssos    "xxx",
8416566Ssos    "microsoft",
8516566Ssos    "mousesystems",
8616566Ssos    "mmseries",
8716566Ssos    "logitech",
8816566Ssos    "busmouse",
8916566Ssos    "mouseman",
9016566Ssos    "ps/2",
9118222Speter    "mmhitab",
9216566Ssos    NULL
9316566Ssos};
9416566Ssos
9516566Ssosunsigned short rodentcflags[] =
9616566Ssos{
9716566Ssos    0,							/* nomouse */
9816566Ssos    (CS7	           | CREAD | CLOCAL | HUPCL ),	/* MicroSoft */
9916566Ssos    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* MouseSystems */
10016566Ssos    (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ),	/* MMSeries */
10116566Ssos    (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* Logitech */
10216566Ssos    0,							/* BusMouse */
10316566Ssos    (CS7		   | CREAD | CLOCAL | HUPCL ),	/* MouseMan */
10418222Speter    0,							/* PS/2 */
10518222Speter    (CS8		   | CREAD | CLOCAL | HUPCL ),	/* MMHitTablet */
10616566Ssos};
10716566Ssos
10816566Ssos
10916566Ssostypedef struct
11016566Ssos{
11116566Ssos    int
11216566Ssos	dx,dy,
11316566Ssos	buttons;
11416566Ssos} ACTIVITY;
11516566Ssos
11616566Ssos
11716566Ssosstruct rodentparam
11816566Ssos{
11916566Ssos    int
12016566Ssos	baudrate,
12116566Ssos	samplerate,
12216566Ssos	flags,
12316566Ssos	rtype,
12416566Ssos	lastbuttons,
12516566Ssos	buttons,
12618222Speter	mfd,
12718222Speter	cleardtr,
12818222Speter	clearrts;
12916566Ssos
13016566Ssos    char
13116566Ssos	*portname;
13216566Ssos
13316566Ssos} rodent = { baudrate : 1200,
13416566Ssos	     samplerate : 0,
13516566Ssos             flags : 0,
13616566Ssos             rtype : R_UNKNOWN,
13716566Ssos	     lastbuttons : 0,
13816566Ssos	     buttons : 0,
13916566Ssos	     mfd : -1,
14018222Speter	     portname : NULL,
14118222Speter	     cleardtr : 0,
14218222Speter	     clearrts : 0};
14316566Ssos
14416566Ssos#define	ChordMiddle	1
14516566Ssos
14616566Ssosvoid		r_init(void);
14716566SsosACTIVITY	*r_protocol(u_char b);
14818222Spetervoid		setmousespeed(int old, int new, unsigned cflag);
14916566Ssos
15016566Ssosvoid
15116566Ssosmain(int argc, char *argv[])
15216566Ssos{
15316566Ssos    int			c,i,cfd;
15416566Ssos    u_char		b;
15516566Ssos    ACTIVITY		*act;
15616566Ssos    struct mouse_info 	mouse;
15721885Ssos    fd_set		fds;
15816566Ssos
15924428Simp    while((c = getopt(argc,argv,"cdfr:sp:t:h?RDS:")) != -1)
16016566Ssos	switch(c)
16116566Ssos	{
16216566Ssos	case 'c':
16316566Ssos	    rodent.flags |= ChordMiddle;
16416566Ssos	    break;
16516566Ssos
16616566Ssos	case 'd':
16716566Ssos	    debug = 1;
16816566Ssos	    break;
16916566Ssos
17016566Ssos	case 'f':
17116566Ssos	    nodaemon = 1;
17216566Ssos	    break;
17316566Ssos
17416566Ssos	case 'p':
17516566Ssos	    rodent.portname = optarg;
17616566Ssos	    break;
17716566Ssos
17824377Speter	case 'r':
17924377Speter	    rodent.samplerate = atoi(optarg);
18024377Speter	    break;
18124377Speter
18216566Ssos	case 's':
18316566Ssos	    rodent.baudrate = 9600;
18418222Speter	    break;
18516566Ssos
18618222Speter	case 'R':
18718222Speter	    rodent.clearrts = 1;
18818222Speter	    break;
18918222Speter
19018222Speter	case 'D':
19118222Speter	    rodent.cleardtr = 1;
19218222Speter	    break;
19318222Speter
19418222Speter	case 'S':
19518222Speter	    rodent.baudrate = atoi(optarg);
19618222Speter	    debug("rodent baudrate %d", rodent.baudrate);
19718222Speter	    break;
19818222Speter
19916566Ssos	case 't':
20016566Ssos	    for (i = 0; rnames[i]; i++)
20116566Ssos		if (!strcmp(optarg,rnames[i]))
20216566Ssos		{
20316566Ssos		    debug("rodent is %s",rnames[i]);
20416566Ssos		    rodent.rtype = i;
20516566Ssos		    break;
20616566Ssos		}
20716566Ssos	    if (rnames[i])
20816566Ssos		break;
20918222Speter	    warnx("no such mouse type `%s'",optarg);
21016566Ssos	    usage();
21116566Ssos
21216566Ssos	case 'h':
21316566Ssos	case '?':
21416566Ssos	default:
21516566Ssos	    usage();
21616566Ssos	}
21716566Ssos
21816566Ssos    switch(rodent.rtype)
21916566Ssos    {
22016566Ssos    case R_BUSMOUSE:
22116566Ssos	if (!rodent.portname)
22216566Ssos	    rodent.portname = "/dev/mse0";
22316566Ssos	break;
22416566Ssos    case R_PS_2:
22516566Ssos	if (!rodent.portname)
22616566Ssos	    rodent.portname = "/dev/psm0";
22716566Ssos	break;
22816566Ssos    default:
22916566Ssos	if (rodent.portname)
23016566Ssos	    break;
23129849Scharnier	warnx("no port name specified");
23216566Ssos	usage();
23316566Ssos    }
23416566Ssos
23516566Ssos    if ((rodent.mfd = open(rodent.portname, O_RDWR, 0)) == -1)
23616566Ssos    {
23729849Scharnier	warn("can't open %s",rodent.portname);
23816566Ssos	usage();
23916566Ssos    }
24016566Ssos    r_init();				/* call init function */
24116566Ssos
24218190Ssos    if ((cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
24318222Speter	err(1, "open(/dev/consolectl)");
24416566Ssos
24516566Ssos    if (!nodaemon)
24616566Ssos	if (daemon(0,0))
24716566Ssos	{
24818222Speter	    err(1, "daemon() failed");
24916566Ssos	}
25016566Ssos
25116566Ssos    for(;;)
25216566Ssos    {
25321885Ssos	FD_ZERO(&fds);
25421885Ssos	FD_SET(rodent.mfd,&fds);
25521885Ssos	select(FD_SETSIZE,&fds,NULL,&fds,NULL);
25616566Ssos	i = read(rodent.mfd,&b,1);	/* get a byte */
25716566Ssos	if (i != 1)			/* read returned or error; goodbye */
25816566Ssos	{
25916566Ssos	    debug("read returned %d : %s exiting",i,strerror(errno));
26016566Ssos	    close(rodent.mfd);
26116566Ssos	    exit(1);
26216566Ssos	}
26316566Ssos	act = r_protocol(b);		/* pass byte to handler */
26416566Ssos	if (act)			/* handler detected action */
26516566Ssos	{
26616693Ssos	    mouse.operation = MOUSE_ACTION;
26716693Ssos	    mouse.u.data.x = act->dx;
26816693Ssos	    mouse.u.data.y = act->dy;
26916693Ssos	    mouse.u.data.buttons = act->buttons;
27016566Ssos	    ioctl(cfd, CONS_MOUSECTL, &mouse);
27129849Scharnier	    debug("activity : buttons 0x%02x  dx %d  dy %d",
27216566Ssos		    act->buttons,act->dx,act->dy);
27316566Ssos	}
27416566Ssos    }
27516566Ssos}
27616566Ssos
27716566Ssos
27816566Ssos/**
27916566Ssos ** usage
28016566Ssos **
28116566Ssos ** Complain, and free the CPU for more worthy tasks
28216566Ssos **/
28316566Ssosvoid
28416566Ssosusage(void)
28516566Ssos{
28629849Scharnier    fprintf(stderr, "%s\n%s\n",
28729849Scharnier	"usage: moused [-DRcdfs] [-r samplerate] [-S baudrate]",
28829849Scharnier	"              -p <port> -t <mousetype>");
28916566Ssos    exit(1);
29016566Ssos}
29116566Ssos
29216566Ssos
29316566Ssos/**
29416566Ssos ** Mouse interface code, courtesy of XFree86 3.1.2.
29516566Ssos **
29616566Ssos ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
29716566Ssos ** to clean, reformat and rationalise naming, it's quite possible that
29816566Ssos ** some things in here have been broken.
29916566Ssos **
30016566Ssos ** I hope not 8)
30116566Ssos **
30216566Ssos ** The following code is derived from a module marked :
30316566Ssos **/
30416566Ssos
30516566Ssos/* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
30616566Ssos/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
30716566Ssos 17:03:40 dawes Exp $ */
30816566Ssos/*
30916566Ssos *
31016566Ssos * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
31116566Ssos * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
31216566Ssos *
31316566Ssos * Permission to use, copy, modify, distribute, and sell this software and its
31416566Ssos * documentation for any purpose is hereby granted without fee, provided that
31516566Ssos * the above copyright notice appear in all copies and that both that
31616566Ssos * copyright notice and this permission notice appear in supporting
31716566Ssos * documentation, and that the names of Thomas Roell and David Dawes not be
31816566Ssos * used in advertising or publicity pertaining to distribution of the
31916566Ssos * software without specific, written prior permission.  Thomas Roell
32016566Ssos * and David Dawes makes no representations about the suitability of this
32116566Ssos * software for any purpose.  It is provided "as is" without express or
32216566Ssos * implied warranty.
32316566Ssos *
32416566Ssos * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
32516566Ssos * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
32616566Ssos * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
32716566Ssos * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
32816566Ssos * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
32916566Ssos * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
33016566Ssos * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33116566Ssos *
33216566Ssos */
33316566Ssos
33416566Ssos
33516566Ssosvoid
33616566Ssosr_init(void)
33716566Ssos{
33816566Ssos    /**
33916566Ssos     ** This comment is a little out of context here, but it contains
34016566Ssos     ** some useful information...
34116566Ssos     ********************************************************************
34216566Ssos     **
34316566Ssos     ** The following lines take care of the Logitech MouseMan protocols.
34416566Ssos     **
34516566Ssos     ** NOTE: There are different versions of both MouseMan and TrackMan!
34616566Ssos     **       Hence I add another protocol P_LOGIMAN, which the user can
34716566Ssos     **       specify as MouseMan in his XF86Config file. This entry was
34816566Ssos     **       formerly handled as a special case of P_MS. However, people
34916566Ssos     **       who don't have the middle button problem, can still specify
35016566Ssos     **       Microsoft and use P_MS.
35116566Ssos     **
35216566Ssos     ** By default, these mice should use a 3 byte Microsoft protocol
35316566Ssos     ** plus a 4th byte for the middle button. However, the mouse might
35416566Ssos     ** have switched to a different protocol before we use it, so I send
35516566Ssos     ** the proper sequence just in case.
35616566Ssos     **
35716566Ssos     ** NOTE: - all commands to (at least the European) MouseMan have to
35816566Ssos     **         be sent at 1200 Baud.
35916566Ssos     **       - each command starts with a '*'.
36016566Ssos     **       - whenever the MouseMan receives a '*', it will switch back
36116566Ssos     **	 to 1200 Baud. Hence I have to select the desired protocol
36216566Ssos     **	 first, then select the baud rate.
36316566Ssos     **
36416566Ssos     ** The protocols supported by the (European) MouseMan are:
36516566Ssos     **   -  5 byte packed binary protocol, as with the Mouse Systems
36616566Ssos     **      mouse. Selected by sequence "*U".
36716566Ssos     **   -  2 button 3 byte MicroSoft compatible protocol. Selected
36816566Ssos     **      by sequence "*V".
36916566Ssos     **   -  3 button 3+1 byte MicroSoft compatible protocol (default).
37016566Ssos     **      Selected by sequence "*X".
37116566Ssos     **
37216566Ssos     ** The following baud rates are supported:
37316566Ssos     **   -  1200 Baud (default). Selected by sequence "*n".
37416566Ssos     **   -  9600 Baud. Selected by sequence "*q".
37516566Ssos     **
37616566Ssos     ** Selecting a sample rate is no longer supported with the MouseMan!
37716566Ssos     ** Some additional lines in xf86Config.c take care of ill configured
37816566Ssos     ** baud rates and sample rates. (The user will get an error.)
37916566Ssos     */
38016566Ssos
38116566Ssos
38216566Ssos    if (rodent.rtype == R_LOGIMAN)
38316566Ssos    {
38418222Speter	setmousespeed(1200, 1200, rodentcflags[R_LOGIMAN]);
38516566Ssos	write(rodent.mfd, "*X", 2);
38618222Speter	setmousespeed(1200, rodent.baudrate, rodentcflags[R_LOGIMAN]);
38718222Speter    } else {
38818222Speter	if ((rodent.rtype != R_BUSMOUSE) && (rodent.rtype != R_PS_2))
38918222Speter	{
39018222Speter	    /* try all likely settings */
39118222Speter	    setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
39218222Speter	    setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
39318222Speter	    setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
39418222Speter	    setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
39518222Speter
39618222Speter	    if (rodent.rtype == R_LOGITECH) {
39718222Speter		write(rodent.mfd, "S", 1);
39818222Speter		setmousespeed(rodent.baudrate, rodent.baudrate,
39918222Speter			rodentcflags[R_MMSERIES]);
40018222Speter	    }
40118222Speter
40218222Speter	    if (rodent.rtype == R_MMHITAB) {
40318222Speter		char speedcmd;
40418222Speter	    /*
40518222Speter	     * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
40618222Speter	     * The tablet must be configured to be in MM mode, NO parity,
40718222Speter	     * Binary Format.  xf86Info.sampleRate controls the sensativity
40818222Speter	     * of the tablet.  We only use this tablet for it's 4-button puck
40918222Speter	     * so we don't run in "Absolute Mode"
41018222Speter	     */
41118222Speter		write(rodent.mfd, "z8", 2);	/* Set Parity = "NONE" */
41218222Speter		usleep(50000);
41318222Speter		write(rodent.mfd, "zb", 2);	/* Set Format = "Binary" */
41418222Speter		usleep(50000);
41518222Speter		write(rodent.mfd, "@", 1);	/* Set Report Mode = "Stream" */
41618222Speter		usleep(50000);
41718222Speter		write(rodent.mfd, "R", 1);	/* Set Output Rate = "45 rps" */
41818222Speter		usleep(50000);
41918222Speter		write(rodent.mfd, "I\x20", 2);	/* Set Incrememtal Mode "20" */
42018222Speter		usleep(50000);
42118222Speter		write(rodent.mfd, "E", 1);	/* Set Data Type = "Relative */
42218222Speter		usleep(50000);
42318222Speter
42418222Speter		/* These sample rates translate to 'lines per inch' on the
42518222Speter		   Hitachi tablet */
42618222Speter		if      (rodent.samplerate <=   40) speedcmd = 'g';
42718222Speter		else if (rodent.samplerate <=  100) speedcmd = 'd';
42818222Speter		else if (rodent.samplerate <=  200) speedcmd = 'e';
42918222Speter		else if (rodent.samplerate <=  500) speedcmd = 'h';
43018222Speter		else if (rodent.samplerate <= 1000) speedcmd = 'j';
43118222Speter		else                                speedcmd = 'd';
43218222Speter		write(rodent.mfd, &speedcmd, 1);
43318222Speter		usleep(50000);
43418222Speter
43518222Speter		write(rodent.mfd, "\021", 1);	/* Resume DATA output */
43618222Speter	    } else {
43718222Speter		if      (rodent.samplerate <= 0)   write(rodent.mfd, "O", 1);
43818222Speter		else if (rodent.samplerate <= 15)  write(rodent.mfd, "J", 1);
43918222Speter		else if (rodent.samplerate <= 27)  write(rodent.mfd, "K", 1);
44018222Speter		else if (rodent.samplerate <= 42)  write(rodent.mfd, "L", 1);
44118222Speter		else if (rodent.samplerate <= 60)  write(rodent.mfd, "R", 1);
44218222Speter		else if (rodent.samplerate <= 85)  write(rodent.mfd, "M", 1);
44318222Speter		else if (rodent.samplerate <= 125) write(rodent.mfd, "Q", 1);
44418222Speter		else				   write(rodent.mfd, "N", 1);
44518222Speter	    }
44618222Speter	}
44716566Ssos    }
44818222Speter    if (rodent.rtype == R_MOUSESYS && (rodent.cleardtr))
44916566Ssos    {
45016566Ssos	int val = TIOCM_DTR;
45118222Speter	ioctl(rodent.mfd, TIOCMBIC, &val);
45216566Ssos    }
45318222Speter    if (rodent.rtype == R_MOUSESYS && (rodent.clearrts))
45416566Ssos    {
45516566Ssos	int val = TIOCM_RTS;
45618222Speter	ioctl(rodent.mfd, TIOCMBIC, &val);
45716566Ssos    }
45816566Ssos}
45916566Ssos
46016566SsosACTIVITY *
46116566Ssosr_protocol(u_char rBuf)
46216566Ssos{
46316566Ssos    static int           pBufP = 0;
46416566Ssos    static unsigned char pBuf[8];
46516566Ssos    static ACTIVITY	 act;
46616566Ssos
46718222Speter    static unsigned char proto[10][5] = {
46816566Ssos    /*  hd_mask hd_id   dp_mask dp_id   nobytes */
46916566Ssos    {	0,	0,	0,	0,	0	},  /* nomouse */
47016566Ssos    { 	0x40,	0x40,	0x40,	0x00,	3 	},  /* MicroSoft */
47116566Ssos    {	0xf8,	0x80,	0x00,	0x00,	5	},  /* MouseSystems */
47216566Ssos    {	0xe0,	0x80,	0x80,	0x00,	3	},  /* MMSeries */
47316566Ssos    {	0xe0,	0x80,	0x80,	0x00,	3	},  /* Logitech */
47416566Ssos    {	0xf8,	0x80,	0x00,	0x00,	5	},  /* BusMouse */
47516566Ssos    { 	0x40,	0x40,	0x40,	0x00,	3 	},  /* MouseMan */
47616566Ssos    {	0xc0,	0x00,	0x00,	0x00,	3	},  /* PS/2 mouse */
47718222Speter    {	0xe0,	0x80,	0x80,	0x00,	3	},  /* MM_HitTablet */
47816566Ssos    };
47916566Ssos
48016566Ssos    debug("received char 0x%x",(int)rBuf);
48116566Ssos
48216566Ssos    /*
48316566Ssos     * Hack for resyncing: We check here for a package that is:
48416566Ssos     *  a) illegal (detected by wrong data-package header)
48516566Ssos     *  b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
48616566Ssos     *  c) bad header-package
48716566Ssos     *
48816566Ssos     * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
48916566Ssos     *       -128 are allowed, but since they are very seldom we can easily
49016566Ssos     *       use them as package-header with no button pressed.
49116566Ssos     * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
49216566Ssos     *         0x80 is not valid as a header byte. For a PS/2 mouse we skip
49316566Ssos     *         checking data bytes.
49416566Ssos     *         For resyncing a PS/2 mouse we require the two most significant
49516566Ssos     *         bits in the header byte to be 0. These are the overflow bits,
49616566Ssos     *         and in case of an overflow we actually lose sync. Overflows
49716566Ssos     *         are very rare, however, and we quickly gain sync again after
49816566Ssos     *         an overflow condition. This is the best we can do. (Actually,
49916566Ssos     *         we could use bit 0x08 in the header byte for resyncing, since
50016566Ssos     *         that bit is supposed to be always on, but nobody told
50116566Ssos     *         Microsoft...)
50216566Ssos     */
50316566Ssos
50416566Ssos    if (pBufP != 0 && rodent.rtype != R_PS_2 &&
50516566Ssos	((rBuf & proto[rodent.rtype][2]) != proto[rodent.rtype][3]
50616566Ssos	 || rBuf == 0x80))
50716566Ssos    {
50816566Ssos	pBufP = 0;		/* skip package */
50916566Ssos    }
51016566Ssos
51116566Ssos    if (pBufP == 0 &&
51216566Ssos	(rBuf & proto[rodent.rtype][0]) != proto[rodent.rtype][1])
51316566Ssos    {
51416566Ssos	/*
51516566Ssos	 * Hack for Logitech MouseMan Mouse - Middle button
51616566Ssos	 *
51716566Ssos	 * Unfortunately this mouse has variable length packets: the standard
51816566Ssos	 * Microsoft 3 byte packet plus an optional 4th byte whenever the
51916566Ssos	 * middle button status changes.
52016566Ssos	 *
52116566Ssos	 * We have already processed the standard packet with the movement
52216566Ssos	 * and button info.  Now post an event message with the old status
52316566Ssos	 * of the left and right buttons and the updated middle button.
52416566Ssos	 */
52516566Ssos
52616566Ssos	/*
52716566Ssos	 * Even worse, different MouseMen and TrackMen differ in the 4th
52816566Ssos	 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
52916566Ssos	 * 0x02/0x22, so I have to strip off the lower bits.
53016566Ssos	 */
53116566Ssos	if ((rodent.rtype == R_MICROSOFT || rodent.rtype == R_LOGIMAN)
53216566Ssos	    && (char)(rBuf & ~0x23) == 0)
53316566Ssos	{
53416566Ssos	    act.buttons = ((int)(rBuf & 0x20) >> 4)
53516566Ssos		| (rodent.lastbuttons & 0x05);
53616566Ssos	    rodent.lastbuttons = act.buttons;	/* save new button state */
53716566Ssos	    return(&act);
53816566Ssos	}
53916566Ssos
54016566Ssos	return(NULL);				/* skip package */
54116566Ssos    }
54216566Ssos
54316566Ssos    pBuf[pBufP++] = rBuf;
54416566Ssos    if (pBufP != proto[rodent.rtype][4]) return(NULL);
54516566Ssos
54616566Ssos    /*
54716566Ssos     * assembly full package
54816566Ssos     */
54916566Ssos
55029849Scharnier    debug("assembled full packet (len %d) %x,%x,%x,%x,%x",
55116566Ssos	proto[rodent.rtype][4], pBuf[0],pBuf[1],pBuf[2],pBuf[3],pBuf[4]);
55216566Ssos
55316566Ssos    switch(rodent.rtype)
55416566Ssos    {
55516566Ssos    case R_LOGIMAN:		/* MouseMan / TrackMan */
55616566Ssos    case R_MICROSOFT:		/* Microsoft */
55716566Ssos	if (rodent.flags & ChordMiddle)
55816566Ssos	    act.buttons = (((int) pBuf[0] & 0x30) == 0x30) ? 2 :
55916566Ssos		           ((int)(pBuf[0]&0x20)>>3) | ((int)(pBuf[0]&0x10)>>4);
56016566Ssos	else
56116566Ssos	    act.buttons =   (rodent.lastbuttons & 2)
56216566Ssos		          | ((int)(pBuf[0] & 0x20) >> 3)
56316566Ssos		          | ((int)(pBuf[0] & 0x10) >> 4);
56416566Ssos	act.dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
56516566Ssos	act.dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
56616566Ssos	break;
56716566Ssos
56816566Ssos    case R_MOUSESYS:		/* Mouse Systems Corp */
56916566Ssos	act.buttons = (~pBuf[0]) & 0x07;
57016566Ssos	act.dx =    (char)(pBuf[1]) + (char)(pBuf[3]);
57116566Ssos	act.dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
57216566Ssos	break;
57316566Ssos
57418222Speter    case R_MMHITAB:		/* MM_HitTablet */
57518222Speter	act.buttons = pBuf[0] & 0x07;
57618222Speter	if (act.buttons != 0)
57718222Speter	    act.buttons = 1 << (act.buttons - 1);
57818222Speter	act.dx = (pBuf[0] & 0x10) ?   pBuf[1] : - pBuf[1];
57918222Speter	act.dy = (pBuf[0] & 0x08) ? - pBuf[2] :   pBuf[2];
58018222Speter	break;
58118222Speter
58216566Ssos    case R_MMSERIES:		/* MM Series */
58316566Ssos    case R_LOGITECH:		/* Logitech Mice */
58416566Ssos	act.buttons = pBuf[0] & 0x07;
58516566Ssos	act.dx = (pBuf[0] & 0x10) ?   pBuf[1] : - pBuf[1];
58616566Ssos	act.dy = (pBuf[0] & 0x08) ? - pBuf[2] :   pBuf[2];
58716566Ssos	break;
58816566Ssos
58916566Ssos    case R_BUSMOUSE:		/* BusMouse */
59016566Ssos	act.buttons = (~pBuf[0]) & 0x07;
59116566Ssos	act.dx =   (char)pBuf[1];
59216566Ssos	act.dy = - (char)pBuf[2];
59316566Ssos	break;
59416566Ssos
59516566Ssos    case R_PS_2:		/* PS/2 mouse */
59616566Ssos	act.buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */
59716566Ssos	              (pBuf[0] & 0x02) >> 1 | /* Right */
59816566Ssos		      (pBuf[0] & 0x01) << 2; /* Left */
59916566Ssos	act.dx = (pBuf[0] & 0x10) ?    pBuf[1]-256  :  pBuf[1];
60016566Ssos	act.dy = (pBuf[0] & 0x20) ?  -(pBuf[2]-256) : -pBuf[2];
60116566Ssos	break;
60216566Ssos    }
60316566Ssos    pBufP = 0;
60416566Ssos    return(&act);
60516566Ssos}
60618222Speter
60718222Speter/* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
60818222Speter/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
60918222Speter/*
61018222Speter * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
61118222Speter *
61218222Speter * Permission to use, copy, modify, distribute, and sell this software and its
61318222Speter * documentation for any purpose is hereby granted without fee, provided that
61418222Speter * the above copyright notice appear in all copies and that both that
61518222Speter * copyright notice and this permission notice appear in supporting
61618222Speter * documentation, and that the name of David Dawes
61718222Speter * not be used in advertising or publicity pertaining to distribution of
61818222Speter * the software without specific, written prior permission.
61918222Speter * David Dawes makes no representations about the suitability of this
62018222Speter * software for any purpose.  It is provided "as is" without express or
62118222Speter * implied warranty.
62218222Speter *
62318222Speter * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
62418222Speter * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
62518222Speter * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
62618222Speter * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
62718222Speter * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
62818222Speter * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
62918222Speter * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
63018222Speter *
63118222Speter */
63218222Speter
63318222Speter
63418222Spetervoid
63518222Spetersetmousespeed(old, new, cflag)
63618222Speterint old;
63718222Speterint new;
63818222Speterunsigned cflag;
63918222Speter{
64018222Speter	struct termios tty;
64118222Speter	char *c;
64218222Speter
64318222Speter	if (tcgetattr(rodent.mfd, &tty) < 0)
64418222Speter	{
64529849Scharnier		err(1, "warning: unable to get status of mouse fd");
64618222Speter	}
64718222Speter
64818222Speter	tty.c_iflag = IGNBRK | IGNPAR;
64918222Speter	tty.c_oflag = 0;
65018222Speter	tty.c_lflag = 0;
65118222Speter	tty.c_cflag = (tcflag_t)cflag;
65218222Speter	tty.c_cc[VTIME] = 0;
65318222Speter	tty.c_cc[VMIN] = 1;
65418222Speter
65518222Speter	switch (old)
65618222Speter	{
65718222Speter	case 9600:
65818222Speter		cfsetispeed(&tty, B9600);
65918222Speter		cfsetospeed(&tty, B9600);
66018222Speter		break;
66118222Speter	case 4800:
66218222Speter		cfsetispeed(&tty, B4800);
66318222Speter		cfsetospeed(&tty, B4800);
66418222Speter		break;
66518222Speter	case 2400:
66618222Speter		cfsetispeed(&tty, B2400);
66718222Speter		cfsetospeed(&tty, B2400);
66818222Speter		break;
66918222Speter	case 1200:
67018222Speter	default:
67118222Speter		cfsetispeed(&tty, B1200);
67218222Speter		cfsetospeed(&tty, B1200);
67318222Speter	}
67418222Speter
67518222Speter	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
67618222Speter	{
67729849Scharnier		err(1, "unable to set status of mouse fd");
67818222Speter	}
67918222Speter
68018222Speter	switch (new)
68118222Speter	{
68218222Speter	case 9600:
68318222Speter		c = "*q";
68418222Speter		cfsetispeed(&tty, B9600);
68518222Speter		cfsetospeed(&tty, B9600);
68618222Speter		break;
68718222Speter	case 4800:
68818222Speter		c = "*p";
68918222Speter		cfsetispeed(&tty, B4800);
69018222Speter		cfsetospeed(&tty, B4800);
69118222Speter		break;
69218222Speter	case 2400:
69318222Speter		c = "*o";
69418222Speter		cfsetispeed(&tty, B2400);
69518222Speter		cfsetospeed(&tty, B2400);
69618222Speter		break;
69718222Speter	case 1200:
69818222Speter	default:
69918222Speter		c = "*n";
70018222Speter		cfsetispeed(&tty, B1200);
70118222Speter		cfsetospeed(&tty, B1200);
70218222Speter	}
70318222Speter
70418222Speter	if (rodent.rtype == R_LOGIMAN || rodent.rtype == R_LOGITECH)
70518222Speter	{
70618222Speter		if (write(rodent.mfd, c, 2) != 2)
70718222Speter		{
70829849Scharnier			err(1, "unable to write to mouse fd");
70918222Speter		}
71018222Speter	}
71118222Speter	usleep(100000);
71218222Speter
71318222Speter	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
71418222Speter	{
71529849Scharnier		err(1,"unable to set status of mouse fd");
71618222Speter	}
71718222Speter}
718