xref: /titanic_50/usr/src/uts/common/io/consms.c (revision 97b1ee7eb4859461aa24bfba3eea2c1bbaffb622)
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 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Console mouse driver for Sun.
317c478bd9Sstevel@tonic-gate  * The console "zs" port is linked under us, with the "ms" module pushed
327c478bd9Sstevel@tonic-gate  * on top of it.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * This device merely provides a way to have "/dev/mouse" automatically
357c478bd9Sstevel@tonic-gate  * have the "ms" module present. Due to problems with the way the "specfs"
367c478bd9Sstevel@tonic-gate  * file system works, you can't use an indirect device (a "stat" on
377c478bd9Sstevel@tonic-gate  * "/dev/mouse" won't get the right snode, so you won't get the right time
387c478bd9Sstevel@tonic-gate  * of last access), and due to problems with the kernel window system code,
397c478bd9Sstevel@tonic-gate  * you can't use a "cons"-like driver ("/dev/mouse" won't be a streams device,
407c478bd9Sstevel@tonic-gate  * even though operations on it get turned into operations on the real stream).
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * This module supports multiple mice connected to the system at the same time.
437c478bd9Sstevel@tonic-gate  * All the mice are linked under consms, and act as a mouse with replicated
447c478bd9Sstevel@tonic-gate  * clicks. Only USB and PS/2 mouse are supported to be virtual mouse now.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/param.h>
497c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
507c478bd9Sstevel@tonic-gate #include <sys/stream.h>
517c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
527c478bd9Sstevel@tonic-gate #include <sys/conf.h>
537c478bd9Sstevel@tonic-gate #include <sys/stat.h>
547c478bd9Sstevel@tonic-gate #include <sys/errno.h>
557c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
567c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
577c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
587c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
597c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
607c478bd9Sstevel@tonic-gate #include <sys/vuid_wheel.h>
617c478bd9Sstevel@tonic-gate #include <sys/msio.h>
627c478bd9Sstevel@tonic-gate #include <sys/consms.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static void consms_plink(queue_t *, mblk_t *);
657c478bd9Sstevel@tonic-gate static int consms_punlink(queue_t *, mblk_t *);
667c478bd9Sstevel@tonic-gate static void
677c478bd9Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *, mblk_t *);
687c478bd9Sstevel@tonic-gate static void consms_add_lq(consms_lq_t *);
697c478bd9Sstevel@tonic-gate static void consms_check_caps(void);
707c478bd9Sstevel@tonic-gate static mblk_t *consms_new_firm_event(int, int);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate static void consms_mux_max_wheel_report(mblk_t *);
737c478bd9Sstevel@tonic-gate static void consms_mux_cache_states(mblk_t *);
747c478bd9Sstevel@tonic-gate static void consms_mux_link_msg(consms_msg_t *);
757c478bd9Sstevel@tonic-gate static consms_msg_t *consms_mux_unlink_msg(uint_t);
767c478bd9Sstevel@tonic-gate static consms_msg_t *consms_mux_find_msg(uint_t);
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static void consms_mux_iocdata(consms_msg_t *, mblk_t *);
797c478bd9Sstevel@tonic-gate static void consms_mux_disp_iocdata(consms_response_t *, mblk_t *);
807c478bd9Sstevel@tonic-gate static int consms_mux_disp_ioctl(queue_t *, mblk_t *);
817c478bd9Sstevel@tonic-gate static void consms_mux_copyreq(queue_t *, consms_msg_t *, mblk_t *);
827c478bd9Sstevel@tonic-gate static void consms_mux_ack(consms_msg_t *, mblk_t *);
837c478bd9Sstevel@tonic-gate static void consms_mux_disp_data(mblk_t *);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static int	consmsopen();
877c478bd9Sstevel@tonic-gate static int	consmsclose();
887c478bd9Sstevel@tonic-gate static void	consmsuwput();
897c478bd9Sstevel@tonic-gate static void	consmslrput();
907c478bd9Sstevel@tonic-gate static void	consmslwserv();
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static struct module_info consmsm_info = {
937c478bd9Sstevel@tonic-gate 	0,
947c478bd9Sstevel@tonic-gate 	"consms",
957c478bd9Sstevel@tonic-gate 	0,
967c478bd9Sstevel@tonic-gate 	1024,
977c478bd9Sstevel@tonic-gate 	2048,
987c478bd9Sstevel@tonic-gate 	128
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static struct qinit consmsurinit = {
1027c478bd9Sstevel@tonic-gate 	putq,
1037c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1047c478bd9Sstevel@tonic-gate 	consmsopen,
1057c478bd9Sstevel@tonic-gate 	consmsclose,
1067c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1077c478bd9Sstevel@tonic-gate 	&consmsm_info,
1087c478bd9Sstevel@tonic-gate 	NULL
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static struct qinit consmsuwinit = {
1127c478bd9Sstevel@tonic-gate 	(int (*)())consmsuwput,
1137c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1147c478bd9Sstevel@tonic-gate 	consmsopen,
1157c478bd9Sstevel@tonic-gate 	consmsclose,
1167c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1177c478bd9Sstevel@tonic-gate 	&consmsm_info,
1187c478bd9Sstevel@tonic-gate 	NULL
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static struct qinit consmslrinit = {
1227c478bd9Sstevel@tonic-gate 	(int (*)())consmslrput,
1237c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1247c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1257c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1267c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1277c478bd9Sstevel@tonic-gate 	&consmsm_info,
1287c478bd9Sstevel@tonic-gate 	NULL
1297c478bd9Sstevel@tonic-gate };
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static struct qinit consmslwinit = {
1327c478bd9Sstevel@tonic-gate 	putq,
1337c478bd9Sstevel@tonic-gate 	(int (*)())consmslwserv,
1347c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1357c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1367c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
1377c478bd9Sstevel@tonic-gate 	&consmsm_info,
1387c478bd9Sstevel@tonic-gate 	NULL
1397c478bd9Sstevel@tonic-gate };
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static struct streamtab consms_str_info = {
1427c478bd9Sstevel@tonic-gate 	&consmsurinit,
1437c478bd9Sstevel@tonic-gate 	&consmsuwinit,
1447c478bd9Sstevel@tonic-gate 	&consmslrinit,
1457c478bd9Sstevel@tonic-gate 	&consmslwinit,
1467c478bd9Sstevel@tonic-gate };
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate static void consmsioctl(queue_t *q, mblk_t *mp);
1497c478bd9Sstevel@tonic-gate static int consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1507c478bd9Sstevel@tonic-gate 		void **result);
1517c478bd9Sstevel@tonic-gate static int consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
1527c478bd9Sstevel@tonic-gate static int consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
1537c478bd9Sstevel@tonic-gate static int consms_kstat_update(kstat_t *, int);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * Module global data are protected by the per-module inner perimeter.
1577c478bd9Sstevel@tonic-gate  */
1587c478bd9Sstevel@tonic-gate static queue_t		*upperqueue;	/* regular mouse queue above us */
1597c478bd9Sstevel@tonic-gate static dev_info_t	*consms_dip;	/* private copy of devinfo pointer */
1607c478bd9Sstevel@tonic-gate static long	consms_idle_stamp;	/* seconds tstamp of latest mouse op */
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static consms_msg_t	*consms_mux_msg; /* ioctl messages being processed */
1637c478bd9Sstevel@tonic-gate static	kmutex_t	consms_msg_lock; /* protect ioctl messages list */
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static consms_state_t	consms_state;	/* the global virtual mouse state */
1667c478bd9Sstevel@tonic-gate static	kmutex_t	consmslock;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements.  In
1717c478bd9Sstevel@tonic-gate  * this case we use this type for a single element because the ioctl code
1727c478bd9Sstevel@tonic-gate  * for it knows how to handle mixed kernel/user data models.  Also, it
1737c478bd9Sstevel@tonic-gate  * will be easier to add new statistics later.
1747c478bd9Sstevel@tonic-gate  */
1757c478bd9Sstevel@tonic-gate static struct {
1767c478bd9Sstevel@tonic-gate 	kstat_named_t idle_sec;		/* seconds since last user op */
1777c478bd9Sstevel@tonic-gate } consms_kstat = {
1787c478bd9Sstevel@tonic-gate 	{ "idle_sec", KSTAT_DATA_LONG, }
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate static 	struct cb_ops cb_consms_ops = {
1837c478bd9Sstevel@tonic-gate 	nulldev,		/* cb_open */
1847c478bd9Sstevel@tonic-gate 	nulldev,		/* cb_close */
1857c478bd9Sstevel@tonic-gate 	nodev,			/* cb_strategy */
1867c478bd9Sstevel@tonic-gate 	nodev,			/* cb_print */
1877c478bd9Sstevel@tonic-gate 	nodev,			/* cb_dump */
1887c478bd9Sstevel@tonic-gate 	nodev,			/* cb_read */
1897c478bd9Sstevel@tonic-gate 	nodev,			/* cb_write */
1907c478bd9Sstevel@tonic-gate 	nodev,			/* cb_ioctl */
1917c478bd9Sstevel@tonic-gate 	nodev,			/* cb_devmap */
1927c478bd9Sstevel@tonic-gate 	nodev,			/* cb_mmap */
1937c478bd9Sstevel@tonic-gate 	nodev,			/* cb_segmap */
1947c478bd9Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
1957c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
1967c478bd9Sstevel@tonic-gate 	&consms_str_info,	/* cb_stream */
1977c478bd9Sstevel@tonic-gate 	D_MP | D_MTPERMOD	/* cb_flag */
1987c478bd9Sstevel@tonic-gate };
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate static struct dev_ops consms_ops = {
2017c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
2027c478bd9Sstevel@tonic-gate 	0,			/* devo_refcnt */
2037c478bd9Sstevel@tonic-gate 	consms_info,		/* devo_getinfo */
2047c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_identify */
2057c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_probe */
2067c478bd9Sstevel@tonic-gate 	consms_attach,		/* devo_attach */
2077c478bd9Sstevel@tonic-gate 	consms_detach,		/* devo_detach */
2087c478bd9Sstevel@tonic-gate 	nodev,			/* devo_reset */
2097c478bd9Sstevel@tonic-gate 	&(cb_consms_ops),	/* devo_cb_ops */
2107c478bd9Sstevel@tonic-gate 	(struct bus_ops *)NULL,	/* devo_bus_ops */
2117c478bd9Sstevel@tonic-gate 	NULL			/* devo_power */
2127c478bd9Sstevel@tonic-gate };
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
2177c478bd9Sstevel@tonic-gate  */
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
2207c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
2217c478bd9Sstevel@tonic-gate 	"Mouse Driver for Sun 'consms' %I%",
2227c478bd9Sstevel@tonic-gate 	&consms_ops,	/* driver ops */
2237c478bd9Sstevel@tonic-gate };
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2267c478bd9Sstevel@tonic-gate 	MODREV_1,
2277c478bd9Sstevel@tonic-gate 	(void *)&modldrv,
2287c478bd9Sstevel@tonic-gate 	NULL
2297c478bd9Sstevel@tonic-gate };
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate int
2327c478bd9Sstevel@tonic-gate _init(void)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	int	error;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	mutex_init(&consmslock, NULL, MUTEX_DRIVER, NULL);
2377c478bd9Sstevel@tonic-gate 	mutex_init(&consms_msg_lock, NULL, MUTEX_DRIVER, NULL);
2387c478bd9Sstevel@tonic-gate 	error = mod_install(&modlinkage);
2397c478bd9Sstevel@tonic-gate 	if (error != 0) {
2407c478bd9Sstevel@tonic-gate 		mutex_destroy(&consmslock);
2417c478bd9Sstevel@tonic-gate 		mutex_destroy(&consms_msg_lock);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	return (error);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate int
2477c478bd9Sstevel@tonic-gate _fini(void)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate 	int	error;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	error = mod_remove(&modlinkage);
2527c478bd9Sstevel@tonic-gate 	if (error != 0)
2537c478bd9Sstevel@tonic-gate 		return (error);
2547c478bd9Sstevel@tonic-gate 	mutex_destroy(&consmslock);
2557c478bd9Sstevel@tonic-gate 	mutex_destroy(&consms_msg_lock);
2567c478bd9Sstevel@tonic-gate 	return (0);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate int
2607c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate static int
2667c478bd9Sstevel@tonic-gate consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	kstat_t	*ksp;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	switch (cmd) {
2717c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
2727c478bd9Sstevel@tonic-gate 		break;
2737c478bd9Sstevel@tonic-gate 	default:
2747c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "mouse", S_IFCHR,
2787c478bd9Sstevel@tonic-gate 		0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
2797c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
2807c478bd9Sstevel@tonic-gate 		return (-1);
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	consms_dip = devi;
2837c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	ksp = kstat_create("consms", 0, "activity", "misc", KSTAT_TYPE_NAMED,
2867c478bd9Sstevel@tonic-gate 	    sizeof (consms_kstat) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
2877c478bd9Sstevel@tonic-gate 	if (ksp) {
2887c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *)&consms_kstat;
2897c478bd9Sstevel@tonic-gate 		ksp->ks_update = consms_kstat_update;
2907c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
2917c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();	/* initial value */
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	consms_state.consms_lqs = NULL;
2957c478bd9Sstevel@tonic-gate 	consms_state.consms_num_lqs = 0;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/* default consms state values */
2987c478bd9Sstevel@tonic-gate 	consms_state.consms_vuid_format = VUID_FIRM_EVENT;
2997c478bd9Sstevel@tonic-gate 	consms_state.consms_num_buttons = 0;
3007c478bd9Sstevel@tonic-gate 	consms_state.consms_num_wheels = 0;
3017c478bd9Sstevel@tonic-gate 	consms_state.consms_wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
3027c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_parms.jitter_thresh =
3037c478bd9Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_JITTER;
3047c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_parms.speed_limit =
3057c478bd9Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_SPEED_LIMIT;
3067c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_parms.speed_law =
3077c478bd9Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_SPEED_LAW;
3087c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_sr.height = CONSMS_SR_DEFAULT_HEIGHT;
3097c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_sr.width = CONSMS_SR_DEFAULT_WIDTH;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3157c478bd9Sstevel@tonic-gate static int
3167c478bd9Sstevel@tonic-gate consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	switch (cmd) {
3197c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
3207c478bd9Sstevel@tonic-gate 	default:
3217c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3267c478bd9Sstevel@tonic-gate static int
3277c478bd9Sstevel@tonic-gate consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
3287c478bd9Sstevel@tonic-gate 	void **result)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	register int error;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	switch (infocmd) {
3337c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
3347c478bd9Sstevel@tonic-gate 		if (consms_dip == NULL) {
3357c478bd9Sstevel@tonic-gate 			error = DDI_FAILURE;
3367c478bd9Sstevel@tonic-gate 		} else {
3377c478bd9Sstevel@tonic-gate 			*result = (void *) consms_dip;
3387c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 		break;
3417c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
3427c478bd9Sstevel@tonic-gate 		*result = (void *)0;
3437c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
3447c478bd9Sstevel@tonic-gate 		break;
3457c478bd9Sstevel@tonic-gate 	default:
3467c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 	return (error);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3537c478bd9Sstevel@tonic-gate static int
3547c478bd9Sstevel@tonic-gate consmsopen(q, devp, flag, sflag, crp)
3557c478bd9Sstevel@tonic-gate 	queue_t *q;
3567c478bd9Sstevel@tonic-gate 	dev_t	*devp;
3577c478bd9Sstevel@tonic-gate 	int	flag, sflag;
3587c478bd9Sstevel@tonic-gate 	cred_t	*crp;
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate 	upperqueue = q;
3617c478bd9Sstevel@tonic-gate 	qprocson(q);
3627c478bd9Sstevel@tonic-gate 	return (0);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3667c478bd9Sstevel@tonic-gate static int
3677c478bd9Sstevel@tonic-gate consmsclose(q, flag, crp)
3687c478bd9Sstevel@tonic-gate 	queue_t *q;
3697c478bd9Sstevel@tonic-gate 	int	flag;
3707c478bd9Sstevel@tonic-gate 	cred_t	*crp;
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	qprocsoff(q);
3737c478bd9Sstevel@tonic-gate 	upperqueue = NULL;
3747c478bd9Sstevel@tonic-gate 	return (0);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /*
3787c478bd9Sstevel@tonic-gate  * Put procedure for upper write queue.
3797c478bd9Sstevel@tonic-gate  */
3807c478bd9Sstevel@tonic-gate static void
3817c478bd9Sstevel@tonic-gate consmsuwput(q, mp)
3827c478bd9Sstevel@tonic-gate 	register queue_t *q;
3837c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	struct iocblk		*iocbp = (struct iocblk *)mp->b_rptr;
3867c478bd9Sstevel@tonic-gate 	consms_msg_t		*msg;
3877c478bd9Sstevel@tonic-gate 	int			error = 0;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	case M_IOCTL:
3927c478bd9Sstevel@tonic-gate 		consmsioctl(q, mp);
3937c478bd9Sstevel@tonic-gate 		break;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	case M_FLUSH:
3967c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
3977c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
3987c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
3997c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
4007c478bd9Sstevel@tonic-gate 		if (consms_state.consms_num_lqs > 0) {
4017c478bd9Sstevel@tonic-gate 			consms_mux_disp_data(mp);
4027c478bd9Sstevel@tonic-gate 		} else {
4037c478bd9Sstevel@tonic-gate 			/*
4047c478bd9Sstevel@tonic-gate 			 * No lower queue; just reflect this back upstream.
4057c478bd9Sstevel@tonic-gate 			 */
4067c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
4077c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHR)
4087c478bd9Sstevel@tonic-gate 				qreply(q, mp);
4097c478bd9Sstevel@tonic-gate 			else
4107c478bd9Sstevel@tonic-gate 				freemsg(mp);
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 		break;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	case M_DATA:
4157c478bd9Sstevel@tonic-gate 		if (consms_state.consms_num_lqs > 0) {
4167c478bd9Sstevel@tonic-gate 			consms_mux_disp_data(mp);
4177c478bd9Sstevel@tonic-gate 		} else {
418*97b1ee7eSry162471 			freemsg(mp);
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 		break;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	case M_IOCDATA:
4237c478bd9Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
4247c478bd9Sstevel@tonic-gate 			consms_mux_iocdata(msg, mp);
4257c478bd9Sstevel@tonic-gate 		} else {
4267c478bd9Sstevel@tonic-gate 			error = EINVAL;
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 		break;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	default:
4317c478bd9Sstevel@tonic-gate 		error = EINVAL;
4327c478bd9Sstevel@tonic-gate 		break;
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (error) {
4367c478bd9Sstevel@tonic-gate 		/*
4377c478bd9Sstevel@tonic-gate 		 * Pass an error message up.
4387c478bd9Sstevel@tonic-gate 		 */
4397c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_ERROR;
4407c478bd9Sstevel@tonic-gate 		if (mp->b_cont) {
4417c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
4427c478bd9Sstevel@tonic-gate 			mp->b_cont = NULL;
4437c478bd9Sstevel@tonic-gate 		}
4447c478bd9Sstevel@tonic-gate 		mp->b_rptr = mp->b_datap->db_base;
4457c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + sizeof (char);
4467c478bd9Sstevel@tonic-gate 		*mp->b_rptr = (char)error;
4477c478bd9Sstevel@tonic-gate 		qreply(q, mp);
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static void
4527c478bd9Sstevel@tonic-gate consmsioctl(q, mp)
4537c478bd9Sstevel@tonic-gate 	register queue_t *q;
4547c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	register struct iocblk *iocp;
4577c478bd9Sstevel@tonic-gate 	int		error;
4587c478bd9Sstevel@tonic-gate 	mblk_t		*datap;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	case I_LINK:
4657c478bd9Sstevel@tonic-gate 	case I_PLINK:
4667c478bd9Sstevel@tonic-gate 		mutex_enter(&consmslock);
4677c478bd9Sstevel@tonic-gate 		consms_plink(q, mp);
4687c478bd9Sstevel@tonic-gate 		mutex_exit(&consmslock);
4697c478bd9Sstevel@tonic-gate 		return;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	case I_UNLINK:
4727c478bd9Sstevel@tonic-gate 	case I_PUNLINK:
4737c478bd9Sstevel@tonic-gate 		mutex_enter(&consmslock);
4747c478bd9Sstevel@tonic-gate 		if ((error = consms_punlink(q, mp)) != 0) {
4757c478bd9Sstevel@tonic-gate 			mutex_exit(&consmslock);
4767c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
4777c478bd9Sstevel@tonic-gate 			return;
4787c478bd9Sstevel@tonic-gate 		}
4797c478bd9Sstevel@tonic-gate 		mutex_exit(&consmslock);
4807c478bd9Sstevel@tonic-gate 		iocp->ioc_count = 0;
4817c478bd9Sstevel@tonic-gate 		break;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	case MSIOBUTTONS:	/* query the number of buttons */
4847c478bd9Sstevel@tonic-gate 		if ((consms_state.consms_num_lqs <= 0) ||
4857c478bd9Sstevel@tonic-gate 		    ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)) {
4867c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ENOMEM);
4877c478bd9Sstevel@tonic-gate 			return;
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = consms_state.consms_num_buttons;
4907c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
4917c478bd9Sstevel@tonic-gate 		if (mp->b_cont) {
4927c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
4937c478bd9Sstevel@tonic-gate 		}
4947c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
4957c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
4967c478bd9Sstevel@tonic-gate 		break;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	default:
4997c478bd9Sstevel@tonic-gate 		/*
5007c478bd9Sstevel@tonic-gate 		 * Pass this through, if there's something to pass it
5017c478bd9Sstevel@tonic-gate 		 * through to; otherwise, reject it.
5027c478bd9Sstevel@tonic-gate 		 */
5037c478bd9Sstevel@tonic-gate 		if (consms_state.consms_num_lqs <= 0) {
5047c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
5057c478bd9Sstevel@tonic-gate 			return;
5067c478bd9Sstevel@tonic-gate 		}
5077c478bd9Sstevel@tonic-gate 		if ((error = consms_mux_disp_ioctl(q, mp)) != 0)
5087c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 		return;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	/*
5147c478bd9Sstevel@tonic-gate 	 * Common exit path for calls that return a positive
5157c478bd9Sstevel@tonic-gate 	 * acknowledgment with a return value of 0.
5167c478bd9Sstevel@tonic-gate 	 */
5177c478bd9Sstevel@tonic-gate 	miocack(q, mp, iocp->ioc_count, 0);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate  * Service procedure for lower write queue.
5227c478bd9Sstevel@tonic-gate  * Puts things on the queue below us, if it lets us.
5237c478bd9Sstevel@tonic-gate  */
5247c478bd9Sstevel@tonic-gate static void
5257c478bd9Sstevel@tonic-gate consmslwserv(q)
5267c478bd9Sstevel@tonic-gate 	register queue_t *q;
5277c478bd9Sstevel@tonic-gate {
5287c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	while (canput(q->q_next) && (mp = getq(q)) != NULL)
5317c478bd9Sstevel@tonic-gate 		putnext(q, mp);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate  * Put procedure for lower read queue.
5367c478bd9Sstevel@tonic-gate  */
5377c478bd9Sstevel@tonic-gate static void
5387c478bd9Sstevel@tonic-gate consmslrput(q, mp)
5397c478bd9Sstevel@tonic-gate 	register queue_t *q;
5407c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	struct iocblk		*iocbp = (struct iocblk *)mp->b_rptr;
5437c478bd9Sstevel@tonic-gate 	struct copyreq		*copyreq = (struct copyreq *)mp->b_rptr;
5447c478bd9Sstevel@tonic-gate 	consms_msg_t		*msg;
5457c478bd9Sstevel@tonic-gate 	consms_lq_t		*lq = (consms_lq_t *)q->q_ptr;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	ASSERT(lq != NULL);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
5507c478bd9Sstevel@tonic-gate 	case M_FLUSH:
5517c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
5527c478bd9Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
5537c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
5547c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
5557c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL)
5567c478bd9Sstevel@tonic-gate 			putnext(upperqueue, mp);	/* pass it through */
5577c478bd9Sstevel@tonic-gate 		else {
5587c478bd9Sstevel@tonic-gate 			/*
5597c478bd9Sstevel@tonic-gate 			 * No upper queue; just reflect this back downstream.
5607c478bd9Sstevel@tonic-gate 			 */
5617c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHR;
5627c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW)
5637c478bd9Sstevel@tonic-gate 				qreply(q, mp);
5647c478bd9Sstevel@tonic-gate 			else
5657c478bd9Sstevel@tonic-gate 				freemsg(mp);
5667c478bd9Sstevel@tonic-gate 		}
5677c478bd9Sstevel@tonic-gate 		break;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	case M_DATA:
5707c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL)
5717c478bd9Sstevel@tonic-gate 			putnext(upperqueue, mp);
5727c478bd9Sstevel@tonic-gate 		else
5737c478bd9Sstevel@tonic-gate 			freemsg(mp);
5747c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
5757c478bd9Sstevel@tonic-gate 		break;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	case M_IOCACK:
5787c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
5797c478bd9Sstevel@tonic-gate 		/*
5807c478bd9Sstevel@tonic-gate 		 * First, check to see if this device
5817c478bd9Sstevel@tonic-gate 		 * is still being initialized.
5827c478bd9Sstevel@tonic-gate 		 */
5837c478bd9Sstevel@tonic-gate 		if (lq->lq_ioc_reply_func != NULL) {
5847c478bd9Sstevel@tonic-gate 			mutex_enter(&consmslock);
5857c478bd9Sstevel@tonic-gate 			lq->lq_ioc_reply_func(lq, mp);
5867c478bd9Sstevel@tonic-gate 			mutex_exit(&consmslock);
5877c478bd9Sstevel@tonic-gate 			freemsg(mp);
5887c478bd9Sstevel@tonic-gate 			break;
5897c478bd9Sstevel@tonic-gate 		}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 		/*
5927c478bd9Sstevel@tonic-gate 		 * This is normal ioctl ack for upper layer.
5937c478bd9Sstevel@tonic-gate 		 */
5947c478bd9Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
5957c478bd9Sstevel@tonic-gate 			consms_mux_ack(msg, mp);
5967c478bd9Sstevel@tonic-gate 		} else {
5977c478bd9Sstevel@tonic-gate 			freemsg(mp);
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
6007c478bd9Sstevel@tonic-gate 		break;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	case M_COPYIN:
6037c478bd9Sstevel@tonic-gate 	case M_COPYOUT:
6047c478bd9Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(copyreq->cq_id)) != NULL) {
6057c478bd9Sstevel@tonic-gate 			consms_mux_copyreq(q, msg, mp);
6067c478bd9Sstevel@tonic-gate 		} else
6077c478bd9Sstevel@tonic-gate 			freemsg(mp);
6087c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
6097c478bd9Sstevel@tonic-gate 		break;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	case M_ERROR:
6127c478bd9Sstevel@tonic-gate 	case M_HANGUP:
6137c478bd9Sstevel@tonic-gate 	default:
6147c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* anything useful here? */
6157c478bd9Sstevel@tonic-gate 		break;
6167c478bd9Sstevel@tonic-gate 	}
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /* ARGSUSED */
6207c478bd9Sstevel@tonic-gate static int
6217c478bd9Sstevel@tonic-gate consms_kstat_update(kstat_t *ksp, int rw)
6227c478bd9Sstevel@tonic-gate {
6237c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
6247c478bd9Sstevel@tonic-gate 		return (EACCES);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	consms_kstat.idle_sec.value.l = gethrestime_sec() - consms_idle_stamp;
6277c478bd9Sstevel@tonic-gate 	return (0);
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6317c478bd9Sstevel@tonic-gate static int
6327c478bd9Sstevel@tonic-gate consms_punlink(queue_t *q, mblk_t *mp)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	struct linkblk	*linkp;
6357c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
6367c478bd9Sstevel@tonic-gate 	consms_lq_t	*prev_lq;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	linkp = (struct linkblk *)mp->b_cont->b_rptr;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	prev_lq = NULL;
6437c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
6447c478bd9Sstevel@tonic-gate 		if (lq->lq_queue == linkp->l_qbot) {
6457c478bd9Sstevel@tonic-gate 			if (prev_lq)
6467c478bd9Sstevel@tonic-gate 				prev_lq->lq_next = lq->lq_next;
6477c478bd9Sstevel@tonic-gate 			else
6487c478bd9Sstevel@tonic-gate 				consms_state.consms_lqs = lq->lq_next;
6497c478bd9Sstevel@tonic-gate 			kmem_free(lq, sizeof (*lq));
6507c478bd9Sstevel@tonic-gate 			consms_state.consms_num_lqs--;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 			/*
6537c478bd9Sstevel@tonic-gate 			 * Check to see if mouse capabilities
6547c478bd9Sstevel@tonic-gate 			 * have changed.
6557c478bd9Sstevel@tonic-gate 			 */
6567c478bd9Sstevel@tonic-gate 			consms_check_caps();
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 			return (0);
6597c478bd9Sstevel@tonic-gate 		}
6607c478bd9Sstevel@tonic-gate 		prev_lq = lq;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	return (EINVAL);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate /*
6677c478bd9Sstevel@tonic-gate  * Link a specific mouse into our mouse list.
6687c478bd9Sstevel@tonic-gate  */
6697c478bd9Sstevel@tonic-gate static void
6707c478bd9Sstevel@tonic-gate consms_plink(queue_t *q, mblk_t *mp)
6717c478bd9Sstevel@tonic-gate {
6727c478bd9Sstevel@tonic-gate 	struct	linkblk	*linkp;
6737c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
6747c478bd9Sstevel@tonic-gate 	queue_t		*lowq;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	linkp = (struct linkblk *)mp->b_cont->b_rptr;
6797c478bd9Sstevel@tonic-gate 	lowq = linkp->l_qbot;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	lq = kmem_zalloc(sizeof (*lq), KM_SLEEP);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	lowq->q_ptr = (void *)lq;
6847c478bd9Sstevel@tonic-gate 	OTHERQ(lowq)->q_ptr = (void *)lq;
6857c478bd9Sstevel@tonic-gate 	lq->lq_queue = lowq;
6867c478bd9Sstevel@tonic-gate 	lq->lq_pending_plink = mp;
6877c478bd9Sstevel@tonic-gate 	lq->lq_pending_queue = q;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	/*
6907c478bd9Sstevel@tonic-gate 	 * Set the number of buttons to 3 by default
6917c478bd9Sstevel@tonic-gate 	 * in case the following MSIOBUTTONS ioctl fails.
6927c478bd9Sstevel@tonic-gate 	 */
6937c478bd9Sstevel@tonic-gate 	lq->lq_num_buttons = 3;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/*
6967c478bd9Sstevel@tonic-gate 	 * Begin to initialize this mouse.
6977c478bd9Sstevel@tonic-gate 	 */
6987c478bd9Sstevel@tonic-gate 	lq->lq_state = LQS_START;
6997c478bd9Sstevel@tonic-gate 	consms_lqs_ack_complete(lq, NULL);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate  * Initialize the newly hotplugged-in mouse,
7047c478bd9Sstevel@tonic-gate  * e.g. get the number of buttons, set event
7057c478bd9Sstevel@tonic-gate  * format. Then we add it into our list.
7067c478bd9Sstevel@tonic-gate  */
7077c478bd9Sstevel@tonic-gate static void
7087c478bd9Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *lq, mblk_t *mp)
7097c478bd9Sstevel@tonic-gate {
7107c478bd9Sstevel@tonic-gate 	mblk_t			*req = NULL;
7117c478bd9Sstevel@tonic-gate 	boolean_t		skipped = B_FALSE;
7127c478bd9Sstevel@tonic-gate 	wheel_state		*ws;
7137c478bd9Sstevel@tonic-gate 	Ms_screen_resolution	*sr;
7147c478bd9Sstevel@tonic-gate 	Ms_parms		*params;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	/*
7197c478bd9Sstevel@tonic-gate 	 * We try each ioctl even if the previous one fails
7207c478bd9Sstevel@tonic-gate 	 * until we reach LQS_DONE, and then add this lq
7217c478bd9Sstevel@tonic-gate 	 * into our lq list.
7227c478bd9Sstevel@tonic-gate 	 *
7237c478bd9Sstevel@tonic-gate 	 * If the message allocation fails, we skip this ioctl,
7247c478bd9Sstevel@tonic-gate 	 * set skipped flag to B_TRUE in order to skip the ioctl
7257c478bd9Sstevel@tonic-gate 	 * result, then we try next ioctl, go to next state.
7267c478bd9Sstevel@tonic-gate 	 */
7277c478bd9Sstevel@tonic-gate 	while ((lq->lq_state < LQS_DONE) && (req == NULL)) {
7287c478bd9Sstevel@tonic-gate 		switch (lq->lq_state) {
7297c478bd9Sstevel@tonic-gate 		case LQS_START:
7307c478bd9Sstevel@tonic-gate 			/*
7317c478bd9Sstevel@tonic-gate 			 * First, issue MSIOBUTTONS ioctl
7327c478bd9Sstevel@tonic-gate 			 * to get the number of buttons.
7337c478bd9Sstevel@tonic-gate 			 */
7347c478bd9Sstevel@tonic-gate 			req = mkiocb(MSIOBUTTONS);
7357c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
7367c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7377c478bd9Sstevel@tonic-gate 				freemsg(req);
7387c478bd9Sstevel@tonic-gate 				req = NULL;
7397c478bd9Sstevel@tonic-gate 			}
7407c478bd9Sstevel@tonic-gate 			if (req == NULL)
7417c478bd9Sstevel@tonic-gate 				skipped = B_TRUE;
7427c478bd9Sstevel@tonic-gate 			lq->lq_state++;
7437c478bd9Sstevel@tonic-gate 			break;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		case LQS_BUTTON_COUNT_PENDING:
7467c478bd9Sstevel@tonic-gate 			if (!skipped && mp && mp->b_cont &&
7477c478bd9Sstevel@tonic-gate 			    (mp->b_datap->db_type == M_IOCACK))
7487c478bd9Sstevel@tonic-gate 				lq->lq_num_buttons =
7497c478bd9Sstevel@tonic-gate 				    *(int *)mp->b_cont->b_rptr;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 			/*
7527c478bd9Sstevel@tonic-gate 			 * Second, issue VUIDGWHEELCOUNT ioctl
7537c478bd9Sstevel@tonic-gate 			 * to get the count of wheels.
7547c478bd9Sstevel@tonic-gate 			 */
7557c478bd9Sstevel@tonic-gate 			req = mkiocb(VUIDGWHEELCOUNT);
7567c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
7577c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7587c478bd9Sstevel@tonic-gate 				freemsg(req);
7597c478bd9Sstevel@tonic-gate 				req = NULL;
7607c478bd9Sstevel@tonic-gate 			}
7617c478bd9Sstevel@tonic-gate 			if (req == NULL)
7627c478bd9Sstevel@tonic-gate 				skipped = B_TRUE;
7637c478bd9Sstevel@tonic-gate 			lq->lq_state++;
7647c478bd9Sstevel@tonic-gate 			break;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 		case LQS_WHEEL_COUNT_PENDING:
7677c478bd9Sstevel@tonic-gate 			if (!skipped && mp && mp->b_cont &&
7687c478bd9Sstevel@tonic-gate 			    (mp->b_datap->db_type == M_IOCACK))
7697c478bd9Sstevel@tonic-gate 				lq->lq_num_wheels =
7707c478bd9Sstevel@tonic-gate 				    *(int *)mp->b_cont->b_rptr;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 			/*
7737c478bd9Sstevel@tonic-gate 			 * Third, issue VUIDSFORMAT ioctl
7747c478bd9Sstevel@tonic-gate 			 * to set the event format.
7757c478bd9Sstevel@tonic-gate 			 */
7767c478bd9Sstevel@tonic-gate 			req = mkiocb(VUIDSFORMAT);
7777c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
7787c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7797c478bd9Sstevel@tonic-gate 				freemsg(req);
7807c478bd9Sstevel@tonic-gate 				req = NULL;
7817c478bd9Sstevel@tonic-gate 			}
7827c478bd9Sstevel@tonic-gate 			if (req) {
7837c478bd9Sstevel@tonic-gate 				*(int *)req->b_cont->b_wptr =
7847c478bd9Sstevel@tonic-gate 				    consms_state.consms_vuid_format;
7857c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (int);
7867c478bd9Sstevel@tonic-gate 			}
7877c478bd9Sstevel@tonic-gate 			lq->lq_state++;
7887c478bd9Sstevel@tonic-gate 			break;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 		case LQS_SET_VUID_FORMAT_PENDING:
7917c478bd9Sstevel@tonic-gate 			/*
7927c478bd9Sstevel@tonic-gate 			 * Fourth, issue VUIDSWHEELSTATE ioctl
7937c478bd9Sstevel@tonic-gate 			 * to set the wheel state (enable or disable).
7947c478bd9Sstevel@tonic-gate 			 */
7957c478bd9Sstevel@tonic-gate 			req = mkiocb(VUIDSWHEELSTATE);
7967c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (wheel_state),
7977c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
7987c478bd9Sstevel@tonic-gate 				freemsg(req);
7997c478bd9Sstevel@tonic-gate 				req = NULL;
8007c478bd9Sstevel@tonic-gate 			}
8017c478bd9Sstevel@tonic-gate 			if (req) {
8027c478bd9Sstevel@tonic-gate 				ws = (wheel_state *)req->b_cont->b_wptr;
8037c478bd9Sstevel@tonic-gate 				ws->vers = VUID_WHEEL_STATE_VERS;
8047c478bd9Sstevel@tonic-gate 				ws->id = 0;	/* the first wheel */
8057c478bd9Sstevel@tonic-gate 				ws->stateflags =
8067c478bd9Sstevel@tonic-gate 				    consms_state.consms_wheel_state_bf & 1;
8077c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (wheel_state);
8087c478bd9Sstevel@tonic-gate 			}
8097c478bd9Sstevel@tonic-gate 			lq->lq_state++;
8107c478bd9Sstevel@tonic-gate 			break;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		case LQS_SET_WHEEL_STATE_PENDING:
8137c478bd9Sstevel@tonic-gate 			/*
8147c478bd9Sstevel@tonic-gate 			 * Fifth, issue MSIOSRESOLUTION ioctl
8157c478bd9Sstevel@tonic-gate 			 * to set the screen resolution for absolute mouse.
8167c478bd9Sstevel@tonic-gate 			 */
8177c478bd9Sstevel@tonic-gate 			req = mkiocb(MSIOSRESOLUTION);
8187c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont =
8197c478bd9Sstevel@tonic-gate 			    allocb(sizeof (Ms_screen_resolution),
8207c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
8217c478bd9Sstevel@tonic-gate 				freemsg(req);
8227c478bd9Sstevel@tonic-gate 				req = NULL;
8237c478bd9Sstevel@tonic-gate 			}
8247c478bd9Sstevel@tonic-gate 			if (req) {
8257c478bd9Sstevel@tonic-gate 				sr =
8267c478bd9Sstevel@tonic-gate 				    (Ms_screen_resolution *)req->b_cont->b_wptr;
8277c478bd9Sstevel@tonic-gate 				*sr = consms_state.consms_ms_sr;
8287c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr +=
8297c478bd9Sstevel@tonic-gate 				    sizeof (Ms_screen_resolution);
8307c478bd9Sstevel@tonic-gate 			}
8317c478bd9Sstevel@tonic-gate 			lq->lq_state++;
8327c478bd9Sstevel@tonic-gate 			break;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		case LQS_SET_RESOLUTION_PENDING:
8357c478bd9Sstevel@tonic-gate 			/*
8367c478bd9Sstevel@tonic-gate 			 * Sixth, issue MSIOSETPARMS ioctl
8377c478bd9Sstevel@tonic-gate 			 * to set the parameters for USB mouse.
8387c478bd9Sstevel@tonic-gate 			 */
8397c478bd9Sstevel@tonic-gate 			req = mkiocb(MSIOSETPARMS);
8407c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (Ms_parms),
8417c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
8427c478bd9Sstevel@tonic-gate 				freemsg(req);
8437c478bd9Sstevel@tonic-gate 				req = NULL;
8447c478bd9Sstevel@tonic-gate 			}
8457c478bd9Sstevel@tonic-gate 			if (req) {
8467c478bd9Sstevel@tonic-gate 				params = (Ms_parms *)req->b_cont->b_wptr;
8477c478bd9Sstevel@tonic-gate 				*params = consms_state.consms_ms_parms;
8487c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (Ms_parms);
8497c478bd9Sstevel@tonic-gate 			}
8507c478bd9Sstevel@tonic-gate 			lq->lq_state++;
8517c478bd9Sstevel@tonic-gate 			break;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 		case LQS_SET_PARMS_PENDING:
8547c478bd9Sstevel@tonic-gate 			/*
8557c478bd9Sstevel@tonic-gate 			 * All jobs are done, lq->lq_state is turned into
8567c478bd9Sstevel@tonic-gate 			 * LQS_DONE, and this lq is added into our list.
8577c478bd9Sstevel@tonic-gate 			 */
8587c478bd9Sstevel@tonic-gate 			lq->lq_state++;
8597c478bd9Sstevel@tonic-gate 			consms_add_lq(lq);
8607c478bd9Sstevel@tonic-gate 			break;
8617c478bd9Sstevel@tonic-gate 		}
8627c478bd9Sstevel@tonic-gate 	}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	if (lq->lq_state < LQS_DONE) {
8657c478bd9Sstevel@tonic-gate 		lq->lq_ioc_reply_func = consms_lqs_ack_complete;
8667c478bd9Sstevel@tonic-gate 		(void) putq(lq->lq_queue, req);
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate  * Add this specific lq into our list, finally reply
8727c478bd9Sstevel@tonic-gate  * the previous pending I_PLINK ioctl. Also check to
8737c478bd9Sstevel@tonic-gate  * see if mouse capabilities have changed, and send
8747c478bd9Sstevel@tonic-gate  * a dynamical notification event to upper layer if
8757c478bd9Sstevel@tonic-gate  * necessary.
8767c478bd9Sstevel@tonic-gate  */
8777c478bd9Sstevel@tonic-gate static void
8787c478bd9Sstevel@tonic-gate consms_add_lq(consms_lq_t *lq)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate 	struct	iocblk		*iocp;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	lq->lq_ioc_reply_func = NULL;
8857c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)lq->lq_pending_plink->b_rptr;
8867c478bd9Sstevel@tonic-gate 	iocp->ioc_error = 0;
8877c478bd9Sstevel@tonic-gate 	iocp->ioc_count = 0;
8887c478bd9Sstevel@tonic-gate 	iocp->ioc_rval = 0;
8897c478bd9Sstevel@tonic-gate 	lq->lq_pending_plink->b_datap->db_type = M_IOCACK;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	/* Reply to the I_PLINK ioctl. */
8927c478bd9Sstevel@tonic-gate 	qreply(lq->lq_pending_queue, lq->lq_pending_plink);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	lq->lq_pending_plink = NULL;
8957c478bd9Sstevel@tonic-gate 	lq->lq_pending_queue = NULL;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/*
8987c478bd9Sstevel@tonic-gate 	 * Add this lq into list.
8997c478bd9Sstevel@tonic-gate 	 */
9007c478bd9Sstevel@tonic-gate 	consms_state.consms_num_lqs++;
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	lq->lq_next = consms_state.consms_lqs;
9037c478bd9Sstevel@tonic-gate 	consms_state.consms_lqs = lq;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	/*
9067c478bd9Sstevel@tonic-gate 	 * Check to see if mouse capabilities
9077c478bd9Sstevel@tonic-gate 	 * have changed.
9087c478bd9Sstevel@tonic-gate 	 */
9097c478bd9Sstevel@tonic-gate 	consms_check_caps();
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate static void
9157c478bd9Sstevel@tonic-gate consms_check_caps(void)
9167c478bd9Sstevel@tonic-gate {
9177c478bd9Sstevel@tonic-gate 	consms_lq_t *lq;
9187c478bd9Sstevel@tonic-gate 	int	max_buttons = 0;
9197c478bd9Sstevel@tonic-gate 	int	max_wheels = 0;
9207c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	/*
9237c478bd9Sstevel@tonic-gate 	 * Check to see if the number of buttons
9247c478bd9Sstevel@tonic-gate 	 * and the number of wheels have changed.
9257c478bd9Sstevel@tonic-gate 	 */
9267c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
9277c478bd9Sstevel@tonic-gate 		max_buttons = CONSMS_MAX(max_buttons, lq->lq_num_buttons);
9287c478bd9Sstevel@tonic-gate 		max_wheels = CONSMS_MAX(max_wheels, lq->lq_num_wheels);
9297c478bd9Sstevel@tonic-gate 	}
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	if (max_buttons != consms_state.consms_num_buttons) {
9327c478bd9Sstevel@tonic-gate 		/*
9337c478bd9Sstevel@tonic-gate 		 * Since the number of buttons have changed,
9347c478bd9Sstevel@tonic-gate 		 * send a MOUSE_CAP_CHANGE_NUM_BUT dynamical
9357c478bd9Sstevel@tonic-gate 		 * notification event to upper layer.
9367c478bd9Sstevel@tonic-gate 		 */
9377c478bd9Sstevel@tonic-gate 		consms_state.consms_num_buttons = max_buttons;
9387c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL) {
9397c478bd9Sstevel@tonic-gate 			if ((mp = consms_new_firm_event(
9407c478bd9Sstevel@tonic-gate 			    MOUSE_CAP_CHANGE_NUM_BUT,
9417c478bd9Sstevel@tonic-gate 			    consms_state.consms_num_buttons)) != NULL) {
9427c478bd9Sstevel@tonic-gate 				putnext(upperqueue, mp);
9437c478bd9Sstevel@tonic-gate 			}
9447c478bd9Sstevel@tonic-gate 		}
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	if (max_wheels != consms_state.consms_num_wheels) {
9487c478bd9Sstevel@tonic-gate 		/*
9497c478bd9Sstevel@tonic-gate 		 * Since the number of wheels have changed,
9507c478bd9Sstevel@tonic-gate 		 * send a MOUSE_CAP_CHANGE_NUM_WHEEL dynamical
9517c478bd9Sstevel@tonic-gate 		 * notification event to upper layer.
9527c478bd9Sstevel@tonic-gate 		 */
9537c478bd9Sstevel@tonic-gate 		consms_state.consms_num_wheels = max_wheels;
9547c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL) {
9557c478bd9Sstevel@tonic-gate 			if ((mp = consms_new_firm_event(
9567c478bd9Sstevel@tonic-gate 			    MOUSE_CAP_CHANGE_NUM_WHEEL,
9577c478bd9Sstevel@tonic-gate 			    consms_state.consms_num_wheels)) != NULL) {
9587c478bd9Sstevel@tonic-gate 				putnext(upperqueue, mp);
9597c478bd9Sstevel@tonic-gate 			}
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate /*
9657c478bd9Sstevel@tonic-gate  * Allocate a dynamical notification event.
9667c478bd9Sstevel@tonic-gate  */
9677c478bd9Sstevel@tonic-gate static mblk_t *
9687c478bd9Sstevel@tonic-gate consms_new_firm_event(int id, int value)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate 	Firm_event *fep;
9717c478bd9Sstevel@tonic-gate 	mblk_t	*tmp;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
9747c478bd9Sstevel@tonic-gate 		fep = (Firm_event *)tmp->b_wptr;
9757c478bd9Sstevel@tonic-gate 		fep->id = id;
9767c478bd9Sstevel@tonic-gate 		fep->pair_type = FE_PAIR_NONE;
9777c478bd9Sstevel@tonic-gate 		fep->pair = NULL;
9787c478bd9Sstevel@tonic-gate 		fep->value = value;
9797c478bd9Sstevel@tonic-gate 		tmp->b_wptr += sizeof (Firm_event);
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	return (tmp);
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  * Start of dispatching interfaces as a multiplexor
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate  * There is a global msg list (consms_mux_msg),
9917c478bd9Sstevel@tonic-gate  * which is used to link all ioctl messages from
9927c478bd9Sstevel@tonic-gate  * upper layer, which are currently being processed.
9937c478bd9Sstevel@tonic-gate  *
9947c478bd9Sstevel@tonic-gate  * consms_mux_link_msg links a msg into the list,
9957c478bd9Sstevel@tonic-gate  * consms_mux_unlink_msg unlinks a msg from the list,
9967c478bd9Sstevel@tonic-gate  * consms_mux_find_msg finds a msg from the list
9977c478bd9Sstevel@tonic-gate  * according to its unique id.
9987c478bd9Sstevel@tonic-gate  *
9997c478bd9Sstevel@tonic-gate  * The id of each msg is taken from stream's mp,
10007c478bd9Sstevel@tonic-gate  * so the id is supposed to be unique.
10017c478bd9Sstevel@tonic-gate  */
10027c478bd9Sstevel@tonic-gate static void
10037c478bd9Sstevel@tonic-gate consms_mux_link_msg(consms_msg_t *msg)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
10067c478bd9Sstevel@tonic-gate 	msg->msg_next = consms_mux_msg;
10077c478bd9Sstevel@tonic-gate 	consms_mux_msg = msg;
10087c478bd9Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate static consms_msg_t *
10127c478bd9Sstevel@tonic-gate consms_mux_unlink_msg(uint_t msg_id)
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate 	consms_msg_t	*msg;
10157c478bd9Sstevel@tonic-gate 	consms_msg_t	*prev_msg;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
10187c478bd9Sstevel@tonic-gate 	prev_msg = NULL;
10197c478bd9Sstevel@tonic-gate 	for (msg = consms_mux_msg; msg != NULL;
10207c478bd9Sstevel@tonic-gate 	    prev_msg = msg, msg = msg->msg_next) {
10217c478bd9Sstevel@tonic-gate 		if (msg->msg_id == msg_id)
10227c478bd9Sstevel@tonic-gate 			break;
10237c478bd9Sstevel@tonic-gate 	}
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	if (msg != NULL) {
10267c478bd9Sstevel@tonic-gate 		if (prev_msg != NULL) {
10277c478bd9Sstevel@tonic-gate 			prev_msg->msg_next = msg->msg_next;
10287c478bd9Sstevel@tonic-gate 		} else {
10297c478bd9Sstevel@tonic-gate 			consms_mux_msg = consms_mux_msg->msg_next;
10307c478bd9Sstevel@tonic-gate 		}
10317c478bd9Sstevel@tonic-gate 		msg->msg_next = NULL;
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	return (msg);
10367c478bd9Sstevel@tonic-gate }
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate static consms_msg_t *
10397c478bd9Sstevel@tonic-gate consms_mux_find_msg(uint_t msg_id)
10407c478bd9Sstevel@tonic-gate {
10417c478bd9Sstevel@tonic-gate 	consms_msg_t	*msg;
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
10447c478bd9Sstevel@tonic-gate 	for (msg = consms_mux_msg; msg != NULL; msg = msg->msg_next) {
10457c478bd9Sstevel@tonic-gate 		if (msg->msg_id == msg_id)
10467c478bd9Sstevel@tonic-gate 			break;
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	return (msg);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate /*
10547c478bd9Sstevel@tonic-gate  * Received ACK or NAK from lower mice
10557c478bd9Sstevel@tonic-gate  *
10567c478bd9Sstevel@tonic-gate  * For non-transparent ioctl, the msg->msg_rsp_list
10577c478bd9Sstevel@tonic-gate  * is always NULL; for transparent ioctl, it
10587c478bd9Sstevel@tonic-gate  * remembers the M_COPYIN/M_COPYOUT request
10597c478bd9Sstevel@tonic-gate  * messages from lower mice. So here if msg->msg_rsp_list
10607c478bd9Sstevel@tonic-gate  * is NULL (after receiving all ACK/NAKs), we
10617c478bd9Sstevel@tonic-gate  * are done with this specific ioctl.
10627c478bd9Sstevel@tonic-gate  *
10637c478bd9Sstevel@tonic-gate  * As long as one of lower mice responds success,
10647c478bd9Sstevel@tonic-gate  * we treat it success for a ioctl.
10657c478bd9Sstevel@tonic-gate  */
10667c478bd9Sstevel@tonic-gate static void
10677c478bd9Sstevel@tonic-gate consms_mux_ack(consms_msg_t *msg, mblk_t *mp)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate 	mblk_t	*ack_mp;
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	/* increment response_nums */
10727c478bd9Sstevel@tonic-gate 	msg->msg_num_responses++;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type == M_IOCACK) {
10757c478bd9Sstevel@tonic-gate 		/*
10767c478bd9Sstevel@tonic-gate 		 * Received ACK from lower, then
10777c478bd9Sstevel@tonic-gate 		 * this is the last step for both
10787c478bd9Sstevel@tonic-gate 		 * non-transparent and transparent
10797c478bd9Sstevel@tonic-gate 		 * ioctl. We only need to remember
10807c478bd9Sstevel@tonic-gate 		 * one of the ACKs, finally reply
10817c478bd9Sstevel@tonic-gate 		 * this ACK to upper layer for this
10827c478bd9Sstevel@tonic-gate 		 * specific ioctl.
10837c478bd9Sstevel@tonic-gate 		 */
10847c478bd9Sstevel@tonic-gate 		ASSERT(msg->msg_rsp_list == NULL);
10857c478bd9Sstevel@tonic-gate 		if (msg->msg_ack_mp == NULL) {
10867c478bd9Sstevel@tonic-gate 			msg->msg_ack_mp = mp;
10877c478bd9Sstevel@tonic-gate 			mp = NULL;
10887c478bd9Sstevel@tonic-gate 		}
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	/*
10927c478bd9Sstevel@tonic-gate 	 * Check to see if all lower mice have responded
10937c478bd9Sstevel@tonic-gate 	 * to our dispatching ioctl.
10947c478bd9Sstevel@tonic-gate 	 */
10957c478bd9Sstevel@tonic-gate 	if (msg->msg_num_responses == msg->msg_num_requests) {
10967c478bd9Sstevel@tonic-gate 		if ((msg->msg_ack_mp == NULL) &&
10977c478bd9Sstevel@tonic-gate 		    (msg->msg_rsp_list == NULL)) {
10987c478bd9Sstevel@tonic-gate 			/*
10997c478bd9Sstevel@tonic-gate 			 * All are NAKed.
11007c478bd9Sstevel@tonic-gate 			 */
11017c478bd9Sstevel@tonic-gate 			ack_mp = mp;
11027c478bd9Sstevel@tonic-gate 			mp = NULL;
11037c478bd9Sstevel@tonic-gate 		} else if (msg->msg_rsp_list == NULL) {
11047c478bd9Sstevel@tonic-gate 			/*
11057c478bd9Sstevel@tonic-gate 			 * The last step and at least one ACKed.
11067c478bd9Sstevel@tonic-gate 			 */
11077c478bd9Sstevel@tonic-gate 			ack_mp = msg->msg_ack_mp;
11087c478bd9Sstevel@tonic-gate 			consms_mux_cache_states(msg->msg_request);
11097c478bd9Sstevel@tonic-gate 			consms_mux_max_wheel_report(ack_mp);
11107c478bd9Sstevel@tonic-gate 		} else {
11117c478bd9Sstevel@tonic-gate 			/*
11127c478bd9Sstevel@tonic-gate 			 * This is a NAK, but we have
11137c478bd9Sstevel@tonic-gate 			 * already received M_COPYIN
11147c478bd9Sstevel@tonic-gate 			 * or M_COPYOUT request from
11157c478bd9Sstevel@tonic-gate 			 * at least one of lower mice.
11167c478bd9Sstevel@tonic-gate 			 * (msg->msg_rsp_list != NULL)
11177c478bd9Sstevel@tonic-gate 			 *
11187c478bd9Sstevel@tonic-gate 			 * Still copyin or copyout.
11197c478bd9Sstevel@tonic-gate 			 */
11207c478bd9Sstevel@tonic-gate 			ack_mp = msg->msg_rsp_list->rsp_mp;
11217c478bd9Sstevel@tonic-gate 			consms_mux_max_wheel_report(ack_mp);
11227c478bd9Sstevel@tonic-gate 		}
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 		qreply(msg->msg_queue, ack_mp);
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 		if (msg->msg_rsp_list == NULL) {
11277c478bd9Sstevel@tonic-gate 			/*
11287c478bd9Sstevel@tonic-gate 			 * We are done with this ioctl.
11297c478bd9Sstevel@tonic-gate 			 */
11307c478bd9Sstevel@tonic-gate 			if (msg->msg_request)
11317c478bd9Sstevel@tonic-gate 				freemsg(msg->msg_request);
11327c478bd9Sstevel@tonic-gate 			(void) consms_mux_unlink_msg(msg->msg_id);
11337c478bd9Sstevel@tonic-gate 			kmem_free(msg, sizeof (*msg));
11347c478bd9Sstevel@tonic-gate 		}
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	if (mp) {
11387c478bd9Sstevel@tonic-gate 		freemsg(mp);
11397c478bd9Sstevel@tonic-gate 	}
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate /*
11437c478bd9Sstevel@tonic-gate  * Received M_COPYIN or M_COPYOUT request from
11447c478bd9Sstevel@tonic-gate  * lower mice for transparent ioctl
11457c478bd9Sstevel@tonic-gate  *
11467c478bd9Sstevel@tonic-gate  * We remember each M_COPYIN/M_COPYOUT into the
11477c478bd9Sstevel@tonic-gate  * msg->msg_rsp_list, reply upper layer using the first
11487c478bd9Sstevel@tonic-gate  * M_COPYIN/M_COPYOUT in the list after receiving
11497c478bd9Sstevel@tonic-gate  * all responses from lower mice, even if some of
11507c478bd9Sstevel@tonic-gate  * them return NAKs.
11517c478bd9Sstevel@tonic-gate  */
11527c478bd9Sstevel@tonic-gate static void
11537c478bd9Sstevel@tonic-gate consms_mux_copyreq(queue_t *q, consms_msg_t *msg, mblk_t *mp)
11547c478bd9Sstevel@tonic-gate {
11557c478bd9Sstevel@tonic-gate 	consms_response_t	*rsp;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	rsp = (consms_response_t *)kmem_zalloc(sizeof (*rsp), KM_SLEEP);
11587c478bd9Sstevel@tonic-gate 	rsp->rsp_mp = mp;
11597c478bd9Sstevel@tonic-gate 	rsp->rsp_queue = q;
11607c478bd9Sstevel@tonic-gate 	if (msg->msg_rsp_list) {
11617c478bd9Sstevel@tonic-gate 		rsp->rsp_next = msg->msg_rsp_list;
11627c478bd9Sstevel@tonic-gate 	}
11637c478bd9Sstevel@tonic-gate 	msg->msg_rsp_list = rsp;
11647c478bd9Sstevel@tonic-gate 	msg->msg_num_responses++;
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	if (msg->msg_num_responses == msg->msg_num_requests) {
11677c478bd9Sstevel@tonic-gate 		consms_mux_max_wheel_report(msg->msg_rsp_list->rsp_mp);
11687c478bd9Sstevel@tonic-gate 		qreply(msg->msg_queue, msg->msg_rsp_list->rsp_mp);
11697c478bd9Sstevel@tonic-gate 	}
11707c478bd9Sstevel@tonic-gate }
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate /*
11737c478bd9Sstevel@tonic-gate  * Do the real job for updating M_COPYIN/M_COPYOUT
11747c478bd9Sstevel@tonic-gate  * request with the mp of M_IOCDATA, then put it
11757c478bd9Sstevel@tonic-gate  * down to lower mice.
11767c478bd9Sstevel@tonic-gate  */
11777c478bd9Sstevel@tonic-gate static void
11787c478bd9Sstevel@tonic-gate consms_mux_disp_iocdata(consms_response_t *rsp, mblk_t *mp)
11797c478bd9Sstevel@tonic-gate {
11807c478bd9Sstevel@tonic-gate 	mblk_t	*down_mp = rsp->rsp_mp;
11817c478bd9Sstevel@tonic-gate 	struct copyresp *copyresp = (struct copyresp *)mp->b_rptr;
11827c478bd9Sstevel@tonic-gate 	struct copyresp *newresp = (struct copyresp *)down_mp->b_rptr;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	/*
11857c478bd9Sstevel@tonic-gate 	 * Update the rval.
11867c478bd9Sstevel@tonic-gate 	 */
11877c478bd9Sstevel@tonic-gate 	newresp->cp_rval = copyresp->cp_rval;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/*
11907c478bd9Sstevel@tonic-gate 	 * Update the db_type to M_IOCDATA.
11917c478bd9Sstevel@tonic-gate 	 */
11927c478bd9Sstevel@tonic-gate 	down_mp->b_datap->db_type = mp->b_datap->db_type;
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	/*
11957c478bd9Sstevel@tonic-gate 	 * Update the b_cont.
11967c478bd9Sstevel@tonic-gate 	 */
11977c478bd9Sstevel@tonic-gate 	if (down_mp->b_cont != NULL) {
11987c478bd9Sstevel@tonic-gate 		freemsg(down_mp->b_cont);
11997c478bd9Sstevel@tonic-gate 		down_mp->b_cont = NULL;
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 	if (mp->b_cont != NULL) {
12027c478bd9Sstevel@tonic-gate 		down_mp->b_cont = copymsg(mp->b_cont);
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	/*
12067c478bd9Sstevel@tonic-gate 	 * Put it down.
12077c478bd9Sstevel@tonic-gate 	 */
12087c478bd9Sstevel@tonic-gate 	(void) putq(WR(rsp->rsp_queue), down_mp);
12097c478bd9Sstevel@tonic-gate }
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate /*
12127c478bd9Sstevel@tonic-gate  * Dispatch M_IOCDATA down to all lower mice
12137c478bd9Sstevel@tonic-gate  * for transparent ioctl.
12147c478bd9Sstevel@tonic-gate  *
12157c478bd9Sstevel@tonic-gate  * We update each M_COPYIN/M_COPYOUT in the
12167c478bd9Sstevel@tonic-gate  * msg->msg_rsp_list with the M_IOCDATA.
12177c478bd9Sstevel@tonic-gate  */
12187c478bd9Sstevel@tonic-gate static void
12197c478bd9Sstevel@tonic-gate consms_mux_iocdata(consms_msg_t *msg, mblk_t *mp)
12207c478bd9Sstevel@tonic-gate {
12217c478bd9Sstevel@tonic-gate 	consms_response_t	*rsp;
12227c478bd9Sstevel@tonic-gate 	consms_response_t	*tmp;
12237c478bd9Sstevel@tonic-gate 	consms_response_t	*first;
12247c478bd9Sstevel@tonic-gate 	struct copyresp		*copyresp;
12257c478bd9Sstevel@tonic-gate 	int			request_nums;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	ASSERT(msg->msg_rsp_list != NULL);
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	/*
12307c478bd9Sstevel@tonic-gate 	 * We should remember the ioc data for
12317c478bd9Sstevel@tonic-gate 	 * VUIDSWHEELSTATE, and MSIOSRESOLUTION,
12327c478bd9Sstevel@tonic-gate 	 * for we will cache the wheel state and
12337c478bd9Sstevel@tonic-gate 	 * the screen resolution later if ACKed.
12347c478bd9Sstevel@tonic-gate 	 */
12357c478bd9Sstevel@tonic-gate 	copyresp = (struct copyresp *)mp->b_rptr;
12367c478bd9Sstevel@tonic-gate 	if ((copyresp->cp_cmd == VUIDSWHEELSTATE) ||
12377c478bd9Sstevel@tonic-gate 	    (copyresp->cp_cmd == MSIOSRESOLUTION)) {
12387c478bd9Sstevel@tonic-gate 		freemsg(msg->msg_request);
12397c478bd9Sstevel@tonic-gate 		msg->msg_request = copymsg(mp);
12407c478bd9Sstevel@tonic-gate 	}
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	/*
12437c478bd9Sstevel@tonic-gate 	 * Update request numbers and response numbers.
12447c478bd9Sstevel@tonic-gate 	 */
12457c478bd9Sstevel@tonic-gate 	msg->msg_num_requests = msg->msg_num_responses;
12467c478bd9Sstevel@tonic-gate 	msg->msg_num_responses = 0;
12477c478bd9Sstevel@tonic-gate 	request_nums = 1;
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	/*
12507c478bd9Sstevel@tonic-gate 	 * Since we have use the first M_COPYIN/M_COPYOUT
12517c478bd9Sstevel@tonic-gate 	 * in the msg_rsp_list to reply upper layer, the mp
12527c478bd9Sstevel@tonic-gate 	 * of M_IOCDATA can be directly used for that.
12537c478bd9Sstevel@tonic-gate 	 */
12547c478bd9Sstevel@tonic-gate 	first = msg->msg_rsp_list;
12557c478bd9Sstevel@tonic-gate 	rsp = first->rsp_next;
12567c478bd9Sstevel@tonic-gate 	msg->msg_rsp_list = NULL;
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	for (rsp = first->rsp_next; rsp != NULL; ) {
12597c478bd9Sstevel@tonic-gate 		tmp = rsp;
12607c478bd9Sstevel@tonic-gate 		rsp = rsp->rsp_next;
12617c478bd9Sstevel@tonic-gate 		consms_mux_disp_iocdata(tmp, mp);
12627c478bd9Sstevel@tonic-gate 		kmem_free(tmp, sizeof (*tmp));
12637c478bd9Sstevel@tonic-gate 		request_nums++;
12647c478bd9Sstevel@tonic-gate 	}
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 	/* Must set the request number before the last q. */
12677c478bd9Sstevel@tonic-gate 	msg->msg_num_requests = request_nums;
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	/* the first one */
12707c478bd9Sstevel@tonic-gate 	(void) putq(WR(first->rsp_queue), mp);
12717c478bd9Sstevel@tonic-gate 	kmem_free(first, sizeof (*first));
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate /*
12767c478bd9Sstevel@tonic-gate  * Here we update the number of wheels with
12777c478bd9Sstevel@tonic-gate  * the virtual mouse for VUIDGWHEELCOUNT ioctl.
12787c478bd9Sstevel@tonic-gate  */
12797c478bd9Sstevel@tonic-gate static void
12807c478bd9Sstevel@tonic-gate consms_mux_max_wheel_report(mblk_t *mp)
12817c478bd9Sstevel@tonic-gate {
12827c478bd9Sstevel@tonic-gate 	struct iocblk		*iocp;
12837c478bd9Sstevel@tonic-gate 	int			num_wheels;
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	if (mp == NULL || mp->b_cont == NULL)
12867c478bd9Sstevel@tonic-gate 		return;
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	if ((iocp->ioc_cmd == VUIDGWHEELCOUNT) &&
12917c478bd9Sstevel@tonic-gate 	    (mp->b_datap->db_type == M_COPYOUT)) {
12927c478bd9Sstevel@tonic-gate 		num_wheels = *(int *)mp->b_cont->b_rptr;
12937c478bd9Sstevel@tonic-gate 		if (num_wheels < consms_state.consms_num_wheels) {
12947c478bd9Sstevel@tonic-gate 			*(int *)mp->b_cont->b_rptr =
12957c478bd9Sstevel@tonic-gate 			    consms_state.consms_num_wheels;
12967c478bd9Sstevel@tonic-gate 		}
12977c478bd9Sstevel@tonic-gate 	}
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate /*
13017c478bd9Sstevel@tonic-gate  * Update the virtual mouse state variables with
13027c478bd9Sstevel@tonic-gate  * the latest value from upper layer when these
13037c478bd9Sstevel@tonic-gate  * set ioctls return success. Thus we can update
13047c478bd9Sstevel@tonic-gate  * low mice with the latest state values during
13057c478bd9Sstevel@tonic-gate  * hotplug.
13067c478bd9Sstevel@tonic-gate  */
13077c478bd9Sstevel@tonic-gate static void
13087c478bd9Sstevel@tonic-gate consms_mux_cache_states(mblk_t *mp)
13097c478bd9Sstevel@tonic-gate {
13107c478bd9Sstevel@tonic-gate 	struct iocblk 		*iocp;
13117c478bd9Sstevel@tonic-gate 	Ms_parms		*parms;
13127c478bd9Sstevel@tonic-gate 	Ms_screen_resolution	*sr;
13137c478bd9Sstevel@tonic-gate 	wheel_state		*ws;
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	if (mp == NULL || mp->b_cont == NULL)
13167c478bd9Sstevel@tonic-gate 		return;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
13197c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
13207c478bd9Sstevel@tonic-gate 	case VUIDSFORMAT:
13217c478bd9Sstevel@tonic-gate 		consms_state.consms_vuid_format = *(int *)mp->b_cont->b_rptr;
13227c478bd9Sstevel@tonic-gate 		break;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	case MSIOSETPARMS:
13257c478bd9Sstevel@tonic-gate 		parms = (Ms_parms *)mp->b_cont->b_rptr;
13267c478bd9Sstevel@tonic-gate 		consms_state.consms_ms_parms = *parms;
13277c478bd9Sstevel@tonic-gate 		break;
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	case MSIOSRESOLUTION:
13307c478bd9Sstevel@tonic-gate 		sr = (Ms_screen_resolution *)mp->b_cont->b_rptr;
13317c478bd9Sstevel@tonic-gate 		consms_state.consms_ms_sr = *sr;
13327c478bd9Sstevel@tonic-gate 		break;
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	case VUIDSWHEELSTATE:
13357c478bd9Sstevel@tonic-gate 		ws = (wheel_state *)mp->b_cont->b_rptr;
13367c478bd9Sstevel@tonic-gate 		consms_state.consms_wheel_state_bf =
13377c478bd9Sstevel@tonic-gate 		    (ws->stateflags << ws->id) |
13387c478bd9Sstevel@tonic-gate 		    (consms_state.consms_wheel_state_bf & ~(1 << ws->id));
13397c478bd9Sstevel@tonic-gate 		break;
13407c478bd9Sstevel@tonic-gate 	}
13417c478bd9Sstevel@tonic-gate }
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate /*
13447c478bd9Sstevel@tonic-gate  * Dispatch ioctl mp (non-transparent and transparent)
13457c478bd9Sstevel@tonic-gate  * down to all lower mice.
13467c478bd9Sstevel@tonic-gate  *
13477c478bd9Sstevel@tonic-gate  * First, create a pending message for this mp, link it into
13487c478bd9Sstevel@tonic-gate  * the global messages list. Then wait for ACK/NAK for
13497c478bd9Sstevel@tonic-gate  * non-transparent ioctl, COPYIN/COPYOUT for transparent
13507c478bd9Sstevel@tonic-gate  * ioctl.
13517c478bd9Sstevel@tonic-gate  */
13527c478bd9Sstevel@tonic-gate static int
13537c478bd9Sstevel@tonic-gate consms_mux_disp_ioctl(queue_t *q, mblk_t *mp)
13547c478bd9Sstevel@tonic-gate {
13557c478bd9Sstevel@tonic-gate 	struct iocblk	*iocp;
13567c478bd9Sstevel@tonic-gate 	consms_msg_t	*msg;
13577c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
13587c478bd9Sstevel@tonic-gate 	mblk_t		*copy_mp;
13597c478bd9Sstevel@tonic-gate 	int		error = 0;
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
13627c478bd9Sstevel@tonic-gate 	msg = (consms_msg_t *)kmem_zalloc(sizeof (*msg), KM_SLEEP);
13637c478bd9Sstevel@tonic-gate 	msg->msg_id = iocp->ioc_id;
13647c478bd9Sstevel@tonic-gate 	msg->msg_request = mp;
13657c478bd9Sstevel@tonic-gate 	msg->msg_queue = q;
13667c478bd9Sstevel@tonic-gate 	msg->msg_num_requests = consms_state.consms_num_lqs;
13677c478bd9Sstevel@tonic-gate 	consms_mux_link_msg(msg);
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
13707c478bd9Sstevel@tonic-gate 		if ((copy_mp = copymsg(mp)) != NULL) {
13717c478bd9Sstevel@tonic-gate 			(void) putq(lq->lq_queue, copy_mp);
13727c478bd9Sstevel@tonic-gate 		} else {
13737c478bd9Sstevel@tonic-gate 			/*
13747c478bd9Sstevel@tonic-gate 			 * If copymsg fails, we ignore this lq and
13757c478bd9Sstevel@tonic-gate 			 * try next one. As long as one of them succeeds,
13767c478bd9Sstevel@tonic-gate 			 * we dispatch this ioctl down. And later as long
13777c478bd9Sstevel@tonic-gate 			 * as one of the lower drivers return success, we
13787c478bd9Sstevel@tonic-gate 			 * reply to this ioctl with success.
13797c478bd9Sstevel@tonic-gate 			 */
13807c478bd9Sstevel@tonic-gate 			msg->msg_num_requests--;
13817c478bd9Sstevel@tonic-gate 		}
13827c478bd9Sstevel@tonic-gate 	}
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	if (msg->msg_num_requests <= 0) {
13857c478bd9Sstevel@tonic-gate 		/*
13867c478bd9Sstevel@tonic-gate 		 * Since copymsg fails for all lqs, we NAK this ioctl.
13877c478bd9Sstevel@tonic-gate 		 */
13887c478bd9Sstevel@tonic-gate 		(void) consms_mux_unlink_msg(msg->msg_id);
13897c478bd9Sstevel@tonic-gate 		kmem_free(msg, sizeof (*msg));
13907c478bd9Sstevel@tonic-gate 		error = ENOMEM;
13917c478bd9Sstevel@tonic-gate 	}
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	return (error);
13947c478bd9Sstevel@tonic-gate }
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate /*
13977c478bd9Sstevel@tonic-gate  * Dispatch M_DATA and M_FLUSH message down to all
13987c478bd9Sstevel@tonic-gate  * lower mice, and there are no acknowledgements
13997c478bd9Sstevel@tonic-gate  * for them. Here we just copy the mp and then
14007c478bd9Sstevel@tonic-gate  * put it into the lower queues.
14017c478bd9Sstevel@tonic-gate  */
14027c478bd9Sstevel@tonic-gate static void
14037c478bd9Sstevel@tonic-gate consms_mux_disp_data(mblk_t *mp)
14047c478bd9Sstevel@tonic-gate {
14057c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
14067c478bd9Sstevel@tonic-gate 	mblk_t		*copy_mp;
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
14097c478bd9Sstevel@tonic-gate 		if ((copy_mp = copymsg(mp)) != NULL) {
14107c478bd9Sstevel@tonic-gate 			(void) putq(lq->lq_queue, copy_mp);
14117c478bd9Sstevel@tonic-gate 		}
14127c478bd9Sstevel@tonic-gate 	}
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	freemsg(mp);
14157c478bd9Sstevel@tonic-gate }
1416