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