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