xref: /freebsd/usr.sbin/moused/moused.c (revision 3e0f6b97b257a96f7275e4442204263e44b16686)
1 /**
2  ** Copyright (c) 1995 Michael Smith, All rights reserved.
3  **
4  ** Redistribution and use in source and binary forms, with or without
5  ** modification, are permitted provided that the following conditions
6  ** are met:
7  ** 1. Redistributions of source code must retain the above copyright
8  **    notice, this list of conditions and the following disclaimer as
9  **    the first lines of this file unmodified.
10  ** 2. Redistributions in binary form must reproduce the above copyright
11  **    notice, this list of conditions and the following disclaimer in the
12  **    documentation and/or other materials provided with the distribution.
13  ** 3. All advertising materials mentioning features or use of this software
14  **    must display the following acknowledgment:
15  **      This product includes software developed by Michael Smith.
16  ** 4. The name of the author may not be used to endorse or promote products
17  **    derived from this software without specific prior written permission.
18  **
19  **
20  ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY
21  ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR
24  ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27  ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29  ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  **
32  **
33  **      $FreeBSD$
34  **/
35 
36 /**
37  ** MOUSED.C
38  **
39  ** Mouse daemon : listens to serial port for mouse data stream,
40  ** interprets same and passes ioctls off to the console driver.
41  **
42  ** The mouse interface functions are derived closely from the mouse
43  ** handler in the XFree86 X server.  Many thanks to the XFree86 people
44  ** for their great work!
45  **
46  **/
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <limits.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <termios.h>
55 #include <machine/console.h>
56 #include <sys/types.h>
57 #include <sys/time.h>
58 #include <unistd.h>
59 
60 #define debug(fmt,args...) \
61 	if (debug&&nodaemon) fprintf(stderr,"%s: " fmt "\n", progname, ##args)
62 
63 char	*progname;
64 int	debug = 0;
65 int	nodaemon = 0;
66 
67 void	usage(void);
68 
69 #define	R_UNKNOWN	0
70 #define R_MICROSOFT	1
71 #define R_MOUSESYS	2
72 #define R_MMSERIES	3
73 #define R_LOGITECH	4
74 #define R_BUSMOUSE	5
75 #define R_LOGIMAN	6
76 #define R_PS_2		7
77 #define R_MMHITAB	8
78 
79 char	*rnames[] = {
80     "xxx",
81     "microsoft",
82     "mousesystems",
83     "mmseries",
84     "logitech",
85     "busmouse",
86     "mouseman",
87     "ps/2",
88     "mmhitab",
89     NULL
90 };
91 
92 unsigned short rodentcflags[] =
93 {
94     0,							/* nomouse */
95     (CS7	           | CREAD | CLOCAL | HUPCL ),	/* MicroSoft */
96     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* MouseSystems */
97     (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ),	/* MMSeries */
98     (CS8 | CSTOPB	   | CREAD | CLOCAL | HUPCL ),	/* Logitech */
99     0,							/* BusMouse */
100     (CS7		   | CREAD | CLOCAL | HUPCL ),	/* MouseMan */
101     0,							/* PS/2 */
102     (CS8		   | CREAD | CLOCAL | HUPCL ),	/* MMHitTablet */
103 };
104 
105 
106 typedef struct
107 {
108     int
109 	dx,dy,
110 	buttons;
111 } ACTIVITY;
112 
113 
114 struct rodentparam
115 {
116     int
117 	baudrate,
118 	samplerate,
119 	flags,
120 	rtype,
121 	lastbuttons,
122 	buttons,
123 	mfd,
124 	cleardtr,
125 	clearrts;
126 
127     char
128 	*portname;
129 
130 } rodent = { baudrate : 1200,
131 	     samplerate : 0,
132              flags : 0,
133              rtype : R_UNKNOWN,
134 	     lastbuttons : 0,
135 	     buttons : 0,
136 	     mfd : -1,
137 	     portname : NULL,
138 	     cleardtr : 0,
139 	     clearrts : 0};
140 
141 #define	ChordMiddle	1
142 
143 void		r_init(void);
144 ACTIVITY	*r_protocol(u_char b);
145 void		setmousespeed(int old, int new, unsigned cflag);
146 
147 void
148 main(int argc, char *argv[])
149 {
150     int			c,i,cfd;
151     u_char		b;
152     ACTIVITY		*act;
153     struct termios	t;
154     struct mouse_info 	mouse;
155     int			saved_buttons = 0;
156     fd_set		fds;
157 
158     progname = argv[0];
159 
160     while((c = getopt(argc,argv,"cdfsp:t:h?RDS:")) != EOF)
161 	switch(c)
162 	{
163 	case 'c':
164 	    rodent.flags |= ChordMiddle;
165 	    break;
166 
167 	case 'd':
168 	    debug = 1;
169 	    break;
170 
171 	case 'f':
172 	    nodaemon = 1;
173 	    break;
174 
175 	case 'p':
176 	    rodent.portname = optarg;
177 	    break;
178 
179 	case 's':
180 	    rodent.baudrate = 9600;
181 	    break;
182 
183 	case 'R':
184 	    rodent.clearrts = 1;
185 	    break;
186 
187 	case 'D':
188 	    rodent.cleardtr = 1;
189 	    break;
190 
191 	case 'S':
192 	    rodent.baudrate = atoi(optarg);
193 	    debug("rodent baudrate %d", rodent.baudrate);
194 	    break;
195 
196 	case 't':
197 	    for (i = 0; rnames[i]; i++)
198 		if (!strcmp(optarg,rnames[i]))
199 		{
200 		    debug("rodent is %s",rnames[i]);
201 		    rodent.rtype = i;
202 		    break;
203 		}
204 	    if (rnames[i])
205 		break;
206 	    warnx("no such mouse type `%s'",optarg);
207 	    usage();
208 
209 	case 'h':
210 	case '?':
211 	default:
212 	    usage();
213 	}
214 
215     switch(rodent.rtype)
216     {
217     case R_BUSMOUSE:
218 	if (!rodent.portname)
219 	    rodent.portname = "/dev/mse0";
220 	break;
221     case R_PS_2:
222 	if (!rodent.portname)
223 	    rodent.portname = "/dev/psm0";
224 	break;
225     default:
226 	if (rodent.portname)
227 	    break;
228 	warnx("No port name specified");
229 	usage();
230     }
231 
232     if ((rodent.mfd = open(rodent.portname, O_RDWR, 0)) == -1)
233     {
234 	warn("Can't open %s",rodent.portname);
235 	usage();
236     }
237     r_init();				/* call init function */
238 
239     if ((cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
240 	err(1, "open(/dev/consolectl)");
241 
242     if (!nodaemon)
243 	if (daemon(0,0))
244 	{
245 	    err(1, "daemon() failed");
246 	}
247 
248     for(;;)
249     {
250 	FD_ZERO(&fds);
251 	FD_SET(rodent.mfd,&fds);
252 	select(FD_SETSIZE,&fds,NULL,&fds,NULL);
253 	i = read(rodent.mfd,&b,1);	/* get a byte */
254 	if (i != 1)			/* read returned or error; goodbye */
255 	{
256 	    debug("read returned %d : %s exiting",i,strerror(errno));
257 	    close(rodent.mfd);
258 	    exit(1);
259 	}
260 	act = r_protocol(b);		/* pass byte to handler */
261 	if (act)			/* handler detected action */
262 	{
263 	    mouse.operation = MOUSE_ACTION;
264 	    mouse.u.data.x = act->dx;
265 	    mouse.u.data.y = act->dy;
266 	    mouse.u.data.buttons = act->buttons;
267 	    ioctl(cfd, CONS_MOUSECTL, &mouse);
268 	    debug("Activity : buttons 0x%02x  dx %d  dy %d",
269 		    act->buttons,act->dx,act->dy);
270 	}
271     }
272 }
273 
274 
275 /**
276  ** usage
277  **
278  ** Complain, and free the CPU for more worthy tasks
279  **/
280 void
281 usage(void)
282 {
283     fprintf(stderr,
284 	    " Usage is %s [options] -p <port> -t <mousetype>\n"
285 	    "  Options are   -s   Select 9600 baud mouse.\n"
286 	    "                -f   Don't become a daemon\n"
287 	    "                -d   Enable debugging messages\n"
288 	    "                -c   Enable ChordMiddle option\n"
289 	    "                -R   Lower RTS\n"
290 	    "                -D   Lower DTR\n"
291 	    "                -S baud  Select explicit baud (1200..9600).\n"
292 	    "  <mousetype> should be one of :\n"
293 	    "                microsoft\n"
294 	    "                mousesystems\n"
295 	    "                mmseries\n"
296 	    "                logitech\n"
297 	    "                busmouse\n"
298 	    "                mouseman\n"
299 	    "                ps/2\n"
300 	    "                mmhittab\n"
301 	    ,progname);
302 
303     exit(1);
304 }
305 
306 
307 /**
308  ** Mouse interface code, courtesy of XFree86 3.1.2.
309  **
310  ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
311  ** to clean, reformat and rationalise naming, it's quite possible that
312  ** some things in here have been broken.
313  **
314  ** I hope not 8)
315  **
316  ** The following code is derived from a module marked :
317  **/
318 
319 /* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
320 /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
321  17:03:40 dawes Exp $ */
322 /*
323  *
324  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
325  * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
326  *
327  * Permission to use, copy, modify, distribute, and sell this software and its
328  * documentation for any purpose is hereby granted without fee, provided that
329  * the above copyright notice appear in all copies and that both that
330  * copyright notice and this permission notice appear in supporting
331  * documentation, and that the names of Thomas Roell and David Dawes not be
332  * used in advertising or publicity pertaining to distribution of the
333  * software without specific, written prior permission.  Thomas Roell
334  * and David Dawes makes no representations about the suitability of this
335  * software for any purpose.  It is provided "as is" without express or
336  * implied warranty.
337  *
338  * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
339  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
340  * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
341  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
342  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
343  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
344  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
345  *
346  */
347 
348 
349 void
350 r_init(void)
351 {
352     /**
353      ** This comment is a little out of context here, but it contains
354      ** some useful information...
355      ********************************************************************
356      **
357      ** The following lines take care of the Logitech MouseMan protocols.
358      **
359      ** NOTE: There are different versions of both MouseMan and TrackMan!
360      **       Hence I add another protocol P_LOGIMAN, which the user can
361      **       specify as MouseMan in his XF86Config file. This entry was
362      **       formerly handled as a special case of P_MS. However, people
363      **       who don't have the middle button problem, can still specify
364      **       Microsoft and use P_MS.
365      **
366      ** By default, these mice should use a 3 byte Microsoft protocol
367      ** plus a 4th byte for the middle button. However, the mouse might
368      ** have switched to a different protocol before we use it, so I send
369      ** the proper sequence just in case.
370      **
371      ** NOTE: - all commands to (at least the European) MouseMan have to
372      **         be sent at 1200 Baud.
373      **       - each command starts with a '*'.
374      **       - whenever the MouseMan receives a '*', it will switch back
375      **	 to 1200 Baud. Hence I have to select the desired protocol
376      **	 first, then select the baud rate.
377      **
378      ** The protocols supported by the (European) MouseMan are:
379      **   -  5 byte packed binary protocol, as with the Mouse Systems
380      **      mouse. Selected by sequence "*U".
381      **   -  2 button 3 byte MicroSoft compatible protocol. Selected
382      **      by sequence "*V".
383      **   -  3 button 3+1 byte MicroSoft compatible protocol (default).
384      **      Selected by sequence "*X".
385      **
386      ** The following baud rates are supported:
387      **   -  1200 Baud (default). Selected by sequence "*n".
388      **   -  9600 Baud. Selected by sequence "*q".
389      **
390      ** Selecting a sample rate is no longer supported with the MouseMan!
391      ** Some additional lines in xf86Config.c take care of ill configured
392      ** baud rates and sample rates. (The user will get an error.)
393      */
394 
395 
396     if (rodent.rtype == R_LOGIMAN)
397     {
398 	setmousespeed(1200, 1200, rodentcflags[R_LOGIMAN]);
399 	write(rodent.mfd, "*X", 2);
400 	setmousespeed(1200, rodent.baudrate, rodentcflags[R_LOGIMAN]);
401     } else {
402 	if ((rodent.rtype != R_BUSMOUSE) && (rodent.rtype != R_PS_2))
403 	{
404 	    /* try all likely settings */
405 	    setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
406 	    setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
407 	    setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
408 	    setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
409 
410 	    if (rodent.rtype == R_LOGITECH) {
411 		write(rodent.mfd, "S", 1);
412 		setmousespeed(rodent.baudrate, rodent.baudrate,
413 			rodentcflags[R_MMSERIES]);
414 	    }
415 
416 	    if (rodent.rtype == R_MMHITAB) {
417 		char speedcmd;
418 	    /*
419 	     * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
420 	     * The tablet must be configured to be in MM mode, NO parity,
421 	     * Binary Format.  xf86Info.sampleRate controls the sensativity
422 	     * of the tablet.  We only use this tablet for it's 4-button puck
423 	     * so we don't run in "Absolute Mode"
424 	     */
425 		write(rodent.mfd, "z8", 2);	/* Set Parity = "NONE" */
426 		usleep(50000);
427 		write(rodent.mfd, "zb", 2);	/* Set Format = "Binary" */
428 		usleep(50000);
429 		write(rodent.mfd, "@", 1);	/* Set Report Mode = "Stream" */
430 		usleep(50000);
431 		write(rodent.mfd, "R", 1);	/* Set Output Rate = "45 rps" */
432 		usleep(50000);
433 		write(rodent.mfd, "I\x20", 2);	/* Set Incrememtal Mode "20" */
434 		usleep(50000);
435 		write(rodent.mfd, "E", 1);	/* Set Data Type = "Relative */
436 		usleep(50000);
437 
438 		/* These sample rates translate to 'lines per inch' on the
439 		   Hitachi tablet */
440 		if      (rodent.samplerate <=   40) speedcmd = 'g';
441 		else if (rodent.samplerate <=  100) speedcmd = 'd';
442 		else if (rodent.samplerate <=  200) speedcmd = 'e';
443 		else if (rodent.samplerate <=  500) speedcmd = 'h';
444 		else if (rodent.samplerate <= 1000) speedcmd = 'j';
445 		else                                speedcmd = 'd';
446 		write(rodent.mfd, &speedcmd, 1);
447 		usleep(50000);
448 
449 		write(rodent.mfd, "\021", 1);	/* Resume DATA output */
450 	    } else {
451 		if      (rodent.samplerate <= 0)   write(rodent.mfd, "O", 1);
452 		else if (rodent.samplerate <= 15)  write(rodent.mfd, "J", 1);
453 		else if (rodent.samplerate <= 27)  write(rodent.mfd, "K", 1);
454 		else if (rodent.samplerate <= 42)  write(rodent.mfd, "L", 1);
455 		else if (rodent.samplerate <= 60)  write(rodent.mfd, "R", 1);
456 		else if (rodent.samplerate <= 85)  write(rodent.mfd, "M", 1);
457 		else if (rodent.samplerate <= 125) write(rodent.mfd, "Q", 1);
458 		else				   write(rodent.mfd, "N", 1);
459 	    }
460 	}
461     }
462     if (rodent.rtype == R_MOUSESYS && (rodent.cleardtr))
463     {
464 	int val = TIOCM_DTR;
465 	ioctl(rodent.mfd, TIOCMBIC, &val);
466     }
467     if (rodent.rtype == R_MOUSESYS && (rodent.clearrts))
468     {
469 	int val = TIOCM_RTS;
470 	ioctl(rodent.mfd, TIOCMBIC, &val);
471     }
472 }
473 
474 ACTIVITY *
475 r_protocol(u_char rBuf)
476 {
477     static int           pBufP = 0;
478     static unsigned char pBuf[8];
479     static ACTIVITY	 act;
480 
481     static unsigned char proto[10][5] = {
482     /*  hd_mask hd_id   dp_mask dp_id   nobytes */
483     {	0,	0,	0,	0,	0	},  /* nomouse */
484     { 	0x40,	0x40,	0x40,	0x00,	3 	},  /* MicroSoft */
485     {	0xf8,	0x80,	0x00,	0x00,	5	},  /* MouseSystems */
486     {	0xe0,	0x80,	0x80,	0x00,	3	},  /* MMSeries */
487     {	0xe0,	0x80,	0x80,	0x00,	3	},  /* Logitech */
488     {	0xf8,	0x80,	0x00,	0x00,	5	},  /* BusMouse */
489     { 	0x40,	0x40,	0x40,	0x00,	3 	},  /* MouseMan */
490     {	0xc0,	0x00,	0x00,	0x00,	3	},  /* PS/2 mouse */
491     {	0xe0,	0x80,	0x80,	0x00,	3	},  /* MM_HitTablet */
492     };
493 
494     debug("received char 0x%x",(int)rBuf);
495 
496     /*
497      * Hack for resyncing: We check here for a package that is:
498      *  a) illegal (detected by wrong data-package header)
499      *  b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
500      *  c) bad header-package
501      *
502      * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
503      *       -128 are allowed, but since they are very seldom we can easily
504      *       use them as package-header with no button pressed.
505      * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
506      *         0x80 is not valid as a header byte. For a PS/2 mouse we skip
507      *         checking data bytes.
508      *         For resyncing a PS/2 mouse we require the two most significant
509      *         bits in the header byte to be 0. These are the overflow bits,
510      *         and in case of an overflow we actually lose sync. Overflows
511      *         are very rare, however, and we quickly gain sync again after
512      *         an overflow condition. This is the best we can do. (Actually,
513      *         we could use bit 0x08 in the header byte for resyncing, since
514      *         that bit is supposed to be always on, but nobody told
515      *         Microsoft...)
516      */
517 
518     if (pBufP != 0 && rodent.rtype != R_PS_2 &&
519 	((rBuf & proto[rodent.rtype][2]) != proto[rodent.rtype][3]
520 	 || rBuf == 0x80))
521     {
522 	pBufP = 0;		/* skip package */
523     }
524 
525     if (pBufP == 0 &&
526 	(rBuf & proto[rodent.rtype][0]) != proto[rodent.rtype][1])
527     {
528 	/*
529 	 * Hack for Logitech MouseMan Mouse - Middle button
530 	 *
531 	 * Unfortunately this mouse has variable length packets: the standard
532 	 * Microsoft 3 byte packet plus an optional 4th byte whenever the
533 	 * middle button status changes.
534 	 *
535 	 * We have already processed the standard packet with the movement
536 	 * and button info.  Now post an event message with the old status
537 	 * of the left and right buttons and the updated middle button.
538 	 */
539 
540 	/*
541 	 * Even worse, different MouseMen and TrackMen differ in the 4th
542 	 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
543 	 * 0x02/0x22, so I have to strip off the lower bits.
544 	 */
545 	if ((rodent.rtype == R_MICROSOFT || rodent.rtype == R_LOGIMAN)
546 	    && (char)(rBuf & ~0x23) == 0)
547 	{
548 	    act.buttons = ((int)(rBuf & 0x20) >> 4)
549 		| (rodent.lastbuttons & 0x05);
550 	    rodent.lastbuttons = act.buttons;	/* save new button state */
551 	    return(&act);
552 	}
553 
554 	return(NULL);				/* skip package */
555     }
556 
557     pBuf[pBufP++] = rBuf;
558     if (pBufP != proto[rodent.rtype][4]) return(NULL);
559 
560     /*
561      * assembly full package
562      */
563 
564     debug("Assembled full packet (len %d) %x,%x,%x,%x,%x",
565 	proto[rodent.rtype][4], pBuf[0],pBuf[1],pBuf[2],pBuf[3],pBuf[4]);
566 
567     switch(rodent.rtype)
568     {
569     case R_LOGIMAN:		/* MouseMan / TrackMan */
570     case R_MICROSOFT:		/* Microsoft */
571 	if (rodent.flags & ChordMiddle)
572 	    act.buttons = (((int) pBuf[0] & 0x30) == 0x30) ? 2 :
573 		           ((int)(pBuf[0]&0x20)>>3) | ((int)(pBuf[0]&0x10)>>4);
574 	else
575 	    act.buttons =   (rodent.lastbuttons & 2)
576 		          | ((int)(pBuf[0] & 0x20) >> 3)
577 		          | ((int)(pBuf[0] & 0x10) >> 4);
578 	act.dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
579 	act.dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
580 	break;
581 
582     case R_MOUSESYS:		/* Mouse Systems Corp */
583 	act.buttons = (~pBuf[0]) & 0x07;
584 	act.dx =    (char)(pBuf[1]) + (char)(pBuf[3]);
585 	act.dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
586 	break;
587 
588     case R_MMHITAB:		/* MM_HitTablet */
589 	act.buttons = pBuf[0] & 0x07;
590 	if (act.buttons != 0)
591 	    act.buttons = 1 << (act.buttons - 1);
592 	act.dx = (pBuf[0] & 0x10) ?   pBuf[1] : - pBuf[1];
593 	act.dy = (pBuf[0] & 0x08) ? - pBuf[2] :   pBuf[2];
594 	break;
595 
596     case R_MMSERIES:		/* MM Series */
597     case R_LOGITECH:		/* Logitech Mice */
598 	act.buttons = pBuf[0] & 0x07;
599 	act.dx = (pBuf[0] & 0x10) ?   pBuf[1] : - pBuf[1];
600 	act.dy = (pBuf[0] & 0x08) ? - pBuf[2] :   pBuf[2];
601 	break;
602 
603     case R_BUSMOUSE:		/* BusMouse */
604 	act.buttons = (~pBuf[0]) & 0x07;
605 	act.dx =   (char)pBuf[1];
606 	act.dy = - (char)pBuf[2];
607 	break;
608 
609     case R_PS_2:		/* PS/2 mouse */
610 	act.buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */
611 	              (pBuf[0] & 0x02) >> 1 | /* Right */
612 		      (pBuf[0] & 0x01) << 2; /* Left */
613 	act.dx = (pBuf[0] & 0x10) ?    pBuf[1]-256  :  pBuf[1];
614 	act.dy = (pBuf[0] & 0x20) ?  -(pBuf[2]-256) : -pBuf[2];
615 	break;
616     }
617     pBufP = 0;
618     return(&act);
619 }
620 
621 /* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
622 /* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
623 /*
624  * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
625  *
626  * Permission to use, copy, modify, distribute, and sell this software and its
627  * documentation for any purpose is hereby granted without fee, provided that
628  * the above copyright notice appear in all copies and that both that
629  * copyright notice and this permission notice appear in supporting
630  * documentation, and that the name of David Dawes
631  * not be used in advertising or publicity pertaining to distribution of
632  * the software without specific, written prior permission.
633  * David Dawes makes no representations about the suitability of this
634  * software for any purpose.  It is provided "as is" without express or
635  * implied warranty.
636  *
637  * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
638  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
639  * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
640  * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
641  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
642  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
643  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
644  *
645  */
646 
647 
648 void
649 setmousespeed(old, new, cflag)
650 int old;
651 int new;
652 unsigned cflag;
653 {
654 	struct termios tty;
655 	char *c;
656 
657 	if (tcgetattr(rodent.mfd, &tty) < 0)
658 	{
659 		err(1, "Warning: unable to get status of mouse fd");
660 	}
661 
662 	tty.c_iflag = IGNBRK | IGNPAR;
663 	tty.c_oflag = 0;
664 	tty.c_lflag = 0;
665 	tty.c_cflag = (tcflag_t)cflag;
666 	tty.c_cc[VTIME] = 0;
667 	tty.c_cc[VMIN] = 1;
668 
669 	switch (old)
670 	{
671 	case 9600:
672 		cfsetispeed(&tty, B9600);
673 		cfsetospeed(&tty, B9600);
674 		break;
675 	case 4800:
676 		cfsetispeed(&tty, B4800);
677 		cfsetospeed(&tty, B4800);
678 		break;
679 	case 2400:
680 		cfsetispeed(&tty, B2400);
681 		cfsetospeed(&tty, B2400);
682 		break;
683 	case 1200:
684 	default:
685 		cfsetispeed(&tty, B1200);
686 		cfsetospeed(&tty, B1200);
687 	}
688 
689 	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
690 	{
691 		err(1, "Unable to set status of mouse fd");
692 	}
693 
694 	switch (new)
695 	{
696 	case 9600:
697 		c = "*q";
698 		cfsetispeed(&tty, B9600);
699 		cfsetospeed(&tty, B9600);
700 		break;
701 	case 4800:
702 		c = "*p";
703 		cfsetispeed(&tty, B4800);
704 		cfsetospeed(&tty, B4800);
705 		break;
706 	case 2400:
707 		c = "*o";
708 		cfsetispeed(&tty, B2400);
709 		cfsetospeed(&tty, B2400);
710 		break;
711 	case 1200:
712 	default:
713 		c = "*n";
714 		cfsetispeed(&tty, B1200);
715 		cfsetospeed(&tty, B1200);
716 	}
717 
718 	if (rodent.rtype == R_LOGIMAN || rodent.rtype == R_LOGITECH)
719 	{
720 		if (write(rodent.mfd, c, 2) != 2)
721 		{
722 			err(1, "Unable to write to mouse fd");
723 		}
724 	}
725 	usleep(100000);
726 
727 	if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
728 	{
729 		err(1,"Unable to set status of mouse fd");
730 	}
731 }
732