xref: /onnv-gate/usr/src/uts/common/io/consms.c (revision 7656:2621e50fdf4a)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51662Sqz150045  * Common Development and Distribution License (the "License").
61662Sqz150045  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
227187Shh224818  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Console mouse driver for Sun.
290Sstevel@tonic-gate  * The console "zs" port is linked under us, with the "ms" module pushed
300Sstevel@tonic-gate  * on top of it.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * This device merely provides a way to have "/dev/mouse" automatically
330Sstevel@tonic-gate  * have the "ms" module present. Due to problems with the way the "specfs"
340Sstevel@tonic-gate  * file system works, you can't use an indirect device (a "stat" on
350Sstevel@tonic-gate  * "/dev/mouse" won't get the right snode, so you won't get the right time
360Sstevel@tonic-gate  * of last access), and due to problems with the kernel window system code,
370Sstevel@tonic-gate  * you can't use a "cons"-like driver ("/dev/mouse" won't be a streams device,
380Sstevel@tonic-gate  * even though operations on it get turned into operations on the real stream).
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * This module supports multiple mice connected to the system at the same time.
410Sstevel@tonic-gate  * All the mice are linked under consms, and act as a mouse with replicated
420Sstevel@tonic-gate  * clicks. Only USB and PS/2 mouse are supported to be virtual mouse now.
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <sys/types.h>
460Sstevel@tonic-gate #include <sys/param.h>
470Sstevel@tonic-gate #include <sys/stropts.h>
480Sstevel@tonic-gate #include <sys/stream.h>
490Sstevel@tonic-gate #include <sys/strsun.h>
500Sstevel@tonic-gate #include <sys/conf.h>
510Sstevel@tonic-gate #include <sys/stat.h>
520Sstevel@tonic-gate #include <sys/errno.h>
530Sstevel@tonic-gate #include <sys/modctl.h>
540Sstevel@tonic-gate #include <sys/consdev.h>
550Sstevel@tonic-gate #include <sys/ddi.h>
560Sstevel@tonic-gate #include <sys/sunddi.h>
570Sstevel@tonic-gate #include <sys/kstat.h>
580Sstevel@tonic-gate #include <sys/vuid_wheel.h>
590Sstevel@tonic-gate #include <sys/msio.h>
600Sstevel@tonic-gate #include <sys/consms.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static void consms_plink(queue_t *, mblk_t *);
630Sstevel@tonic-gate static int consms_punlink(queue_t *, mblk_t *);
640Sstevel@tonic-gate static void
650Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *, mblk_t *);
660Sstevel@tonic-gate static void consms_add_lq(consms_lq_t *);
670Sstevel@tonic-gate static void consms_check_caps(void);
687187Shh224818 static mblk_t *consms_new_firm_event(ushort_t, int);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate static void consms_mux_max_wheel_report(mblk_t *);
710Sstevel@tonic-gate static void consms_mux_cache_states(mblk_t *);
720Sstevel@tonic-gate static void consms_mux_link_msg(consms_msg_t *);
730Sstevel@tonic-gate static consms_msg_t *consms_mux_unlink_msg(uint_t);
740Sstevel@tonic-gate static consms_msg_t *consms_mux_find_msg(uint_t);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static void consms_mux_iocdata(consms_msg_t *, mblk_t *);
770Sstevel@tonic-gate static void consms_mux_disp_iocdata(consms_response_t *, mblk_t *);
780Sstevel@tonic-gate static int consms_mux_disp_ioctl(queue_t *, mblk_t *);
790Sstevel@tonic-gate static void consms_mux_copyreq(queue_t *, consms_msg_t *, mblk_t *);
800Sstevel@tonic-gate static void consms_mux_ack(consms_msg_t *, mblk_t *);
810Sstevel@tonic-gate static void consms_mux_disp_data(mblk_t *);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static int	consmsopen();
850Sstevel@tonic-gate static int	consmsclose();
860Sstevel@tonic-gate static void	consmsuwput();
870Sstevel@tonic-gate static void	consmslrput();
880Sstevel@tonic-gate static void	consmslwserv();
890Sstevel@tonic-gate 
900Sstevel@tonic-gate static struct module_info consmsm_info = {
910Sstevel@tonic-gate 	0,
920Sstevel@tonic-gate 	"consms",
930Sstevel@tonic-gate 	0,
940Sstevel@tonic-gate 	1024,
950Sstevel@tonic-gate 	2048,
960Sstevel@tonic-gate 	128
970Sstevel@tonic-gate };
980Sstevel@tonic-gate 
990Sstevel@tonic-gate static struct qinit consmsurinit = {
1000Sstevel@tonic-gate 	putq,
1010Sstevel@tonic-gate 	(int (*)())NULL,
1020Sstevel@tonic-gate 	consmsopen,
1030Sstevel@tonic-gate 	consmsclose,
1040Sstevel@tonic-gate 	(int (*)())NULL,
1050Sstevel@tonic-gate 	&consmsm_info,
1060Sstevel@tonic-gate 	NULL
1070Sstevel@tonic-gate };
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate static struct qinit consmsuwinit = {
1100Sstevel@tonic-gate 	(int (*)())consmsuwput,
1110Sstevel@tonic-gate 	(int (*)())NULL,
1120Sstevel@tonic-gate 	consmsopen,
1130Sstevel@tonic-gate 	consmsclose,
1140Sstevel@tonic-gate 	(int (*)())NULL,
1150Sstevel@tonic-gate 	&consmsm_info,
1160Sstevel@tonic-gate 	NULL
1170Sstevel@tonic-gate };
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static struct qinit consmslrinit = {
1200Sstevel@tonic-gate 	(int (*)())consmslrput,
1210Sstevel@tonic-gate 	(int (*)())NULL,
1220Sstevel@tonic-gate 	(int (*)())NULL,
1230Sstevel@tonic-gate 	(int (*)())NULL,
1240Sstevel@tonic-gate 	(int (*)())NULL,
1250Sstevel@tonic-gate 	&consmsm_info,
1260Sstevel@tonic-gate 	NULL
1270Sstevel@tonic-gate };
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static struct qinit consmslwinit = {
1300Sstevel@tonic-gate 	putq,
1310Sstevel@tonic-gate 	(int (*)())consmslwserv,
1320Sstevel@tonic-gate 	(int (*)())NULL,
1330Sstevel@tonic-gate 	(int (*)())NULL,
1340Sstevel@tonic-gate 	(int (*)())NULL,
1350Sstevel@tonic-gate 	&consmsm_info,
1360Sstevel@tonic-gate 	NULL
1370Sstevel@tonic-gate };
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate static struct streamtab consms_str_info = {
1400Sstevel@tonic-gate 	&consmsurinit,
1410Sstevel@tonic-gate 	&consmsuwinit,
1420Sstevel@tonic-gate 	&consmslrinit,
1430Sstevel@tonic-gate 	&consmslwinit,
1440Sstevel@tonic-gate };
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate static void consmsioctl(queue_t *q, mblk_t *mp);
1470Sstevel@tonic-gate static int consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1480Sstevel@tonic-gate 		void **result);
1490Sstevel@tonic-gate static int consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
1500Sstevel@tonic-gate static int consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
1510Sstevel@tonic-gate static int consms_kstat_update(kstat_t *, int);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * Module global data are protected by the per-module inner perimeter.
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate static queue_t		*upperqueue;	/* regular mouse queue above us */
1570Sstevel@tonic-gate static dev_info_t	*consms_dip;	/* private copy of devinfo pointer */
1580Sstevel@tonic-gate static long	consms_idle_stamp;	/* seconds tstamp of latest mouse op */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate static consms_msg_t	*consms_mux_msg; /* ioctl messages being processed */
1610Sstevel@tonic-gate static	kmutex_t	consms_msg_lock; /* protect ioctl messages list */
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate static consms_state_t	consms_state;	/* the global virtual mouse state */
1640Sstevel@tonic-gate static	kmutex_t	consmslock;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate  * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements.  In
1690Sstevel@tonic-gate  * this case we use this type for a single element because the ioctl code
1700Sstevel@tonic-gate  * for it knows how to handle mixed kernel/user data models.  Also, it
1710Sstevel@tonic-gate  * will be easier to add new statistics later.
1720Sstevel@tonic-gate  */
1730Sstevel@tonic-gate static struct {
1740Sstevel@tonic-gate 	kstat_named_t idle_sec;		/* seconds since last user op */
1750Sstevel@tonic-gate } consms_kstat = {
1760Sstevel@tonic-gate 	{ "idle_sec", KSTAT_DATA_LONG, }
1770Sstevel@tonic-gate };
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate static 	struct cb_ops cb_consms_ops = {
1810Sstevel@tonic-gate 	nulldev,		/* cb_open */
1820Sstevel@tonic-gate 	nulldev,		/* cb_close */
1830Sstevel@tonic-gate 	nodev,			/* cb_strategy */
1840Sstevel@tonic-gate 	nodev,			/* cb_print */
1850Sstevel@tonic-gate 	nodev,			/* cb_dump */
1860Sstevel@tonic-gate 	nodev,			/* cb_read */
1870Sstevel@tonic-gate 	nodev,			/* cb_write */
1880Sstevel@tonic-gate 	nodev,			/* cb_ioctl */
1890Sstevel@tonic-gate 	nodev,			/* cb_devmap */
1900Sstevel@tonic-gate 	nodev,			/* cb_mmap */
1910Sstevel@tonic-gate 	nodev,			/* cb_segmap */
1920Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
1930Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
1940Sstevel@tonic-gate 	&consms_str_info,	/* cb_stream */
1950Sstevel@tonic-gate 	D_MP | D_MTPERMOD	/* cb_flag */
1960Sstevel@tonic-gate };
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate static struct dev_ops consms_ops = {
1990Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
2000Sstevel@tonic-gate 	0,			/* devo_refcnt */
2010Sstevel@tonic-gate 	consms_info,		/* devo_getinfo */
2020Sstevel@tonic-gate 	nulldev,		/* devo_identify */
2030Sstevel@tonic-gate 	nulldev,		/* devo_probe */
2040Sstevel@tonic-gate 	consms_attach,		/* devo_attach */
2050Sstevel@tonic-gate 	consms_detach,		/* devo_detach */
2060Sstevel@tonic-gate 	nodev,			/* devo_reset */
2070Sstevel@tonic-gate 	&(cb_consms_ops),	/* devo_cb_ops */
2080Sstevel@tonic-gate 	(struct bus_ops *)NULL,	/* devo_bus_ops */
209*7656SSherry.Moore@Sun.COM 	NULL,			/* devo_power */
210*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* devo_quiesce */
2110Sstevel@tonic-gate };
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  * Module linkage information for the kernel.
2160Sstevel@tonic-gate  */
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate static struct modldrv modldrv = {
2190Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
220*7656SSherry.Moore@Sun.COM 	"Mouse Driver for Sun 'consms' 5.57",
2210Sstevel@tonic-gate 	&consms_ops,	/* driver ops */
2220Sstevel@tonic-gate };
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate static struct modlinkage modlinkage = {
2250Sstevel@tonic-gate 	MODREV_1,
2260Sstevel@tonic-gate 	(void *)&modldrv,
2270Sstevel@tonic-gate 	NULL
2280Sstevel@tonic-gate };
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate int
_init(void)2310Sstevel@tonic-gate _init(void)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	int	error;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	mutex_init(&consmslock, NULL, MUTEX_DRIVER, NULL);
2360Sstevel@tonic-gate 	mutex_init(&consms_msg_lock, NULL, MUTEX_DRIVER, NULL);
2370Sstevel@tonic-gate 	error = mod_install(&modlinkage);
2380Sstevel@tonic-gate 	if (error != 0) {
2390Sstevel@tonic-gate 		mutex_destroy(&consmslock);
2400Sstevel@tonic-gate 		mutex_destroy(&consms_msg_lock);
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 	return (error);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate int
_fini(void)2460Sstevel@tonic-gate _fini(void)
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate 	int	error;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	error = mod_remove(&modlinkage);
2510Sstevel@tonic-gate 	if (error != 0)
2520Sstevel@tonic-gate 		return (error);
2530Sstevel@tonic-gate 	mutex_destroy(&consmslock);
2540Sstevel@tonic-gate 	mutex_destroy(&consms_msg_lock);
2550Sstevel@tonic-gate 	return (0);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2590Sstevel@tonic-gate _info(struct modinfo *modinfop)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate static int
consms_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2650Sstevel@tonic-gate consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	kstat_t	*ksp;
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	switch (cmd) {
2700Sstevel@tonic-gate 	case DDI_ATTACH:
2710Sstevel@tonic-gate 		break;
2720Sstevel@tonic-gate 	default:
2730Sstevel@tonic-gate 		return (DDI_FAILURE);
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "mouse", S_IFCHR,
2777187Shh224818 	    0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
2780Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
2790Sstevel@tonic-gate 		return (-1);
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 	consms_dip = devi;
2820Sstevel@tonic-gate 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1);
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	ksp = kstat_create("consms", 0, "activity", "misc", KSTAT_TYPE_NAMED,
2850Sstevel@tonic-gate 	    sizeof (consms_kstat) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
2860Sstevel@tonic-gate 	if (ksp) {
2870Sstevel@tonic-gate 		ksp->ks_data = (void *)&consms_kstat;
2880Sstevel@tonic-gate 		ksp->ks_update = consms_kstat_update;
2890Sstevel@tonic-gate 		kstat_install(ksp);
2900Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();	/* initial value */
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	consms_state.consms_lqs = NULL;
2940Sstevel@tonic-gate 	consms_state.consms_num_lqs = 0;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/* default consms state values */
2970Sstevel@tonic-gate 	consms_state.consms_vuid_format = VUID_FIRM_EVENT;
2980Sstevel@tonic-gate 	consms_state.consms_num_buttons = 0;
2990Sstevel@tonic-gate 	consms_state.consms_num_wheels = 0;
3000Sstevel@tonic-gate 	consms_state.consms_wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
3010Sstevel@tonic-gate 	consms_state.consms_ms_parms.jitter_thresh =
3020Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_JITTER;
3030Sstevel@tonic-gate 	consms_state.consms_ms_parms.speed_limit =
3040Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_SPEED_LIMIT;
3050Sstevel@tonic-gate 	consms_state.consms_ms_parms.speed_law =
3060Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_SPEED_LAW;
3070Sstevel@tonic-gate 	consms_state.consms_ms_sr.height = CONSMS_SR_DEFAULT_HEIGHT;
3080Sstevel@tonic-gate 	consms_state.consms_ms_sr.width = CONSMS_SR_DEFAULT_WIDTH;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	return (DDI_SUCCESS);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate /*ARGSUSED*/
3140Sstevel@tonic-gate static int
consms_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)3150Sstevel@tonic-gate consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	switch (cmd) {
3180Sstevel@tonic-gate 	case DDI_DETACH:
3190Sstevel@tonic-gate 	default:
3200Sstevel@tonic-gate 		return (DDI_FAILURE);
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*ARGSUSED*/
3250Sstevel@tonic-gate static int
consms_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3260Sstevel@tonic-gate consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
3270Sstevel@tonic-gate 	void **result)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	register int error;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	switch (infocmd) {
3320Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
3330Sstevel@tonic-gate 		if (consms_dip == NULL) {
3340Sstevel@tonic-gate 			error = DDI_FAILURE;
3350Sstevel@tonic-gate 		} else {
3360Sstevel@tonic-gate 			*result = (void *) consms_dip;
3370Sstevel@tonic-gate 			error = DDI_SUCCESS;
3380Sstevel@tonic-gate 		}
3390Sstevel@tonic-gate 		break;
3400Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
3410Sstevel@tonic-gate 		*result = (void *)0;
3420Sstevel@tonic-gate 		error = DDI_SUCCESS;
3430Sstevel@tonic-gate 		break;
3440Sstevel@tonic-gate 	default:
3450Sstevel@tonic-gate 		error = DDI_FAILURE;
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	return (error);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate /*ARGSUSED*/
3520Sstevel@tonic-gate static int
consmsopen(q,devp,flag,sflag,crp)3530Sstevel@tonic-gate consmsopen(q, devp, flag, sflag, crp)
3540Sstevel@tonic-gate 	queue_t *q;
3550Sstevel@tonic-gate 	dev_t	*devp;
3560Sstevel@tonic-gate 	int	flag, sflag;
3570Sstevel@tonic-gate 	cred_t	*crp;
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	upperqueue = q;
3600Sstevel@tonic-gate 	qprocson(q);
3610Sstevel@tonic-gate 	return (0);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate /*ARGSUSED*/
3650Sstevel@tonic-gate static int
consmsclose(q,flag,crp)3660Sstevel@tonic-gate consmsclose(q, flag, crp)
3670Sstevel@tonic-gate 	queue_t *q;
3680Sstevel@tonic-gate 	int	flag;
3690Sstevel@tonic-gate 	cred_t	*crp;
3700Sstevel@tonic-gate {
3710Sstevel@tonic-gate 	qprocsoff(q);
3720Sstevel@tonic-gate 	upperqueue = NULL;
3730Sstevel@tonic-gate 	return (0);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate /*
3770Sstevel@tonic-gate  * Put procedure for upper write queue.
3780Sstevel@tonic-gate  */
3790Sstevel@tonic-gate static void
consmsuwput(q,mp)3800Sstevel@tonic-gate consmsuwput(q, mp)
3810Sstevel@tonic-gate 	register queue_t *q;
3820Sstevel@tonic-gate 	register mblk_t *mp;
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate 	struct iocblk		*iocbp = (struct iocblk *)mp->b_rptr;
3850Sstevel@tonic-gate 	consms_msg_t		*msg;
3860Sstevel@tonic-gate 	int			error = 0;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	case M_IOCTL:
3910Sstevel@tonic-gate 		consmsioctl(q, mp);
3920Sstevel@tonic-gate 		break;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	case M_FLUSH:
3950Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
3960Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
3970Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
3980Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
3990Sstevel@tonic-gate 		if (consms_state.consms_num_lqs > 0) {
4000Sstevel@tonic-gate 			consms_mux_disp_data(mp);
4010Sstevel@tonic-gate 		} else {
4020Sstevel@tonic-gate 			/*
4030Sstevel@tonic-gate 			 * No lower queue; just reflect this back upstream.
4040Sstevel@tonic-gate 			 */
4050Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
4060Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHR)
4070Sstevel@tonic-gate 				qreply(q, mp);
4080Sstevel@tonic-gate 			else
4090Sstevel@tonic-gate 				freemsg(mp);
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 		break;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	case M_DATA:
4140Sstevel@tonic-gate 		if (consms_state.consms_num_lqs > 0) {
4150Sstevel@tonic-gate 			consms_mux_disp_data(mp);
4160Sstevel@tonic-gate 		} else {
417829Sry162471 			freemsg(mp);
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 		break;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	case M_IOCDATA:
4220Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
4230Sstevel@tonic-gate 			consms_mux_iocdata(msg, mp);
4240Sstevel@tonic-gate 		} else {
4250Sstevel@tonic-gate 			error = EINVAL;
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 		break;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	default:
4300Sstevel@tonic-gate 		error = EINVAL;
4310Sstevel@tonic-gate 		break;
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if (error) {
4350Sstevel@tonic-gate 		/*
4360Sstevel@tonic-gate 		 * Pass an error message up.
4370Sstevel@tonic-gate 		 */
4380Sstevel@tonic-gate 		mp->b_datap->db_type = M_ERROR;
4390Sstevel@tonic-gate 		if (mp->b_cont) {
4400Sstevel@tonic-gate 			freemsg(mp->b_cont);
4410Sstevel@tonic-gate 			mp->b_cont = NULL;
4420Sstevel@tonic-gate 		}
4430Sstevel@tonic-gate 		mp->b_rptr = mp->b_datap->db_base;
4440Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + sizeof (char);
4450Sstevel@tonic-gate 		*mp->b_rptr = (char)error;
4460Sstevel@tonic-gate 		qreply(q, mp);
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate static void
consmsioctl(q,mp)4510Sstevel@tonic-gate consmsioctl(q, mp)
4520Sstevel@tonic-gate 	register queue_t *q;
4530Sstevel@tonic-gate 	register mblk_t *mp;
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	register struct iocblk *iocp;
4560Sstevel@tonic-gate 	int		error;
4570Sstevel@tonic-gate 	mblk_t		*datap;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	case I_LINK:
4640Sstevel@tonic-gate 	case I_PLINK:
4650Sstevel@tonic-gate 		mutex_enter(&consmslock);
4660Sstevel@tonic-gate 		consms_plink(q, mp);
4670Sstevel@tonic-gate 		mutex_exit(&consmslock);
4680Sstevel@tonic-gate 		return;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	case I_UNLINK:
4710Sstevel@tonic-gate 	case I_PUNLINK:
4720Sstevel@tonic-gate 		mutex_enter(&consmslock);
4730Sstevel@tonic-gate 		if ((error = consms_punlink(q, mp)) != 0) {
4740Sstevel@tonic-gate 			mutex_exit(&consmslock);
4750Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
4760Sstevel@tonic-gate 			return;
4770Sstevel@tonic-gate 		}
4780Sstevel@tonic-gate 		mutex_exit(&consmslock);
4790Sstevel@tonic-gate 		iocp->ioc_count = 0;
4800Sstevel@tonic-gate 		break;
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	case MSIOBUTTONS:	/* query the number of buttons */
4830Sstevel@tonic-gate 		if ((consms_state.consms_num_lqs <= 0) ||
4840Sstevel@tonic-gate 		    ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)) {
4850Sstevel@tonic-gate 			miocnak(q, mp, 0, ENOMEM);
4860Sstevel@tonic-gate 			return;
4870Sstevel@tonic-gate 		}
4880Sstevel@tonic-gate 		*(int *)datap->b_wptr = consms_state.consms_num_buttons;
4890Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
4900Sstevel@tonic-gate 		if (mp->b_cont) {
4910Sstevel@tonic-gate 			freemsg(mp->b_cont);
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 		mp->b_cont = datap;
4940Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
4950Sstevel@tonic-gate 		break;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	default:
4980Sstevel@tonic-gate 		/*
4990Sstevel@tonic-gate 		 * Pass this through, if there's something to pass it
5000Sstevel@tonic-gate 		 * through to; otherwise, reject it.
5010Sstevel@tonic-gate 		 */
5020Sstevel@tonic-gate 		if (consms_state.consms_num_lqs <= 0) {
5030Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
5040Sstevel@tonic-gate 			return;
5050Sstevel@tonic-gate 		}
5060Sstevel@tonic-gate 		if ((error = consms_mux_disp_ioctl(q, mp)) != 0)
5070Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		return;
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/*
5130Sstevel@tonic-gate 	 * Common exit path for calls that return a positive
5140Sstevel@tonic-gate 	 * acknowledgment with a return value of 0.
5150Sstevel@tonic-gate 	 */
5160Sstevel@tonic-gate 	miocack(q, mp, iocp->ioc_count, 0);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate /*
5200Sstevel@tonic-gate  * Service procedure for lower write queue.
5210Sstevel@tonic-gate  * Puts things on the queue below us, if it lets us.
5220Sstevel@tonic-gate  */
5230Sstevel@tonic-gate static void
consmslwserv(q)5240Sstevel@tonic-gate consmslwserv(q)
5250Sstevel@tonic-gate 	register queue_t *q;
5260Sstevel@tonic-gate {
5270Sstevel@tonic-gate 	register mblk_t *mp;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	while (canput(q->q_next) && (mp = getq(q)) != NULL)
5300Sstevel@tonic-gate 		putnext(q, mp);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate  * Put procedure for lower read queue.
5350Sstevel@tonic-gate  */
5360Sstevel@tonic-gate static void
consmslrput(q,mp)5370Sstevel@tonic-gate consmslrput(q, mp)
5380Sstevel@tonic-gate 	register queue_t *q;
5390Sstevel@tonic-gate 	register mblk_t *mp;
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	struct iocblk		*iocbp = (struct iocblk *)mp->b_rptr;
5420Sstevel@tonic-gate 	struct copyreq		*copyreq = (struct copyreq *)mp->b_rptr;
5430Sstevel@tonic-gate 	consms_msg_t		*msg;
5440Sstevel@tonic-gate 	consms_lq_t		*lq = (consms_lq_t *)q->q_ptr;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	ASSERT(lq != NULL);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
5490Sstevel@tonic-gate 	case M_FLUSH:
5500Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
5510Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
5520Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
5530Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
5540Sstevel@tonic-gate 		if (upperqueue != NULL)
5550Sstevel@tonic-gate 			putnext(upperqueue, mp);	/* pass it through */
5560Sstevel@tonic-gate 		else {
5570Sstevel@tonic-gate 			/*
5580Sstevel@tonic-gate 			 * No upper queue; just reflect this back downstream.
5590Sstevel@tonic-gate 			 */
5600Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHR;
5610Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW)
5620Sstevel@tonic-gate 				qreply(q, mp);
5630Sstevel@tonic-gate 			else
5640Sstevel@tonic-gate 				freemsg(mp);
5650Sstevel@tonic-gate 		}
5660Sstevel@tonic-gate 		break;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	case M_DATA:
5690Sstevel@tonic-gate 		if (upperqueue != NULL)
5700Sstevel@tonic-gate 			putnext(upperqueue, mp);
5710Sstevel@tonic-gate 		else
5720Sstevel@tonic-gate 			freemsg(mp);
5730Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
5740Sstevel@tonic-gate 		break;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	case M_IOCACK:
5770Sstevel@tonic-gate 	case M_IOCNAK:
5780Sstevel@tonic-gate 		/*
5790Sstevel@tonic-gate 		 * First, check to see if this device
5800Sstevel@tonic-gate 		 * is still being initialized.
5810Sstevel@tonic-gate 		 */
5820Sstevel@tonic-gate 		if (lq->lq_ioc_reply_func != NULL) {
5830Sstevel@tonic-gate 			mutex_enter(&consmslock);
5840Sstevel@tonic-gate 			lq->lq_ioc_reply_func(lq, mp);
5850Sstevel@tonic-gate 			mutex_exit(&consmslock);
5860Sstevel@tonic-gate 			freemsg(mp);
5870Sstevel@tonic-gate 			break;
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		/*
5910Sstevel@tonic-gate 		 * This is normal ioctl ack for upper layer.
5920Sstevel@tonic-gate 		 */
5930Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
5940Sstevel@tonic-gate 			consms_mux_ack(msg, mp);
5950Sstevel@tonic-gate 		} else {
5960Sstevel@tonic-gate 			freemsg(mp);
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
5990Sstevel@tonic-gate 		break;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	case M_COPYIN:
6020Sstevel@tonic-gate 	case M_COPYOUT:
6030Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(copyreq->cq_id)) != NULL) {
6040Sstevel@tonic-gate 			consms_mux_copyreq(q, msg, mp);
6050Sstevel@tonic-gate 		} else
6060Sstevel@tonic-gate 			freemsg(mp);
6070Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
6080Sstevel@tonic-gate 		break;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	case M_ERROR:
6110Sstevel@tonic-gate 	case M_HANGUP:
6120Sstevel@tonic-gate 	default:
6130Sstevel@tonic-gate 		freemsg(mp);	/* anything useful here? */
6140Sstevel@tonic-gate 		break;
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate /* ARGSUSED */
6190Sstevel@tonic-gate static int
consms_kstat_update(kstat_t * ksp,int rw)6200Sstevel@tonic-gate consms_kstat_update(kstat_t *ksp, int rw)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
6230Sstevel@tonic-gate 		return (EACCES);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	consms_kstat.idle_sec.value.l = gethrestime_sec() - consms_idle_stamp;
6260Sstevel@tonic-gate 	return (0);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate /*ARGSUSED*/
6300Sstevel@tonic-gate static int
consms_punlink(queue_t * q,mblk_t * mp)6310Sstevel@tonic-gate consms_punlink(queue_t *q, mblk_t *mp)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate 	struct linkblk	*linkp;
6340Sstevel@tonic-gate 	consms_lq_t	*lq;
6350Sstevel@tonic-gate 	consms_lq_t	*prev_lq;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	linkp = (struct linkblk *)mp->b_cont->b_rptr;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	prev_lq = NULL;
6420Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
6430Sstevel@tonic-gate 		if (lq->lq_queue == linkp->l_qbot) {
6440Sstevel@tonic-gate 			if (prev_lq)
6450Sstevel@tonic-gate 				prev_lq->lq_next = lq->lq_next;
6460Sstevel@tonic-gate 			else
6470Sstevel@tonic-gate 				consms_state.consms_lqs = lq->lq_next;
6480Sstevel@tonic-gate 			kmem_free(lq, sizeof (*lq));
6490Sstevel@tonic-gate 			consms_state.consms_num_lqs--;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 			/*
6520Sstevel@tonic-gate 			 * Check to see if mouse capabilities
6530Sstevel@tonic-gate 			 * have changed.
6540Sstevel@tonic-gate 			 */
6550Sstevel@tonic-gate 			consms_check_caps();
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 			return (0);
6580Sstevel@tonic-gate 		}
6590Sstevel@tonic-gate 		prev_lq = lq;
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	return (EINVAL);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate  * Link a specific mouse into our mouse list.
6670Sstevel@tonic-gate  */
6680Sstevel@tonic-gate static void
consms_plink(queue_t * q,mblk_t * mp)6690Sstevel@tonic-gate consms_plink(queue_t *q, mblk_t *mp)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	struct	linkblk	*linkp;
6720Sstevel@tonic-gate 	consms_lq_t	*lq;
6730Sstevel@tonic-gate 	queue_t		*lowq;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	linkp = (struct linkblk *)mp->b_cont->b_rptr;
6780Sstevel@tonic-gate 	lowq = linkp->l_qbot;
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	lq = kmem_zalloc(sizeof (*lq), KM_SLEEP);
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	lowq->q_ptr = (void *)lq;
6830Sstevel@tonic-gate 	OTHERQ(lowq)->q_ptr = (void *)lq;
6840Sstevel@tonic-gate 	lq->lq_queue = lowq;
6850Sstevel@tonic-gate 	lq->lq_pending_plink = mp;
6860Sstevel@tonic-gate 	lq->lq_pending_queue = q;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/*
6890Sstevel@tonic-gate 	 * Set the number of buttons to 3 by default
6900Sstevel@tonic-gate 	 * in case the following MSIOBUTTONS ioctl fails.
6910Sstevel@tonic-gate 	 */
6920Sstevel@tonic-gate 	lq->lq_num_buttons = 3;
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	/*
6950Sstevel@tonic-gate 	 * Begin to initialize this mouse.
6960Sstevel@tonic-gate 	 */
6970Sstevel@tonic-gate 	lq->lq_state = LQS_START;
6980Sstevel@tonic-gate 	consms_lqs_ack_complete(lq, NULL);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate  * Initialize the newly hotplugged-in mouse,
7030Sstevel@tonic-gate  * e.g. get the number of buttons, set event
7040Sstevel@tonic-gate  * format. Then we add it into our list.
7050Sstevel@tonic-gate  */
7060Sstevel@tonic-gate static void
consms_lqs_ack_complete(consms_lq_t * lq,mblk_t * mp)7070Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *lq, mblk_t *mp)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate 	mblk_t			*req = NULL;
7100Sstevel@tonic-gate 	boolean_t		skipped = B_FALSE;
7110Sstevel@tonic-gate 	wheel_state		*ws;
7120Sstevel@tonic-gate 	Ms_screen_resolution	*sr;
7130Sstevel@tonic-gate 	Ms_parms		*params;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/*
7180Sstevel@tonic-gate 	 * We try each ioctl even if the previous one fails
7190Sstevel@tonic-gate 	 * until we reach LQS_DONE, and then add this lq
7200Sstevel@tonic-gate 	 * into our lq list.
7210Sstevel@tonic-gate 	 *
7220Sstevel@tonic-gate 	 * If the message allocation fails, we skip this ioctl,
7230Sstevel@tonic-gate 	 * set skipped flag to B_TRUE in order to skip the ioctl
7240Sstevel@tonic-gate 	 * result, then we try next ioctl, go to next state.
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	while ((lq->lq_state < LQS_DONE) && (req == NULL)) {
7270Sstevel@tonic-gate 		switch (lq->lq_state) {
7280Sstevel@tonic-gate 		case LQS_START:
7290Sstevel@tonic-gate 			/*
7300Sstevel@tonic-gate 			 * First, issue MSIOBUTTONS ioctl
7310Sstevel@tonic-gate 			 * to get the number of buttons.
7320Sstevel@tonic-gate 			 */
7330Sstevel@tonic-gate 			req = mkiocb(MSIOBUTTONS);
7340Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
7350Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7360Sstevel@tonic-gate 				freemsg(req);
7370Sstevel@tonic-gate 				req = NULL;
7380Sstevel@tonic-gate 			}
7390Sstevel@tonic-gate 			if (req == NULL)
7400Sstevel@tonic-gate 				skipped = B_TRUE;
7410Sstevel@tonic-gate 			lq->lq_state++;
7420Sstevel@tonic-gate 			break;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		case LQS_BUTTON_COUNT_PENDING:
7450Sstevel@tonic-gate 			if (!skipped && mp && mp->b_cont &&
7460Sstevel@tonic-gate 			    (mp->b_datap->db_type == M_IOCACK))
7470Sstevel@tonic-gate 				lq->lq_num_buttons =
7480Sstevel@tonic-gate 				    *(int *)mp->b_cont->b_rptr;
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 			/*
7510Sstevel@tonic-gate 			 * Second, issue VUIDGWHEELCOUNT ioctl
7520Sstevel@tonic-gate 			 * to get the count of wheels.
7530Sstevel@tonic-gate 			 */
7540Sstevel@tonic-gate 			req = mkiocb(VUIDGWHEELCOUNT);
7550Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
7560Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7570Sstevel@tonic-gate 				freemsg(req);
7580Sstevel@tonic-gate 				req = NULL;
7590Sstevel@tonic-gate 			}
7600Sstevel@tonic-gate 			if (req == NULL)
7610Sstevel@tonic-gate 				skipped = B_TRUE;
7620Sstevel@tonic-gate 			lq->lq_state++;
7630Sstevel@tonic-gate 			break;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 		case LQS_WHEEL_COUNT_PENDING:
7660Sstevel@tonic-gate 			if (!skipped && mp && mp->b_cont &&
7670Sstevel@tonic-gate 			    (mp->b_datap->db_type == M_IOCACK))
7680Sstevel@tonic-gate 				lq->lq_num_wheels =
7690Sstevel@tonic-gate 				    *(int *)mp->b_cont->b_rptr;
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 			/*
7720Sstevel@tonic-gate 			 * Third, issue VUIDSFORMAT ioctl
7730Sstevel@tonic-gate 			 * to set the event format.
7740Sstevel@tonic-gate 			 */
7750Sstevel@tonic-gate 			req = mkiocb(VUIDSFORMAT);
7760Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
7770Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7780Sstevel@tonic-gate 				freemsg(req);
7790Sstevel@tonic-gate 				req = NULL;
7800Sstevel@tonic-gate 			}
7810Sstevel@tonic-gate 			if (req) {
7820Sstevel@tonic-gate 				*(int *)req->b_cont->b_wptr =
7830Sstevel@tonic-gate 				    consms_state.consms_vuid_format;
7840Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (int);
7850Sstevel@tonic-gate 			}
7860Sstevel@tonic-gate 			lq->lq_state++;
7870Sstevel@tonic-gate 			break;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 		case LQS_SET_VUID_FORMAT_PENDING:
7900Sstevel@tonic-gate 			/*
7910Sstevel@tonic-gate 			 * Fourth, issue VUIDSWHEELSTATE ioctl
7920Sstevel@tonic-gate 			 * to set the wheel state (enable or disable).
7930Sstevel@tonic-gate 			 */
7940Sstevel@tonic-gate 			req = mkiocb(VUIDSWHEELSTATE);
7950Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (wheel_state),
7960Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7970Sstevel@tonic-gate 				freemsg(req);
7980Sstevel@tonic-gate 				req = NULL;
7990Sstevel@tonic-gate 			}
8000Sstevel@tonic-gate 			if (req) {
8010Sstevel@tonic-gate 				ws = (wheel_state *)req->b_cont->b_wptr;
8020Sstevel@tonic-gate 				ws->vers = VUID_WHEEL_STATE_VERS;
8030Sstevel@tonic-gate 				ws->id = 0;	/* the first wheel */
8040Sstevel@tonic-gate 				ws->stateflags =
8050Sstevel@tonic-gate 				    consms_state.consms_wheel_state_bf & 1;
8060Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (wheel_state);
8070Sstevel@tonic-gate 			}
8080Sstevel@tonic-gate 			lq->lq_state++;
8090Sstevel@tonic-gate 			break;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 		case LQS_SET_WHEEL_STATE_PENDING:
8120Sstevel@tonic-gate 			/*
8131662Sqz150045 			 * Fifth,  issue MSIOSETPARMS ioctl
8141662Sqz150045 			 * to set the parameters for USB mouse.
8151662Sqz150045 			 */
8161662Sqz150045 			req = mkiocb(MSIOSETPARMS);
8171662Sqz150045 			if (req && ((req->b_cont = allocb(sizeof (Ms_parms),
8181662Sqz150045 			    BPRI_MED)) == NULL)) {
8191662Sqz150045 				freemsg(req);
8201662Sqz150045 				req = NULL;
8211662Sqz150045 			}
8221662Sqz150045 			if (req) {
8231662Sqz150045 				params = (Ms_parms *)req->b_cont->b_wptr;
8241662Sqz150045 				*params = consms_state.consms_ms_parms;
8251662Sqz150045 				req->b_cont->b_wptr += sizeof (Ms_parms);
8261662Sqz150045 			}
8271662Sqz150045 			lq->lq_state++;
8281662Sqz150045 			break;
8291662Sqz150045 
8301662Sqz150045 		case LQS_SET_PARMS_PENDING:
8311662Sqz150045 			/*
8321662Sqz150045 			 * Sixth, issue MSIOSRESOLUTION ioctl
8330Sstevel@tonic-gate 			 * to set the screen resolution for absolute mouse.
8340Sstevel@tonic-gate 			 */
8350Sstevel@tonic-gate 			req = mkiocb(MSIOSRESOLUTION);
8360Sstevel@tonic-gate 			if (req && ((req->b_cont =
8370Sstevel@tonic-gate 			    allocb(sizeof (Ms_screen_resolution),
8380Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
8390Sstevel@tonic-gate 				freemsg(req);
8400Sstevel@tonic-gate 				req = NULL;
8410Sstevel@tonic-gate 			}
8420Sstevel@tonic-gate 			if (req) {
8430Sstevel@tonic-gate 				sr =
8440Sstevel@tonic-gate 				    (Ms_screen_resolution *)req->b_cont->b_wptr;
8450Sstevel@tonic-gate 				*sr = consms_state.consms_ms_sr;
8460Sstevel@tonic-gate 				req->b_cont->b_wptr +=
8470Sstevel@tonic-gate 				    sizeof (Ms_screen_resolution);
8480Sstevel@tonic-gate 			}
8490Sstevel@tonic-gate 			lq->lq_state++;
8500Sstevel@tonic-gate 			break;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 		case LQS_SET_RESOLUTION_PENDING:
8530Sstevel@tonic-gate 			/*
8540Sstevel@tonic-gate 			 * All jobs are done, lq->lq_state is turned into
8550Sstevel@tonic-gate 			 * LQS_DONE, and this lq is added into our list.
8560Sstevel@tonic-gate 			 */
8570Sstevel@tonic-gate 			lq->lq_state++;
8580Sstevel@tonic-gate 			consms_add_lq(lq);
8590Sstevel@tonic-gate 			break;
8600Sstevel@tonic-gate 		}
8610Sstevel@tonic-gate 	}
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	if (lq->lq_state < LQS_DONE) {
8640Sstevel@tonic-gate 		lq->lq_ioc_reply_func = consms_lqs_ack_complete;
8650Sstevel@tonic-gate 		(void) putq(lq->lq_queue, req);
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate  * Add this specific lq into our list, finally reply
8710Sstevel@tonic-gate  * the previous pending I_PLINK ioctl. Also check to
8720Sstevel@tonic-gate  * see if mouse capabilities have changed, and send
8730Sstevel@tonic-gate  * a dynamical notification event to upper layer if
8740Sstevel@tonic-gate  * necessary.
8750Sstevel@tonic-gate  */
8760Sstevel@tonic-gate static void
consms_add_lq(consms_lq_t * lq)8770Sstevel@tonic-gate consms_add_lq(consms_lq_t *lq)
8780Sstevel@tonic-gate {
8790Sstevel@tonic-gate 	struct	iocblk		*iocp;
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	lq->lq_ioc_reply_func = NULL;
8840Sstevel@tonic-gate 	iocp = (struct iocblk *)lq->lq_pending_plink->b_rptr;
8850Sstevel@tonic-gate 	iocp->ioc_error = 0;
8860Sstevel@tonic-gate 	iocp->ioc_count = 0;
8870Sstevel@tonic-gate 	iocp->ioc_rval = 0;
8880Sstevel@tonic-gate 	lq->lq_pending_plink->b_datap->db_type = M_IOCACK;
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	/* Reply to the I_PLINK ioctl. */
8910Sstevel@tonic-gate 	qreply(lq->lq_pending_queue, lq->lq_pending_plink);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	lq->lq_pending_plink = NULL;
8940Sstevel@tonic-gate 	lq->lq_pending_queue = NULL;
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	/*
8970Sstevel@tonic-gate 	 * Add this lq into list.
8980Sstevel@tonic-gate 	 */
8990Sstevel@tonic-gate 	consms_state.consms_num_lqs++;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	lq->lq_next = consms_state.consms_lqs;
9020Sstevel@tonic-gate 	consms_state.consms_lqs = lq;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	/*
9050Sstevel@tonic-gate 	 * Check to see if mouse capabilities
9060Sstevel@tonic-gate 	 * have changed.
9070Sstevel@tonic-gate 	 */
9080Sstevel@tonic-gate 	consms_check_caps();
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate static void
consms_check_caps(void)9140Sstevel@tonic-gate consms_check_caps(void)
9150Sstevel@tonic-gate {
9160Sstevel@tonic-gate 	consms_lq_t *lq;
9170Sstevel@tonic-gate 	int	max_buttons = 0;
9180Sstevel@tonic-gate 	int	max_wheels = 0;
9190Sstevel@tonic-gate 	mblk_t	*mp;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	/*
9220Sstevel@tonic-gate 	 * Check to see if the number of buttons
9230Sstevel@tonic-gate 	 * and the number of wheels have changed.
9240Sstevel@tonic-gate 	 */
9250Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
9260Sstevel@tonic-gate 		max_buttons = CONSMS_MAX(max_buttons, lq->lq_num_buttons);
9270Sstevel@tonic-gate 		max_wheels = CONSMS_MAX(max_wheels, lq->lq_num_wheels);
9280Sstevel@tonic-gate 	}
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	if (max_buttons != consms_state.consms_num_buttons) {
9310Sstevel@tonic-gate 		/*
9320Sstevel@tonic-gate 		 * Since the number of buttons have changed,
9330Sstevel@tonic-gate 		 * send a MOUSE_CAP_CHANGE_NUM_BUT dynamical
9340Sstevel@tonic-gate 		 * notification event to upper layer.
9350Sstevel@tonic-gate 		 */
9360Sstevel@tonic-gate 		consms_state.consms_num_buttons = max_buttons;
9370Sstevel@tonic-gate 		if (upperqueue != NULL) {
9380Sstevel@tonic-gate 			if ((mp = consms_new_firm_event(
9390Sstevel@tonic-gate 			    MOUSE_CAP_CHANGE_NUM_BUT,
9400Sstevel@tonic-gate 			    consms_state.consms_num_buttons)) != NULL) {
9410Sstevel@tonic-gate 				putnext(upperqueue, mp);
9420Sstevel@tonic-gate 			}
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	if (max_wheels != consms_state.consms_num_wheels) {
9470Sstevel@tonic-gate 		/*
9480Sstevel@tonic-gate 		 * Since the number of wheels have changed,
9490Sstevel@tonic-gate 		 * send a MOUSE_CAP_CHANGE_NUM_WHEEL dynamical
9500Sstevel@tonic-gate 		 * notification event to upper layer.
9510Sstevel@tonic-gate 		 */
9520Sstevel@tonic-gate 		consms_state.consms_num_wheels = max_wheels;
9530Sstevel@tonic-gate 		if (upperqueue != NULL) {
9540Sstevel@tonic-gate 			if ((mp = consms_new_firm_event(
9550Sstevel@tonic-gate 			    MOUSE_CAP_CHANGE_NUM_WHEEL,
9560Sstevel@tonic-gate 			    consms_state.consms_num_wheels)) != NULL) {
9570Sstevel@tonic-gate 				putnext(upperqueue, mp);
9580Sstevel@tonic-gate 			}
9590Sstevel@tonic-gate 		}
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate /*
9640Sstevel@tonic-gate  * Allocate a dynamical notification event.
9650Sstevel@tonic-gate  */
9660Sstevel@tonic-gate static mblk_t *
consms_new_firm_event(ushort_t id,int value)9677187Shh224818 consms_new_firm_event(ushort_t id, int value)
9680Sstevel@tonic-gate {
9690Sstevel@tonic-gate 	Firm_event *fep;
9700Sstevel@tonic-gate 	mblk_t	*tmp;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
9730Sstevel@tonic-gate 		fep = (Firm_event *)tmp->b_wptr;
9740Sstevel@tonic-gate 		fep->id = id;
9750Sstevel@tonic-gate 		fep->pair_type = FE_PAIR_NONE;
9760Sstevel@tonic-gate 		fep->pair = NULL;
9770Sstevel@tonic-gate 		fep->value = value;
9780Sstevel@tonic-gate 		tmp->b_wptr += sizeof (Firm_event);
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	return (tmp);
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate /*
9850Sstevel@tonic-gate  * Start of dispatching interfaces as a multiplexor
9860Sstevel@tonic-gate  */
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate /*
9890Sstevel@tonic-gate  * There is a global msg list (consms_mux_msg),
9900Sstevel@tonic-gate  * which is used to link all ioctl messages from
9910Sstevel@tonic-gate  * upper layer, which are currently being processed.
9920Sstevel@tonic-gate  *
9930Sstevel@tonic-gate  * consms_mux_link_msg links a msg into the list,
9940Sstevel@tonic-gate  * consms_mux_unlink_msg unlinks a msg from the list,
9950Sstevel@tonic-gate  * consms_mux_find_msg finds a msg from the list
9960Sstevel@tonic-gate  * according to its unique id.
9970Sstevel@tonic-gate  *
9980Sstevel@tonic-gate  * The id of each msg is taken from stream's mp,
9990Sstevel@tonic-gate  * so the id is supposed to be unique.
10000Sstevel@tonic-gate  */
10010Sstevel@tonic-gate static void
consms_mux_link_msg(consms_msg_t * msg)10020Sstevel@tonic-gate consms_mux_link_msg(consms_msg_t *msg)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
10050Sstevel@tonic-gate 	msg->msg_next = consms_mux_msg;
10060Sstevel@tonic-gate 	consms_mux_msg = msg;
10070Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate static consms_msg_t *
consms_mux_unlink_msg(uint_t msg_id)10110Sstevel@tonic-gate consms_mux_unlink_msg(uint_t msg_id)
10120Sstevel@tonic-gate {
10130Sstevel@tonic-gate 	consms_msg_t	*msg;
10140Sstevel@tonic-gate 	consms_msg_t	*prev_msg;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
10170Sstevel@tonic-gate 	prev_msg = NULL;
10180Sstevel@tonic-gate 	for (msg = consms_mux_msg; msg != NULL;
10190Sstevel@tonic-gate 	    prev_msg = msg, msg = msg->msg_next) {
10200Sstevel@tonic-gate 		if (msg->msg_id == msg_id)
10210Sstevel@tonic-gate 			break;
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	if (msg != NULL) {
10250Sstevel@tonic-gate 		if (prev_msg != NULL) {
10260Sstevel@tonic-gate 			prev_msg->msg_next = msg->msg_next;
10270Sstevel@tonic-gate 		} else {
10280Sstevel@tonic-gate 			consms_mux_msg = consms_mux_msg->msg_next;
10290Sstevel@tonic-gate 		}
10300Sstevel@tonic-gate 		msg->msg_next = NULL;
10310Sstevel@tonic-gate 	}
10320Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	return (msg);
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate static consms_msg_t *
consms_mux_find_msg(uint_t msg_id)10380Sstevel@tonic-gate consms_mux_find_msg(uint_t msg_id)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate 	consms_msg_t	*msg;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
10430Sstevel@tonic-gate 	for (msg = consms_mux_msg; msg != NULL; msg = msg->msg_next) {
10440Sstevel@tonic-gate 		if (msg->msg_id == msg_id)
10450Sstevel@tonic-gate 			break;
10460Sstevel@tonic-gate 	}
10470Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	return (msg);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate  * Received ACK or NAK from lower mice
10540Sstevel@tonic-gate  *
10550Sstevel@tonic-gate  * For non-transparent ioctl, the msg->msg_rsp_list
10560Sstevel@tonic-gate  * is always NULL; for transparent ioctl, it
10570Sstevel@tonic-gate  * remembers the M_COPYIN/M_COPYOUT request
10580Sstevel@tonic-gate  * messages from lower mice. So here if msg->msg_rsp_list
10590Sstevel@tonic-gate  * is NULL (after receiving all ACK/NAKs), we
10600Sstevel@tonic-gate  * are done with this specific ioctl.
10610Sstevel@tonic-gate  *
10620Sstevel@tonic-gate  * As long as one of lower mice responds success,
10630Sstevel@tonic-gate  * we treat it success for a ioctl.
10640Sstevel@tonic-gate  */
10650Sstevel@tonic-gate static void
consms_mux_ack(consms_msg_t * msg,mblk_t * mp)10660Sstevel@tonic-gate consms_mux_ack(consms_msg_t *msg, mblk_t *mp)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate 	mblk_t	*ack_mp;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	/* increment response_nums */
10710Sstevel@tonic-gate 	msg->msg_num_responses++;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	if (mp->b_datap->db_type == M_IOCACK) {
10740Sstevel@tonic-gate 		/*
10750Sstevel@tonic-gate 		 * Received ACK from lower, then
10760Sstevel@tonic-gate 		 * this is the last step for both
10770Sstevel@tonic-gate 		 * non-transparent and transparent
10780Sstevel@tonic-gate 		 * ioctl. We only need to remember
10790Sstevel@tonic-gate 		 * one of the ACKs, finally reply
10800Sstevel@tonic-gate 		 * this ACK to upper layer for this
10810Sstevel@tonic-gate 		 * specific ioctl.
10820Sstevel@tonic-gate 		 */
10830Sstevel@tonic-gate 		ASSERT(msg->msg_rsp_list == NULL);
10840Sstevel@tonic-gate 		if (msg->msg_ack_mp == NULL) {
10850Sstevel@tonic-gate 			msg->msg_ack_mp = mp;
10860Sstevel@tonic-gate 			mp = NULL;
10870Sstevel@tonic-gate 		}
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/*
10910Sstevel@tonic-gate 	 * Check to see if all lower mice have responded
10920Sstevel@tonic-gate 	 * to our dispatching ioctl.
10930Sstevel@tonic-gate 	 */
10940Sstevel@tonic-gate 	if (msg->msg_num_responses == msg->msg_num_requests) {
10950Sstevel@tonic-gate 		if ((msg->msg_ack_mp == NULL) &&
10960Sstevel@tonic-gate 		    (msg->msg_rsp_list == NULL)) {
10970Sstevel@tonic-gate 			/*
10980Sstevel@tonic-gate 			 * All are NAKed.
10990Sstevel@tonic-gate 			 */
11000Sstevel@tonic-gate 			ack_mp = mp;
11010Sstevel@tonic-gate 			mp = NULL;
11020Sstevel@tonic-gate 		} else if (msg->msg_rsp_list == NULL) {
11030Sstevel@tonic-gate 			/*
11040Sstevel@tonic-gate 			 * The last step and at least one ACKed.
11050Sstevel@tonic-gate 			 */
11060Sstevel@tonic-gate 			ack_mp = msg->msg_ack_mp;
11070Sstevel@tonic-gate 			consms_mux_cache_states(msg->msg_request);
11080Sstevel@tonic-gate 			consms_mux_max_wheel_report(ack_mp);
11090Sstevel@tonic-gate 		} else {
11100Sstevel@tonic-gate 			/*
11110Sstevel@tonic-gate 			 * This is a NAK, but we have
11120Sstevel@tonic-gate 			 * already received M_COPYIN
11130Sstevel@tonic-gate 			 * or M_COPYOUT request from
11140Sstevel@tonic-gate 			 * at least one of lower mice.
11150Sstevel@tonic-gate 			 * (msg->msg_rsp_list != NULL)
11160Sstevel@tonic-gate 			 *
11170Sstevel@tonic-gate 			 * Still copyin or copyout.
11180Sstevel@tonic-gate 			 */
11190Sstevel@tonic-gate 			ack_mp = msg->msg_rsp_list->rsp_mp;
11200Sstevel@tonic-gate 			consms_mux_max_wheel_report(ack_mp);
11210Sstevel@tonic-gate 		}
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 		qreply(msg->msg_queue, ack_mp);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		if (msg->msg_rsp_list == NULL) {
11260Sstevel@tonic-gate 			/*
11270Sstevel@tonic-gate 			 * We are done with this ioctl.
11280Sstevel@tonic-gate 			 */
11290Sstevel@tonic-gate 			if (msg->msg_request)
11300Sstevel@tonic-gate 				freemsg(msg->msg_request);
11310Sstevel@tonic-gate 			(void) consms_mux_unlink_msg(msg->msg_id);
11320Sstevel@tonic-gate 			kmem_free(msg, sizeof (*msg));
11330Sstevel@tonic-gate 		}
11340Sstevel@tonic-gate 	}
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	if (mp) {
11370Sstevel@tonic-gate 		freemsg(mp);
11380Sstevel@tonic-gate 	}
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate /*
11420Sstevel@tonic-gate  * Received M_COPYIN or M_COPYOUT request from
11430Sstevel@tonic-gate  * lower mice for transparent ioctl
11440Sstevel@tonic-gate  *
11450Sstevel@tonic-gate  * We remember each M_COPYIN/M_COPYOUT into the
11460Sstevel@tonic-gate  * msg->msg_rsp_list, reply upper layer using the first
11470Sstevel@tonic-gate  * M_COPYIN/M_COPYOUT in the list after receiving
11480Sstevel@tonic-gate  * all responses from lower mice, even if some of
11490Sstevel@tonic-gate  * them return NAKs.
11500Sstevel@tonic-gate  */
11510Sstevel@tonic-gate static void
consms_mux_copyreq(queue_t * q,consms_msg_t * msg,mblk_t * mp)11520Sstevel@tonic-gate consms_mux_copyreq(queue_t *q, consms_msg_t *msg, mblk_t *mp)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate 	consms_response_t	*rsp;
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	rsp = (consms_response_t *)kmem_zalloc(sizeof (*rsp), KM_SLEEP);
11570Sstevel@tonic-gate 	rsp->rsp_mp = mp;
11580Sstevel@tonic-gate 	rsp->rsp_queue = q;
11590Sstevel@tonic-gate 	if (msg->msg_rsp_list) {
11600Sstevel@tonic-gate 		rsp->rsp_next = msg->msg_rsp_list;
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 	msg->msg_rsp_list = rsp;
11630Sstevel@tonic-gate 	msg->msg_num_responses++;
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	if (msg->msg_num_responses == msg->msg_num_requests) {
11660Sstevel@tonic-gate 		consms_mux_max_wheel_report(msg->msg_rsp_list->rsp_mp);
11670Sstevel@tonic-gate 		qreply(msg->msg_queue, msg->msg_rsp_list->rsp_mp);
11680Sstevel@tonic-gate 	}
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate  * Do the real job for updating M_COPYIN/M_COPYOUT
11730Sstevel@tonic-gate  * request with the mp of M_IOCDATA, then put it
11740Sstevel@tonic-gate  * down to lower mice.
11750Sstevel@tonic-gate  */
11760Sstevel@tonic-gate static void
consms_mux_disp_iocdata(consms_response_t * rsp,mblk_t * mp)11770Sstevel@tonic-gate consms_mux_disp_iocdata(consms_response_t *rsp, mblk_t *mp)
11780Sstevel@tonic-gate {
11790Sstevel@tonic-gate 	mblk_t	*down_mp = rsp->rsp_mp;
11800Sstevel@tonic-gate 	struct copyresp *copyresp = (struct copyresp *)mp->b_rptr;
11810Sstevel@tonic-gate 	struct copyresp *newresp = (struct copyresp *)down_mp->b_rptr;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	/*
11840Sstevel@tonic-gate 	 * Update the rval.
11850Sstevel@tonic-gate 	 */
11860Sstevel@tonic-gate 	newresp->cp_rval = copyresp->cp_rval;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	/*
11890Sstevel@tonic-gate 	 * Update the db_type to M_IOCDATA.
11900Sstevel@tonic-gate 	 */
11910Sstevel@tonic-gate 	down_mp->b_datap->db_type = mp->b_datap->db_type;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/*
11940Sstevel@tonic-gate 	 * Update the b_cont.
11950Sstevel@tonic-gate 	 */
11960Sstevel@tonic-gate 	if (down_mp->b_cont != NULL) {
11970Sstevel@tonic-gate 		freemsg(down_mp->b_cont);
11980Sstevel@tonic-gate 		down_mp->b_cont = NULL;
11990Sstevel@tonic-gate 	}
12000Sstevel@tonic-gate 	if (mp->b_cont != NULL) {
12010Sstevel@tonic-gate 		down_mp->b_cont = copymsg(mp->b_cont);
12020Sstevel@tonic-gate 	}
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	/*
12050Sstevel@tonic-gate 	 * Put it down.
12060Sstevel@tonic-gate 	 */
12070Sstevel@tonic-gate 	(void) putq(WR(rsp->rsp_queue), down_mp);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate /*
12110Sstevel@tonic-gate  * Dispatch M_IOCDATA down to all lower mice
12120Sstevel@tonic-gate  * for transparent ioctl.
12130Sstevel@tonic-gate  *
12140Sstevel@tonic-gate  * We update each M_COPYIN/M_COPYOUT in the
12150Sstevel@tonic-gate  * msg->msg_rsp_list with the M_IOCDATA.
12160Sstevel@tonic-gate  */
12170Sstevel@tonic-gate static void
consms_mux_iocdata(consms_msg_t * msg,mblk_t * mp)12180Sstevel@tonic-gate consms_mux_iocdata(consms_msg_t *msg, mblk_t *mp)
12190Sstevel@tonic-gate {
12200Sstevel@tonic-gate 	consms_response_t	*rsp;
12210Sstevel@tonic-gate 	consms_response_t	*tmp;
12220Sstevel@tonic-gate 	consms_response_t	*first;
12230Sstevel@tonic-gate 	struct copyresp		*copyresp;
12240Sstevel@tonic-gate 	int			request_nums;
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	ASSERT(msg->msg_rsp_list != NULL);
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	/*
12290Sstevel@tonic-gate 	 * We should remember the ioc data for
12300Sstevel@tonic-gate 	 * VUIDSWHEELSTATE, and MSIOSRESOLUTION,
12310Sstevel@tonic-gate 	 * for we will cache the wheel state and
12320Sstevel@tonic-gate 	 * the screen resolution later if ACKed.
12330Sstevel@tonic-gate 	 */
12340Sstevel@tonic-gate 	copyresp = (struct copyresp *)mp->b_rptr;
12350Sstevel@tonic-gate 	if ((copyresp->cp_cmd == VUIDSWHEELSTATE) ||
12360Sstevel@tonic-gate 	    (copyresp->cp_cmd == MSIOSRESOLUTION)) {
12370Sstevel@tonic-gate 		freemsg(msg->msg_request);
12380Sstevel@tonic-gate 		msg->msg_request = copymsg(mp);
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	/*
12420Sstevel@tonic-gate 	 * Update request numbers and response numbers.
12430Sstevel@tonic-gate 	 */
12440Sstevel@tonic-gate 	msg->msg_num_requests = msg->msg_num_responses;
12450Sstevel@tonic-gate 	msg->msg_num_responses = 0;
12460Sstevel@tonic-gate 	request_nums = 1;
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	/*
12490Sstevel@tonic-gate 	 * Since we have use the first M_COPYIN/M_COPYOUT
12500Sstevel@tonic-gate 	 * in the msg_rsp_list to reply upper layer, the mp
12510Sstevel@tonic-gate 	 * of M_IOCDATA can be directly used for that.
12520Sstevel@tonic-gate 	 */
12530Sstevel@tonic-gate 	first = msg->msg_rsp_list;
12540Sstevel@tonic-gate 	rsp = first->rsp_next;
12550Sstevel@tonic-gate 	msg->msg_rsp_list = NULL;
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	for (rsp = first->rsp_next; rsp != NULL; ) {
12580Sstevel@tonic-gate 		tmp = rsp;
12590Sstevel@tonic-gate 		rsp = rsp->rsp_next;
12600Sstevel@tonic-gate 		consms_mux_disp_iocdata(tmp, mp);
12610Sstevel@tonic-gate 		kmem_free(tmp, sizeof (*tmp));
12620Sstevel@tonic-gate 		request_nums++;
12630Sstevel@tonic-gate 	}
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	/* Must set the request number before the last q. */
12660Sstevel@tonic-gate 	msg->msg_num_requests = request_nums;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	/* the first one */
12690Sstevel@tonic-gate 	(void) putq(WR(first->rsp_queue), mp);
12700Sstevel@tonic-gate 	kmem_free(first, sizeof (*first));
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate /*
12750Sstevel@tonic-gate  * Here we update the number of wheels with
12760Sstevel@tonic-gate  * the virtual mouse for VUIDGWHEELCOUNT ioctl.
12770Sstevel@tonic-gate  */
12780Sstevel@tonic-gate static void
consms_mux_max_wheel_report(mblk_t * mp)12790Sstevel@tonic-gate consms_mux_max_wheel_report(mblk_t *mp)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate 	struct iocblk		*iocp;
12820Sstevel@tonic-gate 	int			num_wheels;
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	if (mp == NULL || mp->b_cont == NULL)
12850Sstevel@tonic-gate 		return;
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	if ((iocp->ioc_cmd == VUIDGWHEELCOUNT) &&
12900Sstevel@tonic-gate 	    (mp->b_datap->db_type == M_COPYOUT)) {
12910Sstevel@tonic-gate 		num_wheels = *(int *)mp->b_cont->b_rptr;
12920Sstevel@tonic-gate 		if (num_wheels < consms_state.consms_num_wheels) {
12930Sstevel@tonic-gate 			*(int *)mp->b_cont->b_rptr =
12940Sstevel@tonic-gate 			    consms_state.consms_num_wheels;
12950Sstevel@tonic-gate 		}
12960Sstevel@tonic-gate 	}
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate /*
13000Sstevel@tonic-gate  * Update the virtual mouse state variables with
13010Sstevel@tonic-gate  * the latest value from upper layer when these
13020Sstevel@tonic-gate  * set ioctls return success. Thus we can update
13030Sstevel@tonic-gate  * low mice with the latest state values during
13040Sstevel@tonic-gate  * hotplug.
13050Sstevel@tonic-gate  */
13060Sstevel@tonic-gate static void
consms_mux_cache_states(mblk_t * mp)13070Sstevel@tonic-gate consms_mux_cache_states(mblk_t *mp)
13080Sstevel@tonic-gate {
13090Sstevel@tonic-gate 	struct iocblk 		*iocp;
13100Sstevel@tonic-gate 	Ms_parms		*parms;
13110Sstevel@tonic-gate 	Ms_screen_resolution	*sr;
13120Sstevel@tonic-gate 	wheel_state		*ws;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	if (mp == NULL || mp->b_cont == NULL)
13150Sstevel@tonic-gate 		return;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
13180Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
13190Sstevel@tonic-gate 	case VUIDSFORMAT:
13200Sstevel@tonic-gate 		consms_state.consms_vuid_format = *(int *)mp->b_cont->b_rptr;
13210Sstevel@tonic-gate 		break;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	case MSIOSETPARMS:
13240Sstevel@tonic-gate 		parms = (Ms_parms *)mp->b_cont->b_rptr;
13250Sstevel@tonic-gate 		consms_state.consms_ms_parms = *parms;
13260Sstevel@tonic-gate 		break;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	case MSIOSRESOLUTION:
13290Sstevel@tonic-gate 		sr = (Ms_screen_resolution *)mp->b_cont->b_rptr;
13300Sstevel@tonic-gate 		consms_state.consms_ms_sr = *sr;
13310Sstevel@tonic-gate 		break;
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	case VUIDSWHEELSTATE:
13340Sstevel@tonic-gate 		ws = (wheel_state *)mp->b_cont->b_rptr;
13350Sstevel@tonic-gate 		consms_state.consms_wheel_state_bf =
13360Sstevel@tonic-gate 		    (ws->stateflags << ws->id) |
13370Sstevel@tonic-gate 		    (consms_state.consms_wheel_state_bf & ~(1 << ws->id));
13380Sstevel@tonic-gate 		break;
13390Sstevel@tonic-gate 	}
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate /*
13430Sstevel@tonic-gate  * Dispatch ioctl mp (non-transparent and transparent)
13440Sstevel@tonic-gate  * down to all lower mice.
13450Sstevel@tonic-gate  *
13460Sstevel@tonic-gate  * First, create a pending message for this mp, link it into
13470Sstevel@tonic-gate  * the global messages list. Then wait for ACK/NAK for
13480Sstevel@tonic-gate  * non-transparent ioctl, COPYIN/COPYOUT for transparent
13490Sstevel@tonic-gate  * ioctl.
13500Sstevel@tonic-gate  */
13510Sstevel@tonic-gate static int
consms_mux_disp_ioctl(queue_t * q,mblk_t * mp)13520Sstevel@tonic-gate consms_mux_disp_ioctl(queue_t *q, mblk_t *mp)
13530Sstevel@tonic-gate {
13540Sstevel@tonic-gate 	struct iocblk	*iocp;
13550Sstevel@tonic-gate 	consms_msg_t	*msg;
13560Sstevel@tonic-gate 	consms_lq_t	*lq;
13570Sstevel@tonic-gate 	mblk_t		*copy_mp;
13580Sstevel@tonic-gate 	int		error = 0;
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
13610Sstevel@tonic-gate 	msg = (consms_msg_t *)kmem_zalloc(sizeof (*msg), KM_SLEEP);
13620Sstevel@tonic-gate 	msg->msg_id = iocp->ioc_id;
13630Sstevel@tonic-gate 	msg->msg_request = mp;
13640Sstevel@tonic-gate 	msg->msg_queue = q;
13650Sstevel@tonic-gate 	msg->msg_num_requests = consms_state.consms_num_lqs;
13660Sstevel@tonic-gate 	consms_mux_link_msg(msg);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
13690Sstevel@tonic-gate 		if ((copy_mp = copymsg(mp)) != NULL) {
13700Sstevel@tonic-gate 			(void) putq(lq->lq_queue, copy_mp);
13710Sstevel@tonic-gate 		} else {
13720Sstevel@tonic-gate 			/*
13730Sstevel@tonic-gate 			 * If copymsg fails, we ignore this lq and
13740Sstevel@tonic-gate 			 * try next one. As long as one of them succeeds,
13750Sstevel@tonic-gate 			 * we dispatch this ioctl down. And later as long
13760Sstevel@tonic-gate 			 * as one of the lower drivers return success, we
13770Sstevel@tonic-gate 			 * reply to this ioctl with success.
13780Sstevel@tonic-gate 			 */
13790Sstevel@tonic-gate 			msg->msg_num_requests--;
13800Sstevel@tonic-gate 		}
13810Sstevel@tonic-gate 	}
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	if (msg->msg_num_requests <= 0) {
13840Sstevel@tonic-gate 		/*
13850Sstevel@tonic-gate 		 * Since copymsg fails for all lqs, we NAK this ioctl.
13860Sstevel@tonic-gate 		 */
13870Sstevel@tonic-gate 		(void) consms_mux_unlink_msg(msg->msg_id);
13880Sstevel@tonic-gate 		kmem_free(msg, sizeof (*msg));
13890Sstevel@tonic-gate 		error = ENOMEM;
13900Sstevel@tonic-gate 	}
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	return (error);
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate /*
13960Sstevel@tonic-gate  * Dispatch M_DATA and M_FLUSH message down to all
13970Sstevel@tonic-gate  * lower mice, and there are no acknowledgements
13980Sstevel@tonic-gate  * for them. Here we just copy the mp and then
13990Sstevel@tonic-gate  * put it into the lower queues.
14000Sstevel@tonic-gate  */
14010Sstevel@tonic-gate static void
consms_mux_disp_data(mblk_t * mp)14020Sstevel@tonic-gate consms_mux_disp_data(mblk_t *mp)
14030Sstevel@tonic-gate {
14040Sstevel@tonic-gate 	consms_lq_t	*lq;
14050Sstevel@tonic-gate 	mblk_t		*copy_mp;
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
14080Sstevel@tonic-gate 		if ((copy_mp = copymsg(mp)) != NULL) {
14090Sstevel@tonic-gate 			(void) putq(lq->lq_queue, copy_mp);
14100Sstevel@tonic-gate 		}
14110Sstevel@tonic-gate 	}
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	freemsg(mp);
14140Sstevel@tonic-gate }
1415