xref: /illumos-gate/usr/src/uts/sun/io/ms.c (revision 166fc0161da8f2aef0ff36cc5241a32f8f0cf3bc)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Mouse streams module.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/signal.h>
357c478bd9Sstevel@tonic-gate #include <sys/termios.h>
367c478bd9Sstevel@tonic-gate #include <sys/termio.h>
377c478bd9Sstevel@tonic-gate #include <sys/stream.h>
387c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
397c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
407c478bd9Sstevel@tonic-gate #include <sys/tty.h>
417c478bd9Sstevel@tonic-gate #include <sys/strtty.h>
427c478bd9Sstevel@tonic-gate #include <sys/time.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/file.h>
457c478bd9Sstevel@tonic-gate #include <sys/uio.h>
467c478bd9Sstevel@tonic-gate #include <sys/errno.h>
477c478bd9Sstevel@tonic-gate #include <sys/debug.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <sys/vuid_event.h>
507c478bd9Sstevel@tonic-gate #include <sys/msreg.h>
517c478bd9Sstevel@tonic-gate #include <sys/msio.h>
527c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
537c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * This is the loadable module wrapper.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static struct streamtab ms_info;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
657c478bd9Sstevel@tonic-gate 	"ms",
667c478bd9Sstevel@tonic-gate 	&ms_info,
677c478bd9Sstevel@tonic-gate 	D_MP | D_MTPERMOD
687c478bd9Sstevel@tonic-gate };
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
757c478bd9Sstevel@tonic-gate 	&mod_strmodops, "streams module for mouse", &fsw
767c478bd9Sstevel@tonic-gate };
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
797c478bd9Sstevel@tonic-gate 	MODREV_1, &modlstrmod, NULL
807c478bd9Sstevel@tonic-gate };
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate int
_init(void)847c478bd9Sstevel@tonic-gate _init(void)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate int
_fini(void)907c478bd9Sstevel@tonic-gate _fini(void)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	return (EBUSY);
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)967c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	BYTECLIP(x)	(char)((x) > 127 ? 127 : ((x) < -128 ? -128 : (x)))
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate struct msdata {
1047c478bd9Sstevel@tonic-gate 	struct ms_softc	msd_softc;
1057c478bd9Sstevel@tonic-gate 	queue_t	*msd_readq;	/* upstream read queue */
1067c478bd9Sstevel@tonic-gate 	mblk_t	*msd_iocpending; /* "ioctl" awaiting buffer */
1077c478bd9Sstevel@tonic-gate 	int	msd_flags;	/* random flags */
1087c478bd9Sstevel@tonic-gate 	int	msd_iocid;	/* ID of "ioctl" being waited for */
1097c478bd9Sstevel@tonic-gate 	int	msd_iocerror;	/* error return from "ioctl" */
1107c478bd9Sstevel@tonic-gate 	char	msd_oldbutt;	/* button state at last sample */
1117c478bd9Sstevel@tonic-gate 	short	msd_state;	/* state counter for input routine */
1127c478bd9Sstevel@tonic-gate 	short	msd_jitter;
1137c478bd9Sstevel@tonic-gate 	timeout_id_t	msd_timeout_id;	/* id returned by timeout() */
1147c478bd9Sstevel@tonic-gate 	bufcall_id_t	msd_reioctl_id;	/* id returned by bufcall() */
1157c478bd9Sstevel@tonic-gate 	bufcall_id_t	msd_resched_id;	/* id returned by bufcall() */
1167c478bd9Sstevel@tonic-gate 	int	msd_baud_rate;	/* mouse baud rate */
1177c478bd9Sstevel@tonic-gate 	int	msd_rcnt_baud_chng; /* baud changed recently */
1187c478bd9Sstevel@tonic-gate 	int	msd_data_pkt_cnt; /* no of packets since last baud change */
1197c478bd9Sstevel@tonic-gate 	int	msd_qenable_more; /* enable msrserv if baud changed recently */
1207c478bd9Sstevel@tonic-gate 	int	msd_hold_baud_stup; /* # of packets to wait for baud setup */
1217c478bd9Sstevel@tonic-gate };
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate #define	MS_OPEN		0x00000001	/* mouse is open for business */
1247c478bd9Sstevel@tonic-gate #define	MS_IOCWAIT	0x00000002	/* "open" waiting for ioctl to finish */
1257c478bd9Sstevel@tonic-gate #define	MS_IOCTOSS	0x00000004	/* Toss ioctl returns */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * Input routine states. See msinput().
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate #define	MS_WAIT_BUTN	0
1317c478bd9Sstevel@tonic-gate #define	MS_WAIT_X	1
1327c478bd9Sstevel@tonic-gate #define	MS_WAIT_Y	2
1337c478bd9Sstevel@tonic-gate #define	MS_WAIT_X2	3
1347c478bd9Sstevel@tonic-gate #define	MS_WAIT_Y2	4
1357c478bd9Sstevel@tonic-gate #define	MS_PKT_SZ	5
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate  * This module supports mice runing at 1200, 4800 and 9600 baud rates.
1397c478bd9Sstevel@tonic-gate  *
1407c478bd9Sstevel@tonic-gate  * If there was a baud change recently, then we want to wait
1417c478bd9Sstevel@tonic-gate  * for some time to make sure that no other baud change is on its way.
1427c478bd9Sstevel@tonic-gate  * If the second baud rate change is done then the packets between
1437c478bd9Sstevel@tonic-gate  * changes are garbage and are thrown away during the baud change.
1447c478bd9Sstevel@tonic-gate  */
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * The following #defines were tuned by experimentations.
1477c478bd9Sstevel@tonic-gate  */
1487c478bd9Sstevel@tonic-gate #define		MS_HOLD_BAUD_STUP	48
1497c478bd9Sstevel@tonic-gate #define		MS_CNT_TOB1200		7
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static int	ms_overrun_msg;	/* Message when overrun circular buffer */
1537c478bd9Sstevel@tonic-gate static int	ms_overrun_cnt;	/* Increment when overrun circular buffer */
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * Max pixel delta of jitter controlled. As this number increases the jumpiness
1577c478bd9Sstevel@tonic-gate  * of the ms increases, i.e., the coarser the motion for medium speeds.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static int	ms_jitter_thresh = 0;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate  * ms_jitter_thresh is the maximum number of jitters suppressed. Thus,
1637c478bd9Sstevel@tonic-gate  * hz/ms_jitter_thresh is the maximum interval of jitters suppressed. As
1647c478bd9Sstevel@tonic-gate  * ms_jitter_thresh increases, a wider range of jitter is suppressed. However,
1657c478bd9Sstevel@tonic-gate  * the more inertia the mouse seems to have, i.e., the slower the mouse is to
1667c478bd9Sstevel@tonic-gate  * react.
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * Measure how many (ms_speed_count) ms deltas exceed threshold
1717c478bd9Sstevel@tonic-gate  * (ms_speedlimit). If ms_speedlaw then throw away deltas over ms_speedlimit.
1727c478bd9Sstevel@tonic-gate  * This is to keep really bad mice that jump around from getting too far.
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate static int	ms_speedlimit = 48;
1757c478bd9Sstevel@tonic-gate static int	ms_speedlaw = 0;
1767c478bd9Sstevel@tonic-gate static int	ms_speed_count;
1777c478bd9Sstevel@tonic-gate static int	msjitterrate = 12;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate #define	JITTER_TIMEOUT (hz/msjitterrate)
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate static clock_t	msjittertimeout; /* Timeout used when mstimeout in effect */
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * Mouse buffer size in bytes.  Place here as variable so that one could
1857c478bd9Sstevel@tonic-gate  * massage it using adb if it turns out to be too small.
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate static int	MS_BUF_BYTES = 4096;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate static int	MS_DEBUG;
1917c478bd9Sstevel@tonic-gate 
192*166fc016SToomas Soome static int msopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp);
1937c478bd9Sstevel@tonic-gate static int msclose(queue_t *q, int flag, cred_t *credp);
194*166fc016SToomas Soome static int mswput(queue_t *q, mblk_t *mp);
195*166fc016SToomas Soome static int msrput(queue_t *q, mblk_t *mp);
196*166fc016SToomas Soome static int msrserv(queue_t *q);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate static struct module_info msmiinfo = {
1997c478bd9Sstevel@tonic-gate 	0,
2007c478bd9Sstevel@tonic-gate 	"ms",
2017c478bd9Sstevel@tonic-gate 	0,
2027c478bd9Sstevel@tonic-gate 	INFPSZ,
2037c478bd9Sstevel@tonic-gate 	2048,
2047c478bd9Sstevel@tonic-gate 	128
2057c478bd9Sstevel@tonic-gate };
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static struct qinit msrinit = {
208*166fc016SToomas Soome 	msrput,
209*166fc016SToomas Soome 	msrserv,
2107c478bd9Sstevel@tonic-gate 	msopen,
2117c478bd9Sstevel@tonic-gate 	msclose,
212*166fc016SToomas Soome 	NULL,
2137c478bd9Sstevel@tonic-gate 	&msmiinfo
2147c478bd9Sstevel@tonic-gate };
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate static struct module_info msmoinfo = {
2177c478bd9Sstevel@tonic-gate 	0,
2187c478bd9Sstevel@tonic-gate 	"ms",
2197c478bd9Sstevel@tonic-gate 	0,
2207c478bd9Sstevel@tonic-gate 	INFPSZ,
2217c478bd9Sstevel@tonic-gate 	2048,
2227c478bd9Sstevel@tonic-gate 	128
2237c478bd9Sstevel@tonic-gate };
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static struct qinit mswinit = {
226*166fc016SToomas Soome 	mswput,
227*166fc016SToomas Soome 	NULL,
2287c478bd9Sstevel@tonic-gate 	msopen,
2297c478bd9Sstevel@tonic-gate 	msclose,
230*166fc016SToomas Soome 	NULL,
2317c478bd9Sstevel@tonic-gate 	&msmoinfo
2327c478bd9Sstevel@tonic-gate };
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static struct streamtab ms_info = {
2357c478bd9Sstevel@tonic-gate 	&msrinit,
2367c478bd9Sstevel@tonic-gate 	&mswinit,
2377c478bd9Sstevel@tonic-gate 	NULL,
2387c478bd9Sstevel@tonic-gate 	NULL,
2397c478bd9Sstevel@tonic-gate };
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate static void	msresched(void *);
2427c478bd9Sstevel@tonic-gate static void	msreioctl(void *);
2437c478bd9Sstevel@tonic-gate static void	msioctl(queue_t *q, mblk_t *mp);
244*166fc016SToomas Soome static int	ms_getparms(Ms_parms *data);
245*166fc016SToomas Soome static int	ms_setparms(Ms_parms *data);
2467c478bd9Sstevel@tonic-gate static void	msflush(struct msdata *msd);
247*166fc016SToomas Soome static void	msinput(struct msdata *msd, char c);
2487c478bd9Sstevel@tonic-gate static void	msincr(void *);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate /*
2517c478bd9Sstevel@tonic-gate  * Dummy qbufcall callback routine used by open and close.
2527c478bd9Sstevel@tonic-gate  * The framework will wake up qwait_sig when we return from
2537c478bd9Sstevel@tonic-gate  * this routine (as part of leaving the perimeters.)
2547c478bd9Sstevel@tonic-gate  * (The framework enters the perimeters before calling the qbufcall() callback
2557c478bd9Sstevel@tonic-gate  * and leaves the perimeters after the callback routine has executed. The
2567c478bd9Sstevel@tonic-gate  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
2577c478bd9Sstevel@tonic-gate  * when it leaves the perimeter. See qwait(9E).)
2587c478bd9Sstevel@tonic-gate  */
2597c478bd9Sstevel@tonic-gate /* ARGSUSED */
2607c478bd9Sstevel@tonic-gate static void
dummy_callback(void * arg)2617c478bd9Sstevel@tonic-gate dummy_callback(void *arg)
262*166fc016SToomas Soome {
263*166fc016SToomas Soome }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate  * Open a mouse.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2697c478bd9Sstevel@tonic-gate static int
msopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)270*166fc016SToomas Soome msopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
2717c478bd9Sstevel@tonic-gate {
272*166fc016SToomas Soome 	struct mousebuf *b;
273*166fc016SToomas Soome 	struct ms_softc *ms;
274*166fc016SToomas Soome 	struct msdata *msd;
2757c478bd9Sstevel@tonic-gate 	mblk_t	 *mp;
2767c478bd9Sstevel@tonic-gate 	mblk_t	 *datap;
277*166fc016SToomas Soome 	struct iocblk *iocb;
278*166fc016SToomas Soome 	struct termios *cb;
2797c478bd9Sstevel@tonic-gate 	int error = 0;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL)
2827c478bd9Sstevel@tonic-gate 		return (0);		/* already attached */
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if (sflag != MODOPEN)
2857c478bd9Sstevel@tonic-gate 		return (EINVAL);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	/*
2887c478bd9Sstevel@tonic-gate 	 * Allocate an msdata structure.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	msd = kmem_zalloc(sizeof (struct msdata), KM_SLEEP);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/*
2937c478bd9Sstevel@tonic-gate 	 * Set up queue pointers, so that the "put" procedure will accept
2947c478bd9Sstevel@tonic-gate 	 * the reply to the "ioctl" message we send down.
2957c478bd9Sstevel@tonic-gate 	 */
2967c478bd9Sstevel@tonic-gate 	q->q_ptr = msd;
2977c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = msd;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	qprocson(q);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/*
3027c478bd9Sstevel@tonic-gate 	 * Setup tty modes.
3037c478bd9Sstevel@tonic-gate 	 */
3047c478bd9Sstevel@tonic-gate 	while ((mp = mkiocb(TCSETSF)) == NULL) {
3057c478bd9Sstevel@tonic-gate 		bufcall_id_t id = qbufcall(q, sizeof (struct iocblk),
3067c478bd9Sstevel@tonic-gate 		    BPRI_HI, dummy_callback, NULL);
3077c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
3087c478bd9Sstevel@tonic-gate 			qunbufcall(q, id);
3097c478bd9Sstevel@tonic-gate 			kmem_free(msd, sizeof (struct msdata));
3107c478bd9Sstevel@tonic-gate 			qprocsoff(q);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 			return (EINTR);
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 	while ((datap = allocb(sizeof (struct termios), BPRI_HI)) == NULL) {
3167c478bd9Sstevel@tonic-gate 		bufcall_id_t id = qbufcall(q, sizeof (struct termios),
3177c478bd9Sstevel@tonic-gate 		    BPRI_HI, dummy_callback, NULL);
3187c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
3197c478bd9Sstevel@tonic-gate 			qunbufcall(q, id);
3207c478bd9Sstevel@tonic-gate 			freemsg(mp);
3217c478bd9Sstevel@tonic-gate 			kmem_free(msd, sizeof (struct msdata));
3227c478bd9Sstevel@tonic-gate 			qprocsoff(q);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			return (EINTR);
3257c478bd9Sstevel@tonic-gate 		}
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	iocb = (struct iocblk *)mp->b_rptr;
3307c478bd9Sstevel@tonic-gate 	iocb->ioc_count = sizeof (struct termios);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	cb = (struct termios *)datap->b_wptr;
3337c478bd9Sstevel@tonic-gate 	cb->c_iflag = 0;
3347c478bd9Sstevel@tonic-gate 	cb->c_oflag = 0;
3357c478bd9Sstevel@tonic-gate 	cb->c_cflag = CREAD|CS8|B9600;
3367c478bd9Sstevel@tonic-gate 	cb->c_lflag = 0;
3377c478bd9Sstevel@tonic-gate 	bzero(cb->c_cc, NCCS);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	datap->b_wptr += sizeof (*cb);
3407c478bd9Sstevel@tonic-gate 	datap->b_datap->db_type = M_DATA;
3417c478bd9Sstevel@tonic-gate 	mp->b_cont = datap;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	msd->msd_flags |= MS_IOCWAIT;	/* indicate that we're waiting for */
3447c478bd9Sstevel@tonic-gate 	msd->msd_iocid = iocb->ioc_id;	/* this response */
3457c478bd9Sstevel@tonic-gate 	msd->msd_baud_rate = B9600;
3467c478bd9Sstevel@tonic-gate 	msd->msd_rcnt_baud_chng = 1;
3477c478bd9Sstevel@tonic-gate 	msd->msd_data_pkt_cnt = 0;
3487c478bd9Sstevel@tonic-gate 	msd->msd_qenable_more = 0;
3497c478bd9Sstevel@tonic-gate 	msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP;
3507c478bd9Sstevel@tonic-gate 	putnext(WR(q), mp);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	ms = &msd->msd_softc;
3537c478bd9Sstevel@tonic-gate 	/*
3547c478bd9Sstevel@tonic-gate 	 * Now wait for it.  Let our read queue put routine wake us up
3557c478bd9Sstevel@tonic-gate 	 * when it arrives.
3567c478bd9Sstevel@tonic-gate 	 */
3577c478bd9Sstevel@tonic-gate 	while (msd->msd_flags & MS_IOCWAIT) {
3587c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
3597c478bd9Sstevel@tonic-gate 			error = EINTR;
3607c478bd9Sstevel@tonic-gate 			goto error;
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 	if ((error = msd->msd_iocerror) != 0)
3647c478bd9Sstevel@tonic-gate 		goto error;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * Set up private data.
3687c478bd9Sstevel@tonic-gate 	 */
3697c478bd9Sstevel@tonic-gate 	msd->msd_state = MS_WAIT_BUTN;
3707c478bd9Sstevel@tonic-gate 	msd->msd_readq = q;
3717c478bd9Sstevel@tonic-gate 	msd->msd_iocpending = NULL;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	/*
3747c478bd9Sstevel@tonic-gate 	 * Allocate buffer and initialize data.
3757c478bd9Sstevel@tonic-gate 	 */
3767c478bd9Sstevel@tonic-gate 	if (ms->ms_buf == 0) {
3777c478bd9Sstevel@tonic-gate 		ms->ms_bufbytes = MS_BUF_BYTES;
3787c478bd9Sstevel@tonic-gate 		b = kmem_zalloc((uint_t)ms->ms_bufbytes, KM_SLEEP);
3797c478bd9Sstevel@tonic-gate 		b->mb_size = 1 + (ms->ms_bufbytes - sizeof (struct mousebuf))
3807c478bd9Sstevel@tonic-gate 		    / sizeof (struct mouseinfo);
3817c478bd9Sstevel@tonic-gate 		ms->ms_buf = b;
3827c478bd9Sstevel@tonic-gate 		ms->ms_vuidaddr = VKEY_FIRST;
3837c478bd9Sstevel@tonic-gate 		msjittertimeout = JITTER_TIMEOUT;
3847c478bd9Sstevel@tonic-gate 		msflush(msd);
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	msd->msd_flags = MS_OPEN;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/*
3907c478bd9Sstevel@tonic-gate 	 * Tell the module below us that it should return input immediately.
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	(void) putnextctl1(WR(q), M_CTL, MC_SERVICEIMM);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	return (0);
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate error:
3977c478bd9Sstevel@tonic-gate 	qprocsoff(q);
3987c478bd9Sstevel@tonic-gate 	kmem_free(msd, sizeof (struct msdata));
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return (error);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate  * Close the mouse
4057c478bd9Sstevel@tonic-gate  */
4067c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
4077c478bd9Sstevel@tonic-gate static int
msclose(queue_t * q,int flag,cred_t * credp)408*166fc016SToomas Soome msclose(queue_t *q, int flag, cred_t *credp)
4097c478bd9Sstevel@tonic-gate {
410*166fc016SToomas Soome 	struct msdata *msd = (struct msdata *)q->q_ptr;
411*166fc016SToomas Soome 	struct ms_softc *ms;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/*
4147c478bd9Sstevel@tonic-gate 	 * Tell the module below us that it need not return input immediately.
4157c478bd9Sstevel@tonic-gate 	 */
4167c478bd9Sstevel@tonic-gate 	(void) putnextctl1(q, M_CTL, MC_SERVICEDEF);
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	qprocsoff(q);
4197c478bd9Sstevel@tonic-gate 	/*
4207c478bd9Sstevel@tonic-gate 	 * Since we're about to destroy our private data, turn off
4217c478bd9Sstevel@tonic-gate 	 * our open flag first, so we don't accept any more input
4227c478bd9Sstevel@tonic-gate 	 * and try to use that data.
4237c478bd9Sstevel@tonic-gate 	 */
4247c478bd9Sstevel@tonic-gate 	msd->msd_flags = 0;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	if (msd->msd_jitter) {
4277c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, msd->msd_timeout_id);
4287c478bd9Sstevel@tonic-gate 		msd->msd_jitter = 0;
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 	if (msd->msd_reioctl_id) {
4317c478bd9Sstevel@tonic-gate 		qunbufcall(q, msd->msd_reioctl_id);
4327c478bd9Sstevel@tonic-gate 		msd->msd_reioctl_id = 0;
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 	if (msd->msd_resched_id) {
4357c478bd9Sstevel@tonic-gate 		qunbufcall(q, msd->msd_resched_id);
4367c478bd9Sstevel@tonic-gate 		msd->msd_resched_id = 0;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	if (msd->msd_iocpending != NULL) {
4397c478bd9Sstevel@tonic-gate 		/*
4407c478bd9Sstevel@tonic-gate 		 * We were holding an "ioctl" response pending the
4417c478bd9Sstevel@tonic-gate 		 * availability of an "mblk" to hold data to be passed up;
4427c478bd9Sstevel@tonic-gate 		 * another "ioctl" came through, which means that "ioctl"
4437c478bd9Sstevel@tonic-gate 		 * must have timed out or been aborted.
4447c478bd9Sstevel@tonic-gate 		 */
4457c478bd9Sstevel@tonic-gate 		freemsg(msd->msd_iocpending);
4467c478bd9Sstevel@tonic-gate 		msd->msd_iocpending = NULL;
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 	ms = &msd->msd_softc;
4497c478bd9Sstevel@tonic-gate 	/* Free mouse buffer */
4507c478bd9Sstevel@tonic-gate 	if (ms->ms_buf != NULL)
4517c478bd9Sstevel@tonic-gate 		kmem_free(ms->ms_buf, (uint_t)ms->ms_bufbytes);
4527c478bd9Sstevel@tonic-gate 	/* Free msdata structure */
4537c478bd9Sstevel@tonic-gate 	kmem_free((void *)msd, sizeof (*msd));
4547c478bd9Sstevel@tonic-gate 	return (0);
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate  * Read queue service routine.
4597c478bd9Sstevel@tonic-gate  * Turn buffered mouse events into stream messages.
4607c478bd9Sstevel@tonic-gate  */
461*166fc016SToomas Soome static int
msrserv(queue_t * q)462*166fc016SToomas Soome msrserv(queue_t *q)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	struct msdata *msd = (struct msdata *)q->q_ptr;
465*166fc016SToomas Soome 	struct ms_softc *ms;
466*166fc016SToomas Soome 	struct mousebuf *b;
467*166fc016SToomas Soome 	struct mouseinfo *mi;
468*166fc016SToomas Soome 	int    button_number;
469*166fc016SToomas Soome 	int    hwbit;
4707c478bd9Sstevel@tonic-gate 	mblk_t	 *bp;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/*
4737c478bd9Sstevel@tonic-gate 	 * Handle the case of a queue which is backenabled before
4747c478bd9Sstevel@tonic-gate 	 * initialization is complete.
4757c478bd9Sstevel@tonic-gate 	 */
4767c478bd9Sstevel@tonic-gate 	if (!(msd->msd_flags & MS_OPEN)) {
477*166fc016SToomas Soome 		return (1);
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	ms = &msd->msd_softc;
4817c478bd9Sstevel@tonic-gate 	b = ms->ms_buf;
4827c478bd9Sstevel@tonic-gate 	if (msd->msd_rcnt_baud_chng && ms->ms_oldoff != b->mb_off) {
4837c478bd9Sstevel@tonic-gate 		int	no_pkt = b->mb_off - ms->ms_oldoff;
4847c478bd9Sstevel@tonic-gate 		int	i;
4857c478bd9Sstevel@tonic-gate 		no_pkt = no_pkt > 0 ? no_pkt : (b->mb_size - no_pkt);
4867c478bd9Sstevel@tonic-gate 		if (no_pkt < msd->msd_hold_baud_stup) {
4877c478bd9Sstevel@tonic-gate 			msd->msd_qenable_more = 1;
488*166fc016SToomas Soome 			return (0);
4897c478bd9Sstevel@tonic-gate 		} else {
4907c478bd9Sstevel@tonic-gate 			/*
4917c478bd9Sstevel@tonic-gate 			 * throw away packets in beginning (mostly garbage)
4927c478bd9Sstevel@tonic-gate 			 */
4937c478bd9Sstevel@tonic-gate 			for (i = 0; i < msd->msd_hold_baud_stup; i++) {
4947c478bd9Sstevel@tonic-gate 				ms->ms_oldoff++;	/* next event */
4957c478bd9Sstevel@tonic-gate 				/* circular buffer wraparound */
4967c478bd9Sstevel@tonic-gate 				if (ms->ms_oldoff >= b->mb_size)
4977c478bd9Sstevel@tonic-gate 					ms->ms_oldoff = 0;
4987c478bd9Sstevel@tonic-gate 			}
4997c478bd9Sstevel@tonic-gate 			msd->msd_rcnt_baud_chng = 0;
5007c478bd9Sstevel@tonic-gate 			msd->msd_data_pkt_cnt = 0;
5017c478bd9Sstevel@tonic-gate 			msd->msd_qenable_more = 0;
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 	while (canputnext(q) && ms->ms_oldoff != b->mb_off) {
5057c478bd9Sstevel@tonic-gate 		mi = &b->mb_info[ms->ms_oldoff];
5067c478bd9Sstevel@tonic-gate 		switch (ms->ms_readformat) {
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		case MS_3BYTE_FORMAT: {
509*166fc016SToomas Soome 			char *cp;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 			if ((bp = allocb(3, BPRI_HI)) != NULL) {
5127c478bd9Sstevel@tonic-gate 				cp = (char *)bp->b_wptr;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 				*cp++ = 0x80 | mi->mi_buttons;
5157c478bd9Sstevel@tonic-gate 				/* Update read buttons */
5167c478bd9Sstevel@tonic-gate 				ms->ms_prevbuttons = mi->mi_buttons;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 				*cp++ = mi->mi_x;
5197c478bd9Sstevel@tonic-gate 				*cp++ = -mi->mi_y;
5207c478bd9Sstevel@tonic-gate 				/* lower pri to avoid mouse droppings */
5217c478bd9Sstevel@tonic-gate 				bp->b_wptr = (uchar_t *)cp;
5227c478bd9Sstevel@tonic-gate 				putnext(q, bp);
5237c478bd9Sstevel@tonic-gate 			} else {
5247c478bd9Sstevel@tonic-gate 				if (msd->msd_resched_id)
5257c478bd9Sstevel@tonic-gate 					qunbufcall(q, msd->msd_resched_id);
5267c478bd9Sstevel@tonic-gate 				msd->msd_resched_id = qbufcall(q, 3, BPRI_HI,
5277c478bd9Sstevel@tonic-gate 				    msresched, msd);
5287c478bd9Sstevel@tonic-gate 				if (msd->msd_resched_id == 0)
529*166fc016SToomas Soome 					return (0);	/* try again later */
5307c478bd9Sstevel@tonic-gate 				/* bufcall failed; just pitch this event */
5317c478bd9Sstevel@tonic-gate 				/* or maybe flush queue? */
5327c478bd9Sstevel@tonic-gate 			}
5337c478bd9Sstevel@tonic-gate 			ms->ms_oldoff++;	/* next event */
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 			/* circular buffer wraparound */
5367c478bd9Sstevel@tonic-gate 			if (ms->ms_oldoff >= b->mb_size)
5377c478bd9Sstevel@tonic-gate 				ms->ms_oldoff = 0;
5387c478bd9Sstevel@tonic-gate 			break;
5397c478bd9Sstevel@tonic-gate 		}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 		case MS_VUID_FORMAT: {
542*166fc016SToomas Soome 			Firm_event *fep;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 			bp = NULL;
5457c478bd9Sstevel@tonic-gate 			switch (ms->ms_eventstate) {
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 			case EVENT_BUT3:
5487c478bd9Sstevel@tonic-gate 			case EVENT_BUT2:
5497c478bd9Sstevel@tonic-gate 			case EVENT_BUT1:
5507c478bd9Sstevel@tonic-gate 			    /* Test the button. Send an event if it changed. */
5517c478bd9Sstevel@tonic-gate 			    button_number = ms->ms_eventstate - EVENT_BUT1;
5527c478bd9Sstevel@tonic-gate 			    hwbit = MS_HW_BUT1 >> button_number;
5537c478bd9Sstevel@tonic-gate 			    if ((ms->ms_prevbuttons & hwbit) !=
5547c478bd9Sstevel@tonic-gate 				(mi->mi_buttons & hwbit)) {
5557c478bd9Sstevel@tonic-gate 			    if ((bp = allocb(sizeof (Firm_event),
5567c478bd9Sstevel@tonic-gate 						BPRI_HI)) != NULL) {
5577c478bd9Sstevel@tonic-gate 				    fep = (Firm_event *)bp->b_wptr;
5587c478bd9Sstevel@tonic-gate 				    fep->id = vuid_id_addr(ms->ms_vuidaddr) |
5597c478bd9Sstevel@tonic-gate 					vuid_id_offset(BUT(1) + button_number);
5607c478bd9Sstevel@tonic-gate 				    fep->pair_type = FE_PAIR_NONE;
5617c478bd9Sstevel@tonic-gate 				    fep->pair = 0;
5627c478bd9Sstevel@tonic-gate 				    /* Update read buttons and set value */
5637c478bd9Sstevel@tonic-gate 				    if (mi->mi_buttons & hwbit) {
5647c478bd9Sstevel@tonic-gate 					fep->value = 0;
5657c478bd9Sstevel@tonic-gate 					ms->ms_prevbuttons |= hwbit;
5667c478bd9Sstevel@tonic-gate 				    } else {
5677c478bd9Sstevel@tonic-gate 					fep->value = 1;
5687c478bd9Sstevel@tonic-gate 					ms->ms_prevbuttons &= ~hwbit;
5697c478bd9Sstevel@tonic-gate 				    }
5707c478bd9Sstevel@tonic-gate 				    fep->time = mi->mi_time;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 				} else {
5737c478bd9Sstevel@tonic-gate 				    if (msd->msd_resched_id)
5747c478bd9Sstevel@tonic-gate 					qunbufcall(q, msd->msd_resched_id);
5757c478bd9Sstevel@tonic-gate 				    msd->msd_resched_id = qbufcall(q,
5767c478bd9Sstevel@tonic-gate 					sizeof (Firm_event),
5777c478bd9Sstevel@tonic-gate 					BPRI_HI, msresched, msd);
5787c478bd9Sstevel@tonic-gate 				    if (msd->msd_resched_id == 0)
579*166fc016SToomas Soome 					return (0);	/* try again later */
5807c478bd9Sstevel@tonic-gate 				    /* bufcall failed; just pitch this event */
5817c478bd9Sstevel@tonic-gate 				    /* or maybe flush queue? */
5827c478bd9Sstevel@tonic-gate 				    ms->ms_eventstate = EVENT_X;
5837c478bd9Sstevel@tonic-gate 				}
5847c478bd9Sstevel@tonic-gate 			    }
5857c478bd9Sstevel@tonic-gate 			    break;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 			case EVENT_Y:
5887c478bd9Sstevel@tonic-gate 			    /* Send y if changed. */
5897c478bd9Sstevel@tonic-gate 			    if (mi->mi_y != 0) {
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 				if ((bp = allocb(sizeof (Firm_event),
5927c478bd9Sstevel@tonic-gate 						BPRI_HI)) != NULL) {
5937c478bd9Sstevel@tonic-gate 				    fep = (Firm_event *)bp->b_wptr;
5947c478bd9Sstevel@tonic-gate 				    fep->id = vuid_id_addr(ms->ms_vuidaddr) |
5957c478bd9Sstevel@tonic-gate 					    vuid_id_offset(LOC_Y_DELTA);
5967c478bd9Sstevel@tonic-gate 				    fep->pair_type = FE_PAIR_ABSOLUTE;
5977c478bd9Sstevel@tonic-gate 				    fep->pair = (uchar_t)LOC_Y_ABSOLUTE;
5987c478bd9Sstevel@tonic-gate 				    fep->value = -mi->mi_y;
5997c478bd9Sstevel@tonic-gate 				    fep->time = mi->mi_time;
6007c478bd9Sstevel@tonic-gate 				} else {
6017c478bd9Sstevel@tonic-gate 				    if (msd->msd_resched_id)
6027c478bd9Sstevel@tonic-gate 					qunbufcall(q, msd->msd_resched_id);
6037c478bd9Sstevel@tonic-gate 				    msd->msd_resched_id = qbufcall(q,
6047c478bd9Sstevel@tonic-gate 					sizeof (Firm_event),
6057c478bd9Sstevel@tonic-gate 					BPRI_HI, msresched, msd);
6067c478bd9Sstevel@tonic-gate 				    if (msd->msd_resched_id == 0)
607*166fc016SToomas Soome 					return (0);	/* try again later */
6087c478bd9Sstevel@tonic-gate 				    /* bufcall failed; just pitch this event */
6097c478bd9Sstevel@tonic-gate 				    /* or maybe flush queue? */
6107c478bd9Sstevel@tonic-gate 				    ms->ms_eventstate = EVENT_X;
6117c478bd9Sstevel@tonic-gate 				}
6127c478bd9Sstevel@tonic-gate 			    }
6137c478bd9Sstevel@tonic-gate 			    break;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 			case EVENT_X:
6167c478bd9Sstevel@tonic-gate 			    /* Send x if changed. */
6177c478bd9Sstevel@tonic-gate 			    if (mi->mi_x != 0) {
6187c478bd9Sstevel@tonic-gate 				if ((bp = allocb(sizeof (Firm_event),
6197c478bd9Sstevel@tonic-gate 						BPRI_HI)) != NULL) {
6207c478bd9Sstevel@tonic-gate 				    fep = (Firm_event *)bp->b_wptr;
6217c478bd9Sstevel@tonic-gate 				    fep->id = vuid_id_addr(ms->ms_vuidaddr) |
6227c478bd9Sstevel@tonic-gate 					    vuid_id_offset(LOC_X_DELTA);
6237c478bd9Sstevel@tonic-gate 				    fep->pair_type = FE_PAIR_ABSOLUTE;
6247c478bd9Sstevel@tonic-gate 				    fep->pair = (uchar_t)LOC_X_ABSOLUTE;
6257c478bd9Sstevel@tonic-gate 				    fep->value = mi->mi_x;
6267c478bd9Sstevel@tonic-gate 				    fep->time = mi->mi_time;
6277c478bd9Sstevel@tonic-gate 				} else {
6287c478bd9Sstevel@tonic-gate 				    if (msd->msd_resched_id)
6297c478bd9Sstevel@tonic-gate 					qunbufcall(q, msd->msd_resched_id);
6307c478bd9Sstevel@tonic-gate 				    msd->msd_resched_id = qbufcall(q,
6317c478bd9Sstevel@tonic-gate 					sizeof (Firm_event),
6327c478bd9Sstevel@tonic-gate 					BPRI_HI, msresched, msd);
6337c478bd9Sstevel@tonic-gate 				    if (msd->msd_resched_id == 0)
634*166fc016SToomas Soome 					return (0);	/* try again later */
6357c478bd9Sstevel@tonic-gate 				    /* bufcall failed; just pitch this event */
6367c478bd9Sstevel@tonic-gate 				    /* or maybe flush queue? */
6377c478bd9Sstevel@tonic-gate 				    ms->ms_eventstate = EVENT_X;
6387c478bd9Sstevel@tonic-gate 				}
6397c478bd9Sstevel@tonic-gate 			    }
6407c478bd9Sstevel@tonic-gate 			    break;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 			}
6437c478bd9Sstevel@tonic-gate 			if (bp != NULL) {
6447c478bd9Sstevel@tonic-gate 			    /* lower pri to avoid mouse droppings */
6457c478bd9Sstevel@tonic-gate 			    bp->b_wptr += sizeof (Firm_event);
6467c478bd9Sstevel@tonic-gate 			    putnext(q, bp);
6477c478bd9Sstevel@tonic-gate 			}
6487c478bd9Sstevel@tonic-gate 			if (ms->ms_eventstate == EVENT_X) {
6497c478bd9Sstevel@tonic-gate 			    ms->ms_eventstate = EVENT_BUT3;
6507c478bd9Sstevel@tonic-gate 			    ms->ms_oldoff++;	/* next event */
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 			    /* circular buffer wraparound */
6537c478bd9Sstevel@tonic-gate 			    if (ms->ms_oldoff >= b->mb_size)
6547c478bd9Sstevel@tonic-gate 				ms->ms_oldoff = 0;
6557c478bd9Sstevel@tonic-gate 			} else
6567c478bd9Sstevel@tonic-gate 			    ms->ms_eventstate--;
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 	}
660*166fc016SToomas Soome 	return (0);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate static void
msresched(void * msdptr)6647c478bd9Sstevel@tonic-gate msresched(void *msdptr)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	queue_t *q;
6677c478bd9Sstevel@tonic-gate 	struct msdata *msd = msdptr;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	msd->msd_resched_id = 0;
6707c478bd9Sstevel@tonic-gate 	if ((q = msd->msd_readq) != 0)
6717c478bd9Sstevel@tonic-gate 		qenable(q);	/* run the service procedure */
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate  * Line discipline output queue put procedure: handles M_IOCTL
6767c478bd9Sstevel@tonic-gate  * messages.
6777c478bd9Sstevel@tonic-gate  */
678*166fc016SToomas Soome static int
mswput(queue_t * q,mblk_t * mp)679*166fc016SToomas Soome mswput(queue_t *q, mblk_t *mp)
6807c478bd9Sstevel@tonic-gate {
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	/*
6837c478bd9Sstevel@tonic-gate 	 * Process M_FLUSH, and some M_IOCTL, messages here; pass
6847c478bd9Sstevel@tonic-gate 	 * everything else down.
6857c478bd9Sstevel@tonic-gate 	 */
6867c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	case M_FLUSH:
6897c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
6907c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
6917c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
6927c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
6936937e379SToomas Soome 		/* FALLTHROUGH */
6947c478bd9Sstevel@tonic-gate 	default:
6957c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it down the line */
6967c478bd9Sstevel@tonic-gate 		break;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	case M_IOCTL:
6997c478bd9Sstevel@tonic-gate 		msioctl(q, mp);
7007c478bd9Sstevel@tonic-gate 		break;
7017c478bd9Sstevel@tonic-gate 	}
702*166fc016SToomas Soome 	return (0);
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate static void
msreioctl(void * msdptr)7067c478bd9Sstevel@tonic-gate msreioctl(void *msdptr)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	struct msdata *msd = msdptr;
7097c478bd9Sstevel@tonic-gate 	queue_t *q;
7107c478bd9Sstevel@tonic-gate 	mblk_t *mp;
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	msd->msd_reioctl_id = 0;
7137c478bd9Sstevel@tonic-gate 	q = msd->msd_readq;
7147c478bd9Sstevel@tonic-gate 	if ((mp = msd->msd_iocpending) != NULL) {
7157c478bd9Sstevel@tonic-gate 		msd->msd_iocpending = NULL;	/* not pending any more */
7167c478bd9Sstevel@tonic-gate 		msioctl(WR(q), mp);
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate static void
msioctl(queue_t * q,mblk_t * mp)721*166fc016SToomas Soome msioctl(queue_t *q, mblk_t *mp)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	struct msdata		*msd;
724*166fc016SToomas Soome 	struct ms_softc *ms;
725*166fc016SToomas Soome 	struct iocblk	*iocp;
7267c478bd9Sstevel@tonic-gate 	Vuid_addr_probe		*addr_probe;
7277c478bd9Sstevel@tonic-gate 	uint_t			ioctlrespsize;
7287c478bd9Sstevel@tonic-gate 	int			err = 0;
7297c478bd9Sstevel@tonic-gate 	mblk_t			*datap;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	msd = (struct msdata *)q->q_ptr;
7327c478bd9Sstevel@tonic-gate 	if (msd == NULL) {
7337c478bd9Sstevel@tonic-gate 		err = EINVAL;
7347c478bd9Sstevel@tonic-gate 		goto out;
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 	ms = &msd->msd_softc;
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	if (MS_DEBUG)
7417c478bd9Sstevel@tonic-gate 		printf("mswput(M_IOCTL,%x)\n", iocp->ioc_cmd);
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
7447c478bd9Sstevel@tonic-gate 	case VUIDSFORMAT:
7457c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7467c478bd9Sstevel@tonic-gate 		if (err != 0)
7477c478bd9Sstevel@tonic-gate 			break;
7487c478bd9Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr == ms->ms_readformat)
7497c478bd9Sstevel@tonic-gate 			break;
7507c478bd9Sstevel@tonic-gate 		ms->ms_readformat = *(int *)mp->b_cont->b_rptr;
7517c478bd9Sstevel@tonic-gate 		/*
7527c478bd9Sstevel@tonic-gate 		 * Flush mouse buffer because the messages upstream of us
7537c478bd9Sstevel@tonic-gate 		 * are in the old format.
7547c478bd9Sstevel@tonic-gate 		 */
7557c478bd9Sstevel@tonic-gate 		msflush(msd);
7567c478bd9Sstevel@tonic-gate 		break;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	case VUIDGFORMAT:
7597c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
7607c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
7617c478bd9Sstevel@tonic-gate 			goto allocfailure;
7627c478bd9Sstevel@tonic-gate 		}
7637c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = ms->ms_readformat;
7647c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
7657c478bd9Sstevel@tonic-gate 		if (mp->b_cont != NULL)
7667c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
7677c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
7687c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
7697c478bd9Sstevel@tonic-gate 		break;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	case VUIDSADDR:
7727c478bd9Sstevel@tonic-gate 	case VUIDGADDR:
7737c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
7747c478bd9Sstevel@tonic-gate 		if (err != 0)
7757c478bd9Sstevel@tonic-gate 			break;
7767c478bd9Sstevel@tonic-gate 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
7777c478bd9Sstevel@tonic-gate 		if (addr_probe->base != VKEY_FIRST) {
7787c478bd9Sstevel@tonic-gate 			err = ENODEV;
7797c478bd9Sstevel@tonic-gate 			break;
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 		if (iocp->ioc_cmd == VUIDSADDR)
7827c478bd9Sstevel@tonic-gate 			ms->ms_vuidaddr = addr_probe->data.next;
7837c478bd9Sstevel@tonic-gate 		else
7847c478bd9Sstevel@tonic-gate 			addr_probe->data.current = ms->ms_vuidaddr;
7857c478bd9Sstevel@tonic-gate 		break;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	case MSIOGETPARMS:
7887c478bd9Sstevel@tonic-gate 		if (MS_DEBUG)
7897c478bd9Sstevel@tonic-gate 			printf("ms_getparms\n");
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (Ms_parms), BPRI_HI)) == NULL) {
7927c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (Ms_parms);
7937c478bd9Sstevel@tonic-gate 			goto allocfailure;
7947c478bd9Sstevel@tonic-gate 		}
7957c478bd9Sstevel@tonic-gate 		err = ms_getparms((Ms_parms *)datap->b_wptr);
7967c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (Ms_parms);
7977c478bd9Sstevel@tonic-gate 		if (mp->b_cont != NULL)
7987c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
7997c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
8007c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (Ms_parms);
8017c478bd9Sstevel@tonic-gate 		break;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	case MSIOSETPARMS:
8047c478bd9Sstevel@tonic-gate 		if (MS_DEBUG)
8057c478bd9Sstevel@tonic-gate 			printf("ms_setparms\n");
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (Ms_parms));
8087c478bd9Sstevel@tonic-gate 		if (err != 0)
8097c478bd9Sstevel@tonic-gate 			break;
8107c478bd9Sstevel@tonic-gate 		err = ms_setparms((Ms_parms *)mp->b_cont->b_rptr);
8117c478bd9Sstevel@tonic-gate 		break;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	default:
8147c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it down the line */
8157c478bd9Sstevel@tonic-gate 		return;
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate out:
8197c478bd9Sstevel@tonic-gate 	if (err != 0)
8207c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, err);
8217c478bd9Sstevel@tonic-gate 	else {
8227c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
8237c478bd9Sstevel@tonic-gate 		iocp->ioc_error = 0;	/* brain rot */
8247c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
8257c478bd9Sstevel@tonic-gate 		qreply(q, mp);
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate 	return;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate allocfailure:
8307c478bd9Sstevel@tonic-gate 	/*
8317c478bd9Sstevel@tonic-gate 	 * We needed to allocate something to handle this "ioctl", but
8327c478bd9Sstevel@tonic-gate 	 * couldn't; save this "ioctl" and arrange to get called back when
8337c478bd9Sstevel@tonic-gate 	 * it's more likely that we can get what we need.
8347c478bd9Sstevel@tonic-gate 	 * If there's already one being saved, throw it out, since it
8357c478bd9Sstevel@tonic-gate 	 * must have timed out.
8367c478bd9Sstevel@tonic-gate 	 */
8377c478bd9Sstevel@tonic-gate 	if (msd->msd_iocpending != NULL)
8387c478bd9Sstevel@tonic-gate 		freemsg(msd->msd_iocpending);
8397c478bd9Sstevel@tonic-gate 	msd->msd_iocpending = mp;
8407c478bd9Sstevel@tonic-gate 	if (msd->msd_reioctl_id)
8417c478bd9Sstevel@tonic-gate 		qunbufcall(q, msd->msd_reioctl_id);
8427c478bd9Sstevel@tonic-gate 	msd->msd_reioctl_id = qbufcall(q, ioctlrespsize, BPRI_HI,
8437c478bd9Sstevel@tonic-gate 	    msreioctl, msd);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate static int
ms_getparms(Ms_parms * data)847*166fc016SToomas Soome ms_getparms(Ms_parms *data)
8487c478bd9Sstevel@tonic-gate {
8497c478bd9Sstevel@tonic-gate 	data->jitter_thresh = ms_jitter_thresh;
8507c478bd9Sstevel@tonic-gate 	data->speed_law = ms_speedlaw;
8517c478bd9Sstevel@tonic-gate 	data->speed_limit = ms_speedlimit;
8527c478bd9Sstevel@tonic-gate 	return (0);
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate static int
ms_setparms(Ms_parms * data)856*166fc016SToomas Soome ms_setparms(Ms_parms *data)
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate 	ms_jitter_thresh = data->jitter_thresh;
8597c478bd9Sstevel@tonic-gate 	ms_speedlaw = data->speed_law;
8607c478bd9Sstevel@tonic-gate 	ms_speedlimit = data->speed_limit;
8617c478bd9Sstevel@tonic-gate 	return (0);
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate static void
msflush(struct msdata * msd)865*166fc016SToomas Soome msflush(struct msdata *msd)
8667c478bd9Sstevel@tonic-gate {
867*166fc016SToomas Soome 	struct ms_softc *ms = &msd->msd_softc;
868*166fc016SToomas Soome 	queue_t *q;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	ms->ms_oldoff = 0;
8717c478bd9Sstevel@tonic-gate 	ms->ms_eventstate = EVENT_BUT3;
8727c478bd9Sstevel@tonic-gate 	ms->ms_buf->mb_off = 0;
8737c478bd9Sstevel@tonic-gate 	ms->ms_prevbuttons = MS_HW_BUT1 | MS_HW_BUT2 | MS_HW_BUT3;
8747c478bd9Sstevel@tonic-gate 	msd->msd_oldbutt = ms->ms_prevbuttons;
8757c478bd9Sstevel@tonic-gate 	if ((q = msd->msd_readq) != NULL && q->q_next != NULL)
8767c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate /*
8817c478bd9Sstevel@tonic-gate  * Mouse read queue put procedure.
8827c478bd9Sstevel@tonic-gate  */
883*166fc016SToomas Soome static int
msrput(queue_t * q,mblk_t * mp)884*166fc016SToomas Soome msrput(queue_t *q, mblk_t *mp)
8857c478bd9Sstevel@tonic-gate {
886*166fc016SToomas Soome 	struct msdata *msd = (struct msdata *)q->q_ptr;
887*166fc016SToomas Soome 	mblk_t *bp;
888*166fc016SToomas Soome 	char *readp;
889*166fc016SToomas Soome 	mblk_t *imp;
890*166fc016SToomas Soome 	mblk_t *datap;
891*166fc016SToomas Soome 	struct iocblk *iocb;
892*166fc016SToomas Soome 	struct termios *cb;
8937c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	if (msd == 0)
896*166fc016SToomas Soome 		return (0);
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	case M_FLUSH:
9017c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
9027c478bd9Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
9037c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
9047c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
9056937e379SToomas Soome 		/* FALLTHROUGH */
9067c478bd9Sstevel@tonic-gate 	default:
9077c478bd9Sstevel@tonic-gate 		putnext(q, mp);
908*166fc016SToomas Soome 		return (0);
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	case M_BREAK:
9117c478bd9Sstevel@tonic-gate 		if (msd->msd_flags & MS_IOCTOSS) {
9127c478bd9Sstevel@tonic-gate 			freemsg(mp);
913*166fc016SToomas Soome 			return (0);
9147c478bd9Sstevel@tonic-gate 		}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 		if (msd->msd_rcnt_baud_chng && msd->msd_data_pkt_cnt == 0) {
9177c478bd9Sstevel@tonic-gate 			freemsg(mp);
918*166fc016SToomas Soome 			return (0);
9197c478bd9Sstevel@tonic-gate 		}
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 		/*
9227c478bd9Sstevel@tonic-gate 		 * If we are sampling a 4800 baud mouse at 9600,
9237c478bd9Sstevel@tonic-gate 		 * we want to wait for long time because there is no
9247c478bd9Sstevel@tonic-gate 		 * fixed timeframe for receiving break. If we are sampling
9257c478bd9Sstevel@tonic-gate 		 * a 1200 baud mouse at 4800 or 9600 baud rate then
9267c478bd9Sstevel@tonic-gate 		 * it is guaranteed that break will be received very soon.
9277c478bd9Sstevel@tonic-gate 		 */
9287c478bd9Sstevel@tonic-gate 		if (msd->msd_rcnt_baud_chng) {
9297c478bd9Sstevel@tonic-gate 			switch (msd->msd_baud_rate) {
9307c478bd9Sstevel@tonic-gate 			case B9600:
9317c478bd9Sstevel@tonic-gate 				msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP/2;
9327c478bd9Sstevel@tonic-gate 				msd->msd_baud_rate = B4800;
9337c478bd9Sstevel@tonic-gate 				break;
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 			case B4800:
9367c478bd9Sstevel@tonic-gate 				if (msd->msd_data_pkt_cnt <= MS_CNT_TOB1200) {
9377c478bd9Sstevel@tonic-gate 					msd->msd_hold_baud_stup =
9387c478bd9Sstevel@tonic-gate 						MS_HOLD_BAUD_STUP/6;
9397c478bd9Sstevel@tonic-gate 					msd->msd_baud_rate = B1200;
9407c478bd9Sstevel@tonic-gate 				} else {
9417c478bd9Sstevel@tonic-gate 					msd->msd_hold_baud_stup =
9427c478bd9Sstevel@tonic-gate 						MS_HOLD_BAUD_STUP;
9437c478bd9Sstevel@tonic-gate 					msd->msd_baud_rate = B9600;
9447c478bd9Sstevel@tonic-gate 				}
9457c478bd9Sstevel@tonic-gate 				break;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 			case B1200:
9487c478bd9Sstevel@tonic-gate 			default:
9497c478bd9Sstevel@tonic-gate 				msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP;
9507c478bd9Sstevel@tonic-gate 				msd->msd_baud_rate = B9600;
9517c478bd9Sstevel@tonic-gate 				break;
9527c478bd9Sstevel@tonic-gate 			}
9537c478bd9Sstevel@tonic-gate 		} else {
9547c478bd9Sstevel@tonic-gate 			msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP;
9557c478bd9Sstevel@tonic-gate 			msd->msd_baud_rate = B9600;
9567c478bd9Sstevel@tonic-gate 		}
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 		/*
9597c478bd9Sstevel@tonic-gate 		 * Change baud rate.
9607c478bd9Sstevel@tonic-gate 		 */
9617c478bd9Sstevel@tonic-gate 		if ((imp = mkiocb(TCSETSF)) == NULL) {
962*166fc016SToomas Soome 			return (0);
9637c478bd9Sstevel@tonic-gate 		}
9647c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (struct termios),
9657c478bd9Sstevel@tonic-gate 		    BPRI_HI)) == NULL) {
9667c478bd9Sstevel@tonic-gate 			freemsg(imp);
967*166fc016SToomas Soome 			return (0);
9687c478bd9Sstevel@tonic-gate 		}
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		iocb = (struct iocblk *)imp->b_rptr;
9717c478bd9Sstevel@tonic-gate 		iocb->ioc_count = sizeof (struct termios);
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		cb = (struct termios *)datap->b_rptr;
9747c478bd9Sstevel@tonic-gate 		cb->c_iflag = 0;
9757c478bd9Sstevel@tonic-gate 		cb->c_oflag = 0;
9767c478bd9Sstevel@tonic-gate 		cb->c_cflag = CREAD|CS8|msd->msd_baud_rate;
9777c478bd9Sstevel@tonic-gate 		cb->c_lflag = 0;
9787c478bd9Sstevel@tonic-gate 		bzero(cb->c_cc, NCCS);
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (*cb);
9817c478bd9Sstevel@tonic-gate 		datap->b_datap->db_type = M_DATA;
9827c478bd9Sstevel@tonic-gate 		imp->b_cont = datap;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 		msd->msd_flags |= MS_IOCTOSS|MS_IOCWAIT;
9857c478bd9Sstevel@tonic-gate 		msd->msd_iocid = iocb->ioc_id;
9867c478bd9Sstevel@tonic-gate 		msflush(msd);
9877c478bd9Sstevel@tonic-gate 		flushq(q, FLUSHALL);
9887c478bd9Sstevel@tonic-gate 		putnext(WR(q), imp);
9897c478bd9Sstevel@tonic-gate 		freemsg(mp);
9907c478bd9Sstevel@tonic-gate 		msd->msd_rcnt_baud_chng = 1;
9917c478bd9Sstevel@tonic-gate 		msd->msd_data_pkt_cnt = 0;
9927c478bd9Sstevel@tonic-gate 		if (MS_DEBUG)
9937c478bd9Sstevel@tonic-gate 			printf("baud %x\n", msd->msd_baud_rate);
994*166fc016SToomas Soome 		return (0);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	case M_IOCACK:
9977c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
9987c478bd9Sstevel@tonic-gate 		/*
9997c478bd9Sstevel@tonic-gate 		 * If we are doing an "ioctl" ourselves, check if this
10007c478bd9Sstevel@tonic-gate 		 * is the reply to that code.  If so, wake up the
10017c478bd9Sstevel@tonic-gate 		 * "open" routine, and toss the reply, otherwise just
10027c478bd9Sstevel@tonic-gate 		 * pass it up.
10037c478bd9Sstevel@tonic-gate 		 */
10047c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
10057c478bd9Sstevel@tonic-gate 		if (!(msd->msd_flags & MS_IOCWAIT) ||
10067c478bd9Sstevel@tonic-gate 		    iocp->ioc_id != msd->msd_iocid) {
10077c478bd9Sstevel@tonic-gate 			/*
10087c478bd9Sstevel@tonic-gate 			 * This isn't the reply we're looking for.  Move along.
10097c478bd9Sstevel@tonic-gate 			 */
10107c478bd9Sstevel@tonic-gate 			putnext(q, mp);
10117c478bd9Sstevel@tonic-gate 		} else {
10127c478bd9Sstevel@tonic-gate 			msd->msd_flags &= ~MS_IOCWAIT;
10137c478bd9Sstevel@tonic-gate 			msd->msd_iocerror = iocp->ioc_error;
10147c478bd9Sstevel@tonic-gate 			/*
10157c478bd9Sstevel@tonic-gate 			 * If we sent down a request to change the baud rate.
10167c478bd9Sstevel@tonic-gate 			 * This is the reply.  Just ignore it.
10177c478bd9Sstevel@tonic-gate 			 */
10187c478bd9Sstevel@tonic-gate 			if (msd->msd_flags & MS_IOCTOSS) {
10197c478bd9Sstevel@tonic-gate 				msd->msd_flags &= ~MS_IOCTOSS;
10207c478bd9Sstevel@tonic-gate 				msflush(msd);
10217c478bd9Sstevel@tonic-gate 				flushq(q, FLUSHALL);
10227c478bd9Sstevel@tonic-gate 			}
10237c478bd9Sstevel@tonic-gate 			freemsg(mp);
10247c478bd9Sstevel@tonic-gate 		}
1025*166fc016SToomas Soome 		return (0);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	case M_DATA:
10287c478bd9Sstevel@tonic-gate 		if ((msd->msd_flags & MS_IOCTOSS) ||
10297c478bd9Sstevel@tonic-gate 		    !(msd->msd_flags & MS_OPEN)) {
10307c478bd9Sstevel@tonic-gate 			freemsg(mp);
1031*166fc016SToomas Soome 			return (0);
10327c478bd9Sstevel@tonic-gate 		}
10337c478bd9Sstevel@tonic-gate 		break;
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	/*
10377c478bd9Sstevel@tonic-gate 	 * A data message, consisting of bytes from the mouse.
10387c478bd9Sstevel@tonic-gate 	 * Hand each byte to our input routine.
10397c478bd9Sstevel@tonic-gate 	 */
10407c478bd9Sstevel@tonic-gate 	bp = mp;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	do {
10437c478bd9Sstevel@tonic-gate 		readp = (char *)bp->b_rptr;
10447c478bd9Sstevel@tonic-gate 		while (readp < (char *)bp->b_wptr) {
10457c478bd9Sstevel@tonic-gate 			if (msd->msd_rcnt_baud_chng)
10467c478bd9Sstevel@tonic-gate 				msd->msd_data_pkt_cnt++;
10477c478bd9Sstevel@tonic-gate 			msinput(msd, *readp++);
10487c478bd9Sstevel@tonic-gate 		}
10497c478bd9Sstevel@tonic-gate 		bp->b_rptr = (unsigned char *)readp;
10507c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	freemsg(mp);
1053*166fc016SToomas Soome 	return (0);
10547c478bd9Sstevel@tonic-gate }
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate /*
10577c478bd9Sstevel@tonic-gate  * Mouse input routine; process a byte received from a mouse and
10587c478bd9Sstevel@tonic-gate  * assemble into a mouseinfo message for the window system.
10597c478bd9Sstevel@tonic-gate  *
10607c478bd9Sstevel@tonic-gate  * The MSC mice send a five-byte packet organized as
10617c478bd9Sstevel@tonic-gate  *	button, dx, dy, dx, dy
10627c478bd9Sstevel@tonic-gate  * where dx and dy can be any signed byte value. The mouseinfo message
10637c478bd9Sstevel@tonic-gate  * is organized as
10647c478bd9Sstevel@tonic-gate  *	dx, dy, button, timestamp
10657c478bd9Sstevel@tonic-gate  * Our strategy is to add up the 2 dx and the 2 dy in the five-byte
10667c478bd9Sstevel@tonic-gate  * packet, then send the mouseinfo message up.
10677c478bd9Sstevel@tonic-gate  *
10687c478bd9Sstevel@tonic-gate  * Basic algorithm: throw away bytes until we get a [potential]
10697c478bd9Sstevel@tonic-gate  * button byte. Collect button; Collect dx1; Collect dy1; Collect dx2
10707c478bd9Sstevel@tonic-gate  * and add it to dx1; Collect dy2 and add it to dy1; Send button,
10717c478bd9Sstevel@tonic-gate  * dx, dy, timestamp.
10727c478bd9Sstevel@tonic-gate  *
10737c478bd9Sstevel@tonic-gate  * Watch out for overflow!
10747c478bd9Sstevel@tonic-gate  */
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate static void
msinput(struct msdata * msd,char c)1077*166fc016SToomas Soome msinput(struct msdata *msd, char c)
10787c478bd9Sstevel@tonic-gate {
1079*166fc016SToomas Soome 	struct ms_softc *ms;
1080*166fc016SToomas Soome 	struct mousebuf *b;
1081*166fc016SToomas Soome 	struct mouseinfo *mi;
1082*166fc016SToomas Soome 	int    jitter_radius;
1083*166fc016SToomas Soome 	int    temp;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	ms = &msd->msd_softc;
10867c478bd9Sstevel@tonic-gate 	b = ms->ms_buf;
10877c478bd9Sstevel@tonic-gate 	if (b == NULL)
10887c478bd9Sstevel@tonic-gate 		return;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	mi = &b->mb_info[b->mb_off];
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	switch (msd->msd_state) {
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	case MS_WAIT_BUTN:
10957c478bd9Sstevel@tonic-gate 		if ((c & 0xf8) != 0x80) {
10967c478bd9Sstevel@tonic-gate 			if (MS_DEBUG)
10977c478bd9Sstevel@tonic-gate 				printf("Mouse input char %x discarded\n",
10987c478bd9Sstevel@tonic-gate 					(int)c & 0xff);
10997c478bd9Sstevel@tonic-gate 			if (msd->msd_rcnt_baud_chng) {
11007c478bd9Sstevel@tonic-gate 				msflush(msd);
11017c478bd9Sstevel@tonic-gate 				flushq(msd->msd_readq, FLUSHALL);
11027c478bd9Sstevel@tonic-gate 				msd->msd_hold_baud_stup++;
11037c478bd9Sstevel@tonic-gate 			}
11047c478bd9Sstevel@tonic-gate 			return;
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		/*
11087c478bd9Sstevel@tonic-gate 		 * Probably a button byte.
11097c478bd9Sstevel@tonic-gate 		 * Lower 3 bits are left, middle, right.
11107c478bd9Sstevel@tonic-gate 		 */
11117c478bd9Sstevel@tonic-gate 		mi->mi_buttons = c & (MS_HW_BUT1 | MS_HW_BUT2 | MS_HW_BUT3);
11127c478bd9Sstevel@tonic-gate 		break;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	case MS_WAIT_X:
11157c478bd9Sstevel@tonic-gate 		/*
11167c478bd9Sstevel@tonic-gate 		 * Delta X byte.  Add the delta X from this sample to
11177c478bd9Sstevel@tonic-gate 		 * the delta X we're accumulating in the current event.
11187c478bd9Sstevel@tonic-gate 		 */
11197c478bd9Sstevel@tonic-gate 		temp = (int)(mi->mi_x + c);
11207c478bd9Sstevel@tonic-gate 		mi->mi_x = BYTECLIP(temp);
11217c478bd9Sstevel@tonic-gate 		uniqtime32(&mi->mi_time); /* record time when sample arrived */
11227c478bd9Sstevel@tonic-gate 		break;
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	case MS_WAIT_Y:
11257c478bd9Sstevel@tonic-gate 		/*
11267c478bd9Sstevel@tonic-gate 		 * Delta Y byte.  Add the delta Y from this sample to
11277c478bd9Sstevel@tonic-gate 		 * the delta Y we're accumulating in the current event.
11287c478bd9Sstevel@tonic-gate 		 * (Subtract, actually, because the mouse reports
11297c478bd9Sstevel@tonic-gate 		 * increasing Y up the screen.)
11307c478bd9Sstevel@tonic-gate 		 */
11317c478bd9Sstevel@tonic-gate 		temp = (int)(mi->mi_y - c);
11327c478bd9Sstevel@tonic-gate 		mi->mi_y = BYTECLIP(temp);
11337c478bd9Sstevel@tonic-gate 		break;
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	case MS_WAIT_X2:
11367c478bd9Sstevel@tonic-gate 		/*
11377c478bd9Sstevel@tonic-gate 		 * Second delta X byte.
11387c478bd9Sstevel@tonic-gate 		 */
11397c478bd9Sstevel@tonic-gate 		temp = (int)(mi->mi_x + c);
11407c478bd9Sstevel@tonic-gate 		mi->mi_x = BYTECLIP(temp);
11417c478bd9Sstevel@tonic-gate 		uniqtime32(&mi->mi_time);
11427c478bd9Sstevel@tonic-gate 		break;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	case MS_WAIT_Y2:
11457c478bd9Sstevel@tonic-gate 		/*
11467c478bd9Sstevel@tonic-gate 		 * Second delta Y byte.
11477c478bd9Sstevel@tonic-gate 		 */
11487c478bd9Sstevel@tonic-gate 		temp = (int)(mi->mi_y - c);
11497c478bd9Sstevel@tonic-gate 		mi->mi_y = BYTECLIP(temp);
11507c478bd9Sstevel@tonic-gate 		break;
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	/*
11557c478bd9Sstevel@tonic-gate 	 * Done yet?
11567c478bd9Sstevel@tonic-gate 	 */
11577c478bd9Sstevel@tonic-gate 	if (msd->msd_state == MS_WAIT_Y2)
11587c478bd9Sstevel@tonic-gate 		msd->msd_state = MS_WAIT_BUTN;	/* BONG. Start again. */
11597c478bd9Sstevel@tonic-gate 	else {
11607c478bd9Sstevel@tonic-gate 		msd->msd_state += 1;
11617c478bd9Sstevel@tonic-gate 		return;
11627c478bd9Sstevel@tonic-gate 	}
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	if (msd->msd_jitter) {
11657c478bd9Sstevel@tonic-gate 		(void) quntimeout(msd->msd_readq, msd->msd_timeout_id);
11667c478bd9Sstevel@tonic-gate 		msd->msd_jitter = 0;
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if (mi->mi_buttons == msd->msd_oldbutt) {
11707c478bd9Sstevel@tonic-gate 		/*
11717c478bd9Sstevel@tonic-gate 		 * Buttons did not change; did position?
11727c478bd9Sstevel@tonic-gate 		 */
11737c478bd9Sstevel@tonic-gate 		if (mi->mi_x == 0 && mi->mi_y == 0) {
11747c478bd9Sstevel@tonic-gate 			/* no, position did not change - boring event */
11757c478bd9Sstevel@tonic-gate 			return;
11767c478bd9Sstevel@tonic-gate 		}
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 		/*
11797c478bd9Sstevel@tonic-gate 		 * Did the mouse move more than the jitter threshhold?
11807c478bd9Sstevel@tonic-gate 		 */
11817c478bd9Sstevel@tonic-gate 		jitter_radius = ms_jitter_thresh;
11827c478bd9Sstevel@tonic-gate 		if (ABS((int)mi->mi_x) <= jitter_radius &&
11837c478bd9Sstevel@tonic-gate 		    ABS((int)mi->mi_y) <= jitter_radius) {
11847c478bd9Sstevel@tonic-gate 			/*
11857c478bd9Sstevel@tonic-gate 			 * Mouse moved less than the jitter threshhold.
11867c478bd9Sstevel@tonic-gate 			 * Don't indicate an event; keep accumulating motions.
11877c478bd9Sstevel@tonic-gate 			 * After "msjittertimeout" ticks expire, treat
11887c478bd9Sstevel@tonic-gate 			 * the accumulated delta as the real delta.
11897c478bd9Sstevel@tonic-gate 			 */
11907c478bd9Sstevel@tonic-gate 			msd->msd_jitter = 1;
11917c478bd9Sstevel@tonic-gate 			msd->msd_timeout_id = qtimeout(msd->msd_readq,
11927c478bd9Sstevel@tonic-gate 			    msincr, msd, msjittertimeout);
11937c478bd9Sstevel@tonic-gate 			return;
11947c478bd9Sstevel@tonic-gate 		}
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 	msd->msd_oldbutt = mi->mi_buttons;
11977c478bd9Sstevel@tonic-gate 	msincr(msd);
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate /*
12017c478bd9Sstevel@tonic-gate  * Increment the mouse sample pointer.
12027c478bd9Sstevel@tonic-gate  * Called either immediately after a sample or after a jitter timeout.
12037c478bd9Sstevel@tonic-gate  */
12047c478bd9Sstevel@tonic-gate static void
msincr(void * arg)12057c478bd9Sstevel@tonic-gate msincr(void *arg)
12067c478bd9Sstevel@tonic-gate {
12077c478bd9Sstevel@tonic-gate 	struct msdata  *msd = arg;
1208*166fc016SToomas Soome 	struct ms_softc *ms = &msd->msd_softc;
1209*166fc016SToomas Soome 	struct mousebuf *b;
1210*166fc016SToomas Soome 	struct mouseinfo *mi;
12117c478bd9Sstevel@tonic-gate 	char			oldbutt;
1212*166fc016SToomas Soome 	short		xc, yc;
1213*166fc016SToomas Soome 	int		wake;
1214*166fc016SToomas Soome 	int		speedlimit = ms_speedlimit;
1215*166fc016SToomas Soome 	int		xabs, yabs;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	/*
12187c478bd9Sstevel@tonic-gate 	 * No longer waiting for jitter timeout
12197c478bd9Sstevel@tonic-gate 	 */
12207c478bd9Sstevel@tonic-gate 	msd->msd_jitter = 0;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	b = ms->ms_buf;
12237c478bd9Sstevel@tonic-gate 	if (b == NULL)
12247c478bd9Sstevel@tonic-gate 		return;
12257c478bd9Sstevel@tonic-gate 	mi = &b->mb_info[b->mb_off];
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	if (ms_speedlaw) {
12287c478bd9Sstevel@tonic-gate 		xabs = ABS((int)mi->mi_x);
12297c478bd9Sstevel@tonic-gate 		yabs = ABS((int)mi->mi_y);
12307c478bd9Sstevel@tonic-gate 		if (xabs > speedlimit || yabs > speedlimit)
12317c478bd9Sstevel@tonic-gate 			ms_speed_count++;
12327c478bd9Sstevel@tonic-gate 		if (xabs > speedlimit)
12337c478bd9Sstevel@tonic-gate 			mi->mi_x = 0;
12347c478bd9Sstevel@tonic-gate 		if (yabs > speedlimit)
12357c478bd9Sstevel@tonic-gate 			mi->mi_y = 0;
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	oldbutt = mi->mi_buttons;
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	xc = yc = 0;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	/* See if we need to wake up anyone waiting for input */
12437c478bd9Sstevel@tonic-gate 	wake = b->mb_off == ms->ms_oldoff;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	/* Adjust circular buffer pointer */
12467c478bd9Sstevel@tonic-gate 	if (++b->mb_off >= b->mb_size) {
12477c478bd9Sstevel@tonic-gate 		b->mb_off = 0;
12487c478bd9Sstevel@tonic-gate 		mi = b->mb_info;
12497c478bd9Sstevel@tonic-gate 	} else {
12507c478bd9Sstevel@tonic-gate 		mi++;
12517c478bd9Sstevel@tonic-gate 	}
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	/*
12547c478bd9Sstevel@tonic-gate 	 * If over-took read index then flush buffer so that mouse state
12557c478bd9Sstevel@tonic-gate 	 * is consistent.
12567c478bd9Sstevel@tonic-gate 	 */
12577c478bd9Sstevel@tonic-gate 	if (b->mb_off == ms->ms_oldoff) {
12587c478bd9Sstevel@tonic-gate 		if (ms_overrun_msg)
12597c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
12607c478bd9Sstevel@tonic-gate 				"Mouse buffer flushed when overrun.\n");
12617c478bd9Sstevel@tonic-gate 		msflush(msd);
12627c478bd9Sstevel@tonic-gate 		ms_overrun_cnt++;
12637c478bd9Sstevel@tonic-gate 		mi = b->mb_info;
12647c478bd9Sstevel@tonic-gate 	}
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 	/* Remember current buttons and fractional part of x & y */
12677c478bd9Sstevel@tonic-gate 	mi->mi_buttons = oldbutt;
12687c478bd9Sstevel@tonic-gate 	mi->mi_x = (char)xc;
12697c478bd9Sstevel@tonic-gate 	mi->mi_y = (char)yc;
12707c478bd9Sstevel@tonic-gate 	if (wake || msd->msd_qenable_more)
12717c478bd9Sstevel@tonic-gate 		qenable(msd->msd_readq);	/* run the service procedure */
12727c478bd9Sstevel@tonic-gate }
1273