xref: /titanic_51/usr/src/uts/common/io/consms.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Console mouse driver for Sun.
31*7c478bd9Sstevel@tonic-gate  * The console "zs" port is linked under us, with the "ms" module pushed
32*7c478bd9Sstevel@tonic-gate  * on top of it.
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * This device merely provides a way to have "/dev/mouse" automatically
35*7c478bd9Sstevel@tonic-gate  * have the "ms" module present. Due to problems with the way the "specfs"
36*7c478bd9Sstevel@tonic-gate  * file system works, you can't use an indirect device (a "stat" on
37*7c478bd9Sstevel@tonic-gate  * "/dev/mouse" won't get the right snode, so you won't get the right time
38*7c478bd9Sstevel@tonic-gate  * of last access), and due to problems with the kernel window system code,
39*7c478bd9Sstevel@tonic-gate  * you can't use a "cons"-like driver ("/dev/mouse" won't be a streams device,
40*7c478bd9Sstevel@tonic-gate  * even though operations on it get turned into operations on the real stream).
41*7c478bd9Sstevel@tonic-gate  *
42*7c478bd9Sstevel@tonic-gate  * This module supports multiple mice connected to the system at the same time.
43*7c478bd9Sstevel@tonic-gate  * All the mice are linked under consms, and act as a mouse with replicated
44*7c478bd9Sstevel@tonic-gate  * clicks. Only USB and PS/2 mouse are supported to be virtual mouse now.
45*7c478bd9Sstevel@tonic-gate  */
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/vuid_wheel.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/msio.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/consms.h>
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate static void consms_plink(queue_t *, mblk_t *);
65*7c478bd9Sstevel@tonic-gate static int consms_punlink(queue_t *, mblk_t *);
66*7c478bd9Sstevel@tonic-gate static void
67*7c478bd9Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *, mblk_t *);
68*7c478bd9Sstevel@tonic-gate static void consms_add_lq(consms_lq_t *);
69*7c478bd9Sstevel@tonic-gate static void consms_check_caps(void);
70*7c478bd9Sstevel@tonic-gate static mblk_t *consms_new_firm_event(int, int);
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate static void consms_mux_max_wheel_report(mblk_t *);
73*7c478bd9Sstevel@tonic-gate static void consms_mux_cache_states(mblk_t *);
74*7c478bd9Sstevel@tonic-gate static void consms_mux_link_msg(consms_msg_t *);
75*7c478bd9Sstevel@tonic-gate static consms_msg_t *consms_mux_unlink_msg(uint_t);
76*7c478bd9Sstevel@tonic-gate static consms_msg_t *consms_mux_find_msg(uint_t);
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate static void consms_mux_iocdata(consms_msg_t *, mblk_t *);
79*7c478bd9Sstevel@tonic-gate static void consms_mux_disp_iocdata(consms_response_t *, mblk_t *);
80*7c478bd9Sstevel@tonic-gate static int consms_mux_disp_ioctl(queue_t *, mblk_t *);
81*7c478bd9Sstevel@tonic-gate static void consms_mux_copyreq(queue_t *, consms_msg_t *, mblk_t *);
82*7c478bd9Sstevel@tonic-gate static void consms_mux_ack(consms_msg_t *, mblk_t *);
83*7c478bd9Sstevel@tonic-gate static void consms_mux_disp_data(mblk_t *);
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static int	consmsopen();
87*7c478bd9Sstevel@tonic-gate static int	consmsclose();
88*7c478bd9Sstevel@tonic-gate static void	consmsuwput();
89*7c478bd9Sstevel@tonic-gate static void	consmslrput();
90*7c478bd9Sstevel@tonic-gate static void	consmslwserv();
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate static struct module_info consmsm_info = {
93*7c478bd9Sstevel@tonic-gate 	0,
94*7c478bd9Sstevel@tonic-gate 	"consms",
95*7c478bd9Sstevel@tonic-gate 	0,
96*7c478bd9Sstevel@tonic-gate 	1024,
97*7c478bd9Sstevel@tonic-gate 	2048,
98*7c478bd9Sstevel@tonic-gate 	128
99*7c478bd9Sstevel@tonic-gate };
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate static struct qinit consmsurinit = {
102*7c478bd9Sstevel@tonic-gate 	putq,
103*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
104*7c478bd9Sstevel@tonic-gate 	consmsopen,
105*7c478bd9Sstevel@tonic-gate 	consmsclose,
106*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
107*7c478bd9Sstevel@tonic-gate 	&consmsm_info,
108*7c478bd9Sstevel@tonic-gate 	NULL
109*7c478bd9Sstevel@tonic-gate };
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate static struct qinit consmsuwinit = {
112*7c478bd9Sstevel@tonic-gate 	(int (*)())consmsuwput,
113*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
114*7c478bd9Sstevel@tonic-gate 	consmsopen,
115*7c478bd9Sstevel@tonic-gate 	consmsclose,
116*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
117*7c478bd9Sstevel@tonic-gate 	&consmsm_info,
118*7c478bd9Sstevel@tonic-gate 	NULL
119*7c478bd9Sstevel@tonic-gate };
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate static struct qinit consmslrinit = {
122*7c478bd9Sstevel@tonic-gate 	(int (*)())consmslrput,
123*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
124*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
125*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
126*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
127*7c478bd9Sstevel@tonic-gate 	&consmsm_info,
128*7c478bd9Sstevel@tonic-gate 	NULL
129*7c478bd9Sstevel@tonic-gate };
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate static struct qinit consmslwinit = {
132*7c478bd9Sstevel@tonic-gate 	putq,
133*7c478bd9Sstevel@tonic-gate 	(int (*)())consmslwserv,
134*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
135*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
136*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
137*7c478bd9Sstevel@tonic-gate 	&consmsm_info,
138*7c478bd9Sstevel@tonic-gate 	NULL
139*7c478bd9Sstevel@tonic-gate };
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate static struct streamtab consms_str_info = {
142*7c478bd9Sstevel@tonic-gate 	&consmsurinit,
143*7c478bd9Sstevel@tonic-gate 	&consmsuwinit,
144*7c478bd9Sstevel@tonic-gate 	&consmslrinit,
145*7c478bd9Sstevel@tonic-gate 	&consmslwinit,
146*7c478bd9Sstevel@tonic-gate };
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate static void consmsioctl(queue_t *q, mblk_t *mp);
149*7c478bd9Sstevel@tonic-gate static int consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
150*7c478bd9Sstevel@tonic-gate 		void **result);
151*7c478bd9Sstevel@tonic-gate static int consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
152*7c478bd9Sstevel@tonic-gate static int consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
153*7c478bd9Sstevel@tonic-gate static int consms_kstat_update(kstat_t *, int);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate /*
156*7c478bd9Sstevel@tonic-gate  * Module global data are protected by the per-module inner perimeter.
157*7c478bd9Sstevel@tonic-gate  */
158*7c478bd9Sstevel@tonic-gate static queue_t		*upperqueue;	/* regular mouse queue above us */
159*7c478bd9Sstevel@tonic-gate static dev_info_t	*consms_dip;	/* private copy of devinfo pointer */
160*7c478bd9Sstevel@tonic-gate static long	consms_idle_stamp;	/* seconds tstamp of latest mouse op */
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate static consms_msg_t	*consms_mux_msg; /* ioctl messages being processed */
163*7c478bd9Sstevel@tonic-gate static	kmutex_t	consms_msg_lock; /* protect ioctl messages list */
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate static consms_state_t	consms_state;	/* the global virtual mouse state */
166*7c478bd9Sstevel@tonic-gate static	kmutex_t	consmslock;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate  * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements.  In
171*7c478bd9Sstevel@tonic-gate  * this case we use this type for a single element because the ioctl code
172*7c478bd9Sstevel@tonic-gate  * for it knows how to handle mixed kernel/user data models.  Also, it
173*7c478bd9Sstevel@tonic-gate  * will be easier to add new statistics later.
174*7c478bd9Sstevel@tonic-gate  */
175*7c478bd9Sstevel@tonic-gate static struct {
176*7c478bd9Sstevel@tonic-gate 	kstat_named_t idle_sec;		/* seconds since last user op */
177*7c478bd9Sstevel@tonic-gate } consms_kstat = {
178*7c478bd9Sstevel@tonic-gate 	{ "idle_sec", KSTAT_DATA_LONG, }
179*7c478bd9Sstevel@tonic-gate };
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate static 	struct cb_ops cb_consms_ops = {
183*7c478bd9Sstevel@tonic-gate 	nulldev,		/* cb_open */
184*7c478bd9Sstevel@tonic-gate 	nulldev,		/* cb_close */
185*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_strategy */
186*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_print */
187*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_dump */
188*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_read */
189*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_write */
190*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_ioctl */
191*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_devmap */
192*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_mmap */
193*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_segmap */
194*7c478bd9Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
195*7c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
196*7c478bd9Sstevel@tonic-gate 	&consms_str_info,	/* cb_stream */
197*7c478bd9Sstevel@tonic-gate 	D_MP | D_MTPERMOD	/* cb_flag */
198*7c478bd9Sstevel@tonic-gate };
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate static struct dev_ops consms_ops = {
201*7c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
202*7c478bd9Sstevel@tonic-gate 	0,			/* devo_refcnt */
203*7c478bd9Sstevel@tonic-gate 	consms_info,		/* devo_getinfo */
204*7c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_identify */
205*7c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_probe */
206*7c478bd9Sstevel@tonic-gate 	consms_attach,		/* devo_attach */
207*7c478bd9Sstevel@tonic-gate 	consms_detach,		/* devo_detach */
208*7c478bd9Sstevel@tonic-gate 	nodev,			/* devo_reset */
209*7c478bd9Sstevel@tonic-gate 	&(cb_consms_ops),	/* devo_cb_ops */
210*7c478bd9Sstevel@tonic-gate 	(struct bus_ops *)NULL,	/* devo_bus_ops */
211*7c478bd9Sstevel@tonic-gate 	NULL			/* devo_power */
212*7c478bd9Sstevel@tonic-gate };
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate /*
216*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
217*7c478bd9Sstevel@tonic-gate  */
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
220*7c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
221*7c478bd9Sstevel@tonic-gate 	"Mouse Driver for Sun 'consms' %I%",
222*7c478bd9Sstevel@tonic-gate 	&consms_ops,	/* driver ops */
223*7c478bd9Sstevel@tonic-gate };
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
226*7c478bd9Sstevel@tonic-gate 	MODREV_1,
227*7c478bd9Sstevel@tonic-gate 	(void *)&modldrv,
228*7c478bd9Sstevel@tonic-gate 	NULL
229*7c478bd9Sstevel@tonic-gate };
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate int
232*7c478bd9Sstevel@tonic-gate _init(void)
233*7c478bd9Sstevel@tonic-gate {
234*7c478bd9Sstevel@tonic-gate 	int	error;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	mutex_init(&consmslock, NULL, MUTEX_DRIVER, NULL);
237*7c478bd9Sstevel@tonic-gate 	mutex_init(&consms_msg_lock, NULL, MUTEX_DRIVER, NULL);
238*7c478bd9Sstevel@tonic-gate 	error = mod_install(&modlinkage);
239*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
240*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&consmslock);
241*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&consms_msg_lock);
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 	return (error);
244*7c478bd9Sstevel@tonic-gate }
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate int
247*7c478bd9Sstevel@tonic-gate _fini(void)
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	int	error;
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	error = mod_remove(&modlinkage);
252*7c478bd9Sstevel@tonic-gate 	if (error != 0)
253*7c478bd9Sstevel@tonic-gate 		return (error);
254*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&consmslock);
255*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&consms_msg_lock);
256*7c478bd9Sstevel@tonic-gate 	return (0);
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate int
260*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
263*7c478bd9Sstevel@tonic-gate }
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate static int
266*7c478bd9Sstevel@tonic-gate consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
267*7c478bd9Sstevel@tonic-gate {
268*7c478bd9Sstevel@tonic-gate 	kstat_t	*ksp;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
271*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
272*7c478bd9Sstevel@tonic-gate 		break;
273*7c478bd9Sstevel@tonic-gate 	default:
274*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "mouse", S_IFCHR,
278*7c478bd9Sstevel@tonic-gate 		0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
279*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
280*7c478bd9Sstevel@tonic-gate 		return (-1);
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 	consms_dip = devi;
283*7c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1);
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	ksp = kstat_create("consms", 0, "activity", "misc", KSTAT_TYPE_NAMED,
286*7c478bd9Sstevel@tonic-gate 	    sizeof (consms_kstat) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
287*7c478bd9Sstevel@tonic-gate 	if (ksp) {
288*7c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *)&consms_kstat;
289*7c478bd9Sstevel@tonic-gate 		ksp->ks_update = consms_kstat_update;
290*7c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
291*7c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();	/* initial value */
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	consms_state.consms_lqs = NULL;
295*7c478bd9Sstevel@tonic-gate 	consms_state.consms_num_lqs = 0;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	/* default consms state values */
298*7c478bd9Sstevel@tonic-gate 	consms_state.consms_vuid_format = VUID_FIRM_EVENT;
299*7c478bd9Sstevel@tonic-gate 	consms_state.consms_num_buttons = 0;
300*7c478bd9Sstevel@tonic-gate 	consms_state.consms_num_wheels = 0;
301*7c478bd9Sstevel@tonic-gate 	consms_state.consms_wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
302*7c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_parms.jitter_thresh =
303*7c478bd9Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_JITTER;
304*7c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_parms.speed_limit =
305*7c478bd9Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_SPEED_LIMIT;
306*7c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_parms.speed_law =
307*7c478bd9Sstevel@tonic-gate 	    CONSMS_PARMS_DEFAULT_SPEED_LAW;
308*7c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_sr.height = CONSMS_SR_DEFAULT_HEIGHT;
309*7c478bd9Sstevel@tonic-gate 	consms_state.consms_ms_sr.width = CONSMS_SR_DEFAULT_WIDTH;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
315*7c478bd9Sstevel@tonic-gate static int
316*7c478bd9Sstevel@tonic-gate consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
317*7c478bd9Sstevel@tonic-gate {
318*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
319*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
320*7c478bd9Sstevel@tonic-gate 	default:
321*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
322*7c478bd9Sstevel@tonic-gate 	}
323*7c478bd9Sstevel@tonic-gate }
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
326*7c478bd9Sstevel@tonic-gate static int
327*7c478bd9Sstevel@tonic-gate consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
328*7c478bd9Sstevel@tonic-gate 	void **result)
329*7c478bd9Sstevel@tonic-gate {
330*7c478bd9Sstevel@tonic-gate 	register int error;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
333*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
334*7c478bd9Sstevel@tonic-gate 		if (consms_dip == NULL) {
335*7c478bd9Sstevel@tonic-gate 			error = DDI_FAILURE;
336*7c478bd9Sstevel@tonic-gate 		} else {
337*7c478bd9Sstevel@tonic-gate 			*result = (void *) consms_dip;
338*7c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
339*7c478bd9Sstevel@tonic-gate 		}
340*7c478bd9Sstevel@tonic-gate 		break;
341*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
342*7c478bd9Sstevel@tonic-gate 		*result = (void *)0;
343*7c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
344*7c478bd9Sstevel@tonic-gate 		break;
345*7c478bd9Sstevel@tonic-gate 	default:
346*7c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
347*7c478bd9Sstevel@tonic-gate 	}
348*7c478bd9Sstevel@tonic-gate 	return (error);
349*7c478bd9Sstevel@tonic-gate }
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
353*7c478bd9Sstevel@tonic-gate static int
354*7c478bd9Sstevel@tonic-gate consmsopen(q, devp, flag, sflag, crp)
355*7c478bd9Sstevel@tonic-gate 	queue_t *q;
356*7c478bd9Sstevel@tonic-gate 	dev_t	*devp;
357*7c478bd9Sstevel@tonic-gate 	int	flag, sflag;
358*7c478bd9Sstevel@tonic-gate 	cred_t	*crp;
359*7c478bd9Sstevel@tonic-gate {
360*7c478bd9Sstevel@tonic-gate 	upperqueue = q;
361*7c478bd9Sstevel@tonic-gate 	qprocson(q);
362*7c478bd9Sstevel@tonic-gate 	return (0);
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
366*7c478bd9Sstevel@tonic-gate static int
367*7c478bd9Sstevel@tonic-gate consmsclose(q, flag, crp)
368*7c478bd9Sstevel@tonic-gate 	queue_t *q;
369*7c478bd9Sstevel@tonic-gate 	int	flag;
370*7c478bd9Sstevel@tonic-gate 	cred_t	*crp;
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	qprocsoff(q);
373*7c478bd9Sstevel@tonic-gate 	upperqueue = NULL;
374*7c478bd9Sstevel@tonic-gate 	return (0);
375*7c478bd9Sstevel@tonic-gate }
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate /*
378*7c478bd9Sstevel@tonic-gate  * Put procedure for upper write queue.
379*7c478bd9Sstevel@tonic-gate  */
380*7c478bd9Sstevel@tonic-gate static void
381*7c478bd9Sstevel@tonic-gate consmsuwput(q, mp)
382*7c478bd9Sstevel@tonic-gate 	register queue_t *q;
383*7c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
384*7c478bd9Sstevel@tonic-gate {
385*7c478bd9Sstevel@tonic-gate 	struct iocblk		*iocbp = (struct iocblk *)mp->b_rptr;
386*7c478bd9Sstevel@tonic-gate 	consms_msg_t		*msg;
387*7c478bd9Sstevel@tonic-gate 	int			error = 0;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
392*7c478bd9Sstevel@tonic-gate 		consmsioctl(q, mp);
393*7c478bd9Sstevel@tonic-gate 		break;
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
396*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
397*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
398*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
399*7c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
400*7c478bd9Sstevel@tonic-gate 		if (consms_state.consms_num_lqs > 0) {
401*7c478bd9Sstevel@tonic-gate 			consms_mux_disp_data(mp);
402*7c478bd9Sstevel@tonic-gate 		} else {
403*7c478bd9Sstevel@tonic-gate 			/*
404*7c478bd9Sstevel@tonic-gate 			 * No lower queue; just reflect this back upstream.
405*7c478bd9Sstevel@tonic-gate 			 */
406*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
407*7c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHR)
408*7c478bd9Sstevel@tonic-gate 				qreply(q, mp);
409*7c478bd9Sstevel@tonic-gate 			else
410*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
411*7c478bd9Sstevel@tonic-gate 		}
412*7c478bd9Sstevel@tonic-gate 		break;
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	case M_DATA:
415*7c478bd9Sstevel@tonic-gate 		if (consms_state.consms_num_lqs > 0) {
416*7c478bd9Sstevel@tonic-gate 			consms_mux_disp_data(mp);
417*7c478bd9Sstevel@tonic-gate 		} else {
418*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
419*7c478bd9Sstevel@tonic-gate 		}
420*7c478bd9Sstevel@tonic-gate 		break;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	case M_IOCDATA:
423*7c478bd9Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
424*7c478bd9Sstevel@tonic-gate 			consms_mux_iocdata(msg, mp);
425*7c478bd9Sstevel@tonic-gate 		} else {
426*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
427*7c478bd9Sstevel@tonic-gate 		}
428*7c478bd9Sstevel@tonic-gate 		break;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	default:
431*7c478bd9Sstevel@tonic-gate 		error = EINVAL;
432*7c478bd9Sstevel@tonic-gate 		break;
433*7c478bd9Sstevel@tonic-gate 	}
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	if (error) {
436*7c478bd9Sstevel@tonic-gate 		/*
437*7c478bd9Sstevel@tonic-gate 		 * Pass an error message up.
438*7c478bd9Sstevel@tonic-gate 		 */
439*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_ERROR;
440*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont) {
441*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
442*7c478bd9Sstevel@tonic-gate 			mp->b_cont = NULL;
443*7c478bd9Sstevel@tonic-gate 		}
444*7c478bd9Sstevel@tonic-gate 		mp->b_rptr = mp->b_datap->db_base;
445*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + sizeof (char);
446*7c478bd9Sstevel@tonic-gate 		*mp->b_rptr = (char)error;
447*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
448*7c478bd9Sstevel@tonic-gate 	}
449*7c478bd9Sstevel@tonic-gate }
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate static void
452*7c478bd9Sstevel@tonic-gate consmsioctl(q, mp)
453*7c478bd9Sstevel@tonic-gate 	register queue_t *q;
454*7c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
455*7c478bd9Sstevel@tonic-gate {
456*7c478bd9Sstevel@tonic-gate 	register struct iocblk *iocp;
457*7c478bd9Sstevel@tonic-gate 	int		error;
458*7c478bd9Sstevel@tonic-gate 	mblk_t		*datap;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	case I_LINK:
465*7c478bd9Sstevel@tonic-gate 	case I_PLINK:
466*7c478bd9Sstevel@tonic-gate 		mutex_enter(&consmslock);
467*7c478bd9Sstevel@tonic-gate 		consms_plink(q, mp);
468*7c478bd9Sstevel@tonic-gate 		mutex_exit(&consmslock);
469*7c478bd9Sstevel@tonic-gate 		return;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	case I_UNLINK:
472*7c478bd9Sstevel@tonic-gate 	case I_PUNLINK:
473*7c478bd9Sstevel@tonic-gate 		mutex_enter(&consmslock);
474*7c478bd9Sstevel@tonic-gate 		if ((error = consms_punlink(q, mp)) != 0) {
475*7c478bd9Sstevel@tonic-gate 			mutex_exit(&consmslock);
476*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
477*7c478bd9Sstevel@tonic-gate 			return;
478*7c478bd9Sstevel@tonic-gate 		}
479*7c478bd9Sstevel@tonic-gate 		mutex_exit(&consmslock);
480*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = 0;
481*7c478bd9Sstevel@tonic-gate 		break;
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	case MSIOBUTTONS:	/* query the number of buttons */
484*7c478bd9Sstevel@tonic-gate 		if ((consms_state.consms_num_lqs <= 0) ||
485*7c478bd9Sstevel@tonic-gate 		    ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)) {
486*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ENOMEM);
487*7c478bd9Sstevel@tonic-gate 			return;
488*7c478bd9Sstevel@tonic-gate 		}
489*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = consms_state.consms_num_buttons;
490*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
491*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont) {
492*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
493*7c478bd9Sstevel@tonic-gate 		}
494*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
495*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
496*7c478bd9Sstevel@tonic-gate 		break;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	default:
499*7c478bd9Sstevel@tonic-gate 		/*
500*7c478bd9Sstevel@tonic-gate 		 * Pass this through, if there's something to pass it
501*7c478bd9Sstevel@tonic-gate 		 * through to; otherwise, reject it.
502*7c478bd9Sstevel@tonic-gate 		 */
503*7c478bd9Sstevel@tonic-gate 		if (consms_state.consms_num_lqs <= 0) {
504*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
505*7c478bd9Sstevel@tonic-gate 			return;
506*7c478bd9Sstevel@tonic-gate 		}
507*7c478bd9Sstevel@tonic-gate 		if ((error = consms_mux_disp_ioctl(q, mp)) != 0)
508*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 		return;
511*7c478bd9Sstevel@tonic-gate 	}
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	/*
514*7c478bd9Sstevel@tonic-gate 	 * Common exit path for calls that return a positive
515*7c478bd9Sstevel@tonic-gate 	 * acknowledgment with a return value of 0.
516*7c478bd9Sstevel@tonic-gate 	 */
517*7c478bd9Sstevel@tonic-gate 	miocack(q, mp, iocp->ioc_count, 0);
518*7c478bd9Sstevel@tonic-gate }
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate /*
521*7c478bd9Sstevel@tonic-gate  * Service procedure for lower write queue.
522*7c478bd9Sstevel@tonic-gate  * Puts things on the queue below us, if it lets us.
523*7c478bd9Sstevel@tonic-gate  */
524*7c478bd9Sstevel@tonic-gate static void
525*7c478bd9Sstevel@tonic-gate consmslwserv(q)
526*7c478bd9Sstevel@tonic-gate 	register queue_t *q;
527*7c478bd9Sstevel@tonic-gate {
528*7c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	while (canput(q->q_next) && (mp = getq(q)) != NULL)
531*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
532*7c478bd9Sstevel@tonic-gate }
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate /*
535*7c478bd9Sstevel@tonic-gate  * Put procedure for lower read queue.
536*7c478bd9Sstevel@tonic-gate  */
537*7c478bd9Sstevel@tonic-gate static void
538*7c478bd9Sstevel@tonic-gate consmslrput(q, mp)
539*7c478bd9Sstevel@tonic-gate 	register queue_t *q;
540*7c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
541*7c478bd9Sstevel@tonic-gate {
542*7c478bd9Sstevel@tonic-gate 	struct iocblk		*iocbp = (struct iocblk *)mp->b_rptr;
543*7c478bd9Sstevel@tonic-gate 	struct copyreq		*copyreq = (struct copyreq *)mp->b_rptr;
544*7c478bd9Sstevel@tonic-gate 	consms_msg_t		*msg;
545*7c478bd9Sstevel@tonic-gate 	consms_lq_t		*lq = (consms_lq_t *)q->q_ptr;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	ASSERT(lq != NULL);
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
550*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
551*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
552*7c478bd9Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
553*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
554*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
555*7c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL)
556*7c478bd9Sstevel@tonic-gate 			putnext(upperqueue, mp);	/* pass it through */
557*7c478bd9Sstevel@tonic-gate 		else {
558*7c478bd9Sstevel@tonic-gate 			/*
559*7c478bd9Sstevel@tonic-gate 			 * No upper queue; just reflect this back downstream.
560*7c478bd9Sstevel@tonic-gate 			 */
561*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHR;
562*7c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW)
563*7c478bd9Sstevel@tonic-gate 				qreply(q, mp);
564*7c478bd9Sstevel@tonic-gate 			else
565*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
566*7c478bd9Sstevel@tonic-gate 		}
567*7c478bd9Sstevel@tonic-gate 		break;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	case M_DATA:
570*7c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL)
571*7c478bd9Sstevel@tonic-gate 			putnext(upperqueue, mp);
572*7c478bd9Sstevel@tonic-gate 		else
573*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
574*7c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
575*7c478bd9Sstevel@tonic-gate 		break;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	case M_IOCACK:
578*7c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
579*7c478bd9Sstevel@tonic-gate 		/*
580*7c478bd9Sstevel@tonic-gate 		 * First, check to see if this device
581*7c478bd9Sstevel@tonic-gate 		 * is still being initialized.
582*7c478bd9Sstevel@tonic-gate 		 */
583*7c478bd9Sstevel@tonic-gate 		if (lq->lq_ioc_reply_func != NULL) {
584*7c478bd9Sstevel@tonic-gate 			mutex_enter(&consmslock);
585*7c478bd9Sstevel@tonic-gate 			lq->lq_ioc_reply_func(lq, mp);
586*7c478bd9Sstevel@tonic-gate 			mutex_exit(&consmslock);
587*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
588*7c478bd9Sstevel@tonic-gate 			break;
589*7c478bd9Sstevel@tonic-gate 		}
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 		/*
592*7c478bd9Sstevel@tonic-gate 		 * This is normal ioctl ack for upper layer.
593*7c478bd9Sstevel@tonic-gate 		 */
594*7c478bd9Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
595*7c478bd9Sstevel@tonic-gate 			consms_mux_ack(msg, mp);
596*7c478bd9Sstevel@tonic-gate 		} else {
597*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
598*7c478bd9Sstevel@tonic-gate 		}
599*7c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
600*7c478bd9Sstevel@tonic-gate 		break;
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	case M_COPYIN:
603*7c478bd9Sstevel@tonic-gate 	case M_COPYOUT:
604*7c478bd9Sstevel@tonic-gate 		if ((msg = consms_mux_find_msg(copyreq->cq_id)) != NULL) {
605*7c478bd9Sstevel@tonic-gate 			consms_mux_copyreq(q, msg, mp);
606*7c478bd9Sstevel@tonic-gate 		} else
607*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
608*7c478bd9Sstevel@tonic-gate 		consms_idle_stamp = gethrestime_sec();
609*7c478bd9Sstevel@tonic-gate 		break;
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	case M_ERROR:
612*7c478bd9Sstevel@tonic-gate 	case M_HANGUP:
613*7c478bd9Sstevel@tonic-gate 	default:
614*7c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* anything useful here? */
615*7c478bd9Sstevel@tonic-gate 		break;
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate }
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
620*7c478bd9Sstevel@tonic-gate static int
621*7c478bd9Sstevel@tonic-gate consms_kstat_update(kstat_t *ksp, int rw)
622*7c478bd9Sstevel@tonic-gate {
623*7c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
624*7c478bd9Sstevel@tonic-gate 		return (EACCES);
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	consms_kstat.idle_sec.value.l = gethrestime_sec() - consms_idle_stamp;
627*7c478bd9Sstevel@tonic-gate 	return (0);
628*7c478bd9Sstevel@tonic-gate }
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
631*7c478bd9Sstevel@tonic-gate static int
632*7c478bd9Sstevel@tonic-gate consms_punlink(queue_t *q, mblk_t *mp)
633*7c478bd9Sstevel@tonic-gate {
634*7c478bd9Sstevel@tonic-gate 	struct linkblk	*linkp;
635*7c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
636*7c478bd9Sstevel@tonic-gate 	consms_lq_t	*prev_lq;
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	linkp = (struct linkblk *)mp->b_cont->b_rptr;
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	prev_lq = NULL;
643*7c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
644*7c478bd9Sstevel@tonic-gate 		if (lq->lq_queue == linkp->l_qbot) {
645*7c478bd9Sstevel@tonic-gate 			if (prev_lq)
646*7c478bd9Sstevel@tonic-gate 				prev_lq->lq_next = lq->lq_next;
647*7c478bd9Sstevel@tonic-gate 			else
648*7c478bd9Sstevel@tonic-gate 				consms_state.consms_lqs = lq->lq_next;
649*7c478bd9Sstevel@tonic-gate 			kmem_free(lq, sizeof (*lq));
650*7c478bd9Sstevel@tonic-gate 			consms_state.consms_num_lqs--;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 			/*
653*7c478bd9Sstevel@tonic-gate 			 * Check to see if mouse capabilities
654*7c478bd9Sstevel@tonic-gate 			 * have changed.
655*7c478bd9Sstevel@tonic-gate 			 */
656*7c478bd9Sstevel@tonic-gate 			consms_check_caps();
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 			return (0);
659*7c478bd9Sstevel@tonic-gate 		}
660*7c478bd9Sstevel@tonic-gate 		prev_lq = lq;
661*7c478bd9Sstevel@tonic-gate 	}
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	return (EINVAL);
664*7c478bd9Sstevel@tonic-gate }
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate /*
667*7c478bd9Sstevel@tonic-gate  * Link a specific mouse into our mouse list.
668*7c478bd9Sstevel@tonic-gate  */
669*7c478bd9Sstevel@tonic-gate static void
670*7c478bd9Sstevel@tonic-gate consms_plink(queue_t *q, mblk_t *mp)
671*7c478bd9Sstevel@tonic-gate {
672*7c478bd9Sstevel@tonic-gate 	struct	linkblk	*linkp;
673*7c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
674*7c478bd9Sstevel@tonic-gate 	queue_t		*lowq;
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	linkp = (struct linkblk *)mp->b_cont->b_rptr;
679*7c478bd9Sstevel@tonic-gate 	lowq = linkp->l_qbot;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	lq = kmem_zalloc(sizeof (*lq), KM_SLEEP);
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	lowq->q_ptr = (void *)lq;
684*7c478bd9Sstevel@tonic-gate 	OTHERQ(lowq)->q_ptr = (void *)lq;
685*7c478bd9Sstevel@tonic-gate 	lq->lq_queue = lowq;
686*7c478bd9Sstevel@tonic-gate 	lq->lq_pending_plink = mp;
687*7c478bd9Sstevel@tonic-gate 	lq->lq_pending_queue = q;
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 	/*
690*7c478bd9Sstevel@tonic-gate 	 * Set the number of buttons to 3 by default
691*7c478bd9Sstevel@tonic-gate 	 * in case the following MSIOBUTTONS ioctl fails.
692*7c478bd9Sstevel@tonic-gate 	 */
693*7c478bd9Sstevel@tonic-gate 	lq->lq_num_buttons = 3;
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	/*
696*7c478bd9Sstevel@tonic-gate 	 * Begin to initialize this mouse.
697*7c478bd9Sstevel@tonic-gate 	 */
698*7c478bd9Sstevel@tonic-gate 	lq->lq_state = LQS_START;
699*7c478bd9Sstevel@tonic-gate 	consms_lqs_ack_complete(lq, NULL);
700*7c478bd9Sstevel@tonic-gate }
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate /*
703*7c478bd9Sstevel@tonic-gate  * Initialize the newly hotplugged-in mouse,
704*7c478bd9Sstevel@tonic-gate  * e.g. get the number of buttons, set event
705*7c478bd9Sstevel@tonic-gate  * format. Then we add it into our list.
706*7c478bd9Sstevel@tonic-gate  */
707*7c478bd9Sstevel@tonic-gate static void
708*7c478bd9Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *lq, mblk_t *mp)
709*7c478bd9Sstevel@tonic-gate {
710*7c478bd9Sstevel@tonic-gate 	mblk_t			*req = NULL;
711*7c478bd9Sstevel@tonic-gate 	boolean_t		skipped = B_FALSE;
712*7c478bd9Sstevel@tonic-gate 	wheel_state		*ws;
713*7c478bd9Sstevel@tonic-gate 	Ms_screen_resolution	*sr;
714*7c478bd9Sstevel@tonic-gate 	Ms_parms		*params;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	/*
719*7c478bd9Sstevel@tonic-gate 	 * We try each ioctl even if the previous one fails
720*7c478bd9Sstevel@tonic-gate 	 * until we reach LQS_DONE, and then add this lq
721*7c478bd9Sstevel@tonic-gate 	 * into our lq list.
722*7c478bd9Sstevel@tonic-gate 	 *
723*7c478bd9Sstevel@tonic-gate 	 * If the message allocation fails, we skip this ioctl,
724*7c478bd9Sstevel@tonic-gate 	 * set skipped flag to B_TRUE in order to skip the ioctl
725*7c478bd9Sstevel@tonic-gate 	 * result, then we try next ioctl, go to next state.
726*7c478bd9Sstevel@tonic-gate 	 */
727*7c478bd9Sstevel@tonic-gate 	while ((lq->lq_state < LQS_DONE) && (req == NULL)) {
728*7c478bd9Sstevel@tonic-gate 		switch (lq->lq_state) {
729*7c478bd9Sstevel@tonic-gate 		case LQS_START:
730*7c478bd9Sstevel@tonic-gate 			/*
731*7c478bd9Sstevel@tonic-gate 			 * First, issue MSIOBUTTONS ioctl
732*7c478bd9Sstevel@tonic-gate 			 * to get the number of buttons.
733*7c478bd9Sstevel@tonic-gate 			 */
734*7c478bd9Sstevel@tonic-gate 			req = mkiocb(MSIOBUTTONS);
735*7c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
736*7c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
737*7c478bd9Sstevel@tonic-gate 				freemsg(req);
738*7c478bd9Sstevel@tonic-gate 				req = NULL;
739*7c478bd9Sstevel@tonic-gate 			}
740*7c478bd9Sstevel@tonic-gate 			if (req == NULL)
741*7c478bd9Sstevel@tonic-gate 				skipped = B_TRUE;
742*7c478bd9Sstevel@tonic-gate 			lq->lq_state++;
743*7c478bd9Sstevel@tonic-gate 			break;
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 		case LQS_BUTTON_COUNT_PENDING:
746*7c478bd9Sstevel@tonic-gate 			if (!skipped && mp && mp->b_cont &&
747*7c478bd9Sstevel@tonic-gate 			    (mp->b_datap->db_type == M_IOCACK))
748*7c478bd9Sstevel@tonic-gate 				lq->lq_num_buttons =
749*7c478bd9Sstevel@tonic-gate 				    *(int *)mp->b_cont->b_rptr;
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 			/*
752*7c478bd9Sstevel@tonic-gate 			 * Second, issue VUIDGWHEELCOUNT ioctl
753*7c478bd9Sstevel@tonic-gate 			 * to get the count of wheels.
754*7c478bd9Sstevel@tonic-gate 			 */
755*7c478bd9Sstevel@tonic-gate 			req = mkiocb(VUIDGWHEELCOUNT);
756*7c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
757*7c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
758*7c478bd9Sstevel@tonic-gate 				freemsg(req);
759*7c478bd9Sstevel@tonic-gate 				req = NULL;
760*7c478bd9Sstevel@tonic-gate 			}
761*7c478bd9Sstevel@tonic-gate 			if (req == NULL)
762*7c478bd9Sstevel@tonic-gate 				skipped = B_TRUE;
763*7c478bd9Sstevel@tonic-gate 			lq->lq_state++;
764*7c478bd9Sstevel@tonic-gate 			break;
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 		case LQS_WHEEL_COUNT_PENDING:
767*7c478bd9Sstevel@tonic-gate 			if (!skipped && mp && mp->b_cont &&
768*7c478bd9Sstevel@tonic-gate 			    (mp->b_datap->db_type == M_IOCACK))
769*7c478bd9Sstevel@tonic-gate 				lq->lq_num_wheels =
770*7c478bd9Sstevel@tonic-gate 				    *(int *)mp->b_cont->b_rptr;
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 			/*
773*7c478bd9Sstevel@tonic-gate 			 * Third, issue VUIDSFORMAT ioctl
774*7c478bd9Sstevel@tonic-gate 			 * to set the event format.
775*7c478bd9Sstevel@tonic-gate 			 */
776*7c478bd9Sstevel@tonic-gate 			req = mkiocb(VUIDSFORMAT);
777*7c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (int),
778*7c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
779*7c478bd9Sstevel@tonic-gate 				freemsg(req);
780*7c478bd9Sstevel@tonic-gate 				req = NULL;
781*7c478bd9Sstevel@tonic-gate 			}
782*7c478bd9Sstevel@tonic-gate 			if (req) {
783*7c478bd9Sstevel@tonic-gate 				*(int *)req->b_cont->b_wptr =
784*7c478bd9Sstevel@tonic-gate 				    consms_state.consms_vuid_format;
785*7c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (int);
786*7c478bd9Sstevel@tonic-gate 			}
787*7c478bd9Sstevel@tonic-gate 			lq->lq_state++;
788*7c478bd9Sstevel@tonic-gate 			break;
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 		case LQS_SET_VUID_FORMAT_PENDING:
791*7c478bd9Sstevel@tonic-gate 			/*
792*7c478bd9Sstevel@tonic-gate 			 * Fourth, issue VUIDSWHEELSTATE ioctl
793*7c478bd9Sstevel@tonic-gate 			 * to set the wheel state (enable or disable).
794*7c478bd9Sstevel@tonic-gate 			 */
795*7c478bd9Sstevel@tonic-gate 			req = mkiocb(VUIDSWHEELSTATE);
796*7c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (wheel_state),
797*7c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
798*7c478bd9Sstevel@tonic-gate 				freemsg(req);
799*7c478bd9Sstevel@tonic-gate 				req = NULL;
800*7c478bd9Sstevel@tonic-gate 			}
801*7c478bd9Sstevel@tonic-gate 			if (req) {
802*7c478bd9Sstevel@tonic-gate 				ws = (wheel_state *)req->b_cont->b_wptr;
803*7c478bd9Sstevel@tonic-gate 				ws->vers = VUID_WHEEL_STATE_VERS;
804*7c478bd9Sstevel@tonic-gate 				ws->id = 0;	/* the first wheel */
805*7c478bd9Sstevel@tonic-gate 				ws->stateflags =
806*7c478bd9Sstevel@tonic-gate 				    consms_state.consms_wheel_state_bf & 1;
807*7c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (wheel_state);
808*7c478bd9Sstevel@tonic-gate 			}
809*7c478bd9Sstevel@tonic-gate 			lq->lq_state++;
810*7c478bd9Sstevel@tonic-gate 			break;
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 		case LQS_SET_WHEEL_STATE_PENDING:
813*7c478bd9Sstevel@tonic-gate 			/*
814*7c478bd9Sstevel@tonic-gate 			 * Fifth, issue MSIOSRESOLUTION ioctl
815*7c478bd9Sstevel@tonic-gate 			 * to set the screen resolution for absolute mouse.
816*7c478bd9Sstevel@tonic-gate 			 */
817*7c478bd9Sstevel@tonic-gate 			req = mkiocb(MSIOSRESOLUTION);
818*7c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont =
819*7c478bd9Sstevel@tonic-gate 			    allocb(sizeof (Ms_screen_resolution),
820*7c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
821*7c478bd9Sstevel@tonic-gate 				freemsg(req);
822*7c478bd9Sstevel@tonic-gate 				req = NULL;
823*7c478bd9Sstevel@tonic-gate 			}
824*7c478bd9Sstevel@tonic-gate 			if (req) {
825*7c478bd9Sstevel@tonic-gate 				sr =
826*7c478bd9Sstevel@tonic-gate 				    (Ms_screen_resolution *)req->b_cont->b_wptr;
827*7c478bd9Sstevel@tonic-gate 				*sr = consms_state.consms_ms_sr;
828*7c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr +=
829*7c478bd9Sstevel@tonic-gate 				    sizeof (Ms_screen_resolution);
830*7c478bd9Sstevel@tonic-gate 			}
831*7c478bd9Sstevel@tonic-gate 			lq->lq_state++;
832*7c478bd9Sstevel@tonic-gate 			break;
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 		case LQS_SET_RESOLUTION_PENDING:
835*7c478bd9Sstevel@tonic-gate 			/*
836*7c478bd9Sstevel@tonic-gate 			 * Sixth, issue MSIOSETPARMS ioctl
837*7c478bd9Sstevel@tonic-gate 			 * to set the parameters for USB mouse.
838*7c478bd9Sstevel@tonic-gate 			 */
839*7c478bd9Sstevel@tonic-gate 			req = mkiocb(MSIOSETPARMS);
840*7c478bd9Sstevel@tonic-gate 			if (req && ((req->b_cont = allocb(sizeof (Ms_parms),
841*7c478bd9Sstevel@tonic-gate 			    BPRI_MED)) == NULL)) {
842*7c478bd9Sstevel@tonic-gate 				freemsg(req);
843*7c478bd9Sstevel@tonic-gate 				req = NULL;
844*7c478bd9Sstevel@tonic-gate 			}
845*7c478bd9Sstevel@tonic-gate 			if (req) {
846*7c478bd9Sstevel@tonic-gate 				params = (Ms_parms *)req->b_cont->b_wptr;
847*7c478bd9Sstevel@tonic-gate 				*params = consms_state.consms_ms_parms;
848*7c478bd9Sstevel@tonic-gate 				req->b_cont->b_wptr += sizeof (Ms_parms);
849*7c478bd9Sstevel@tonic-gate 			}
850*7c478bd9Sstevel@tonic-gate 			lq->lq_state++;
851*7c478bd9Sstevel@tonic-gate 			break;
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 		case LQS_SET_PARMS_PENDING:
854*7c478bd9Sstevel@tonic-gate 			/*
855*7c478bd9Sstevel@tonic-gate 			 * All jobs are done, lq->lq_state is turned into
856*7c478bd9Sstevel@tonic-gate 			 * LQS_DONE, and this lq is added into our list.
857*7c478bd9Sstevel@tonic-gate 			 */
858*7c478bd9Sstevel@tonic-gate 			lq->lq_state++;
859*7c478bd9Sstevel@tonic-gate 			consms_add_lq(lq);
860*7c478bd9Sstevel@tonic-gate 			break;
861*7c478bd9Sstevel@tonic-gate 		}
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	if (lq->lq_state < LQS_DONE) {
865*7c478bd9Sstevel@tonic-gate 		lq->lq_ioc_reply_func = consms_lqs_ack_complete;
866*7c478bd9Sstevel@tonic-gate 		(void) putq(lq->lq_queue, req);
867*7c478bd9Sstevel@tonic-gate 	}
868*7c478bd9Sstevel@tonic-gate }
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate /*
871*7c478bd9Sstevel@tonic-gate  * Add this specific lq into our list, finally reply
872*7c478bd9Sstevel@tonic-gate  * the previous pending I_PLINK ioctl. Also check to
873*7c478bd9Sstevel@tonic-gate  * see if mouse capabilities have changed, and send
874*7c478bd9Sstevel@tonic-gate  * a dynamical notification event to upper layer if
875*7c478bd9Sstevel@tonic-gate  * necessary.
876*7c478bd9Sstevel@tonic-gate  */
877*7c478bd9Sstevel@tonic-gate static void
878*7c478bd9Sstevel@tonic-gate consms_add_lq(consms_lq_t *lq)
879*7c478bd9Sstevel@tonic-gate {
880*7c478bd9Sstevel@tonic-gate 	struct	iocblk		*iocp;
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&consmslock));
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	lq->lq_ioc_reply_func = NULL;
885*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)lq->lq_pending_plink->b_rptr;
886*7c478bd9Sstevel@tonic-gate 	iocp->ioc_error = 0;
887*7c478bd9Sstevel@tonic-gate 	iocp->ioc_count = 0;
888*7c478bd9Sstevel@tonic-gate 	iocp->ioc_rval = 0;
889*7c478bd9Sstevel@tonic-gate 	lq->lq_pending_plink->b_datap->db_type = M_IOCACK;
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	/* Reply to the I_PLINK ioctl. */
892*7c478bd9Sstevel@tonic-gate 	qreply(lq->lq_pending_queue, lq->lq_pending_plink);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	lq->lq_pending_plink = NULL;
895*7c478bd9Sstevel@tonic-gate 	lq->lq_pending_queue = NULL;
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	/*
898*7c478bd9Sstevel@tonic-gate 	 * Add this lq into list.
899*7c478bd9Sstevel@tonic-gate 	 */
900*7c478bd9Sstevel@tonic-gate 	consms_state.consms_num_lqs++;
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	lq->lq_next = consms_state.consms_lqs;
903*7c478bd9Sstevel@tonic-gate 	consms_state.consms_lqs = lq;
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	/*
906*7c478bd9Sstevel@tonic-gate 	 * Check to see if mouse capabilities
907*7c478bd9Sstevel@tonic-gate 	 * have changed.
908*7c478bd9Sstevel@tonic-gate 	 */
909*7c478bd9Sstevel@tonic-gate 	consms_check_caps();
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate }
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate static void
915*7c478bd9Sstevel@tonic-gate consms_check_caps(void)
916*7c478bd9Sstevel@tonic-gate {
917*7c478bd9Sstevel@tonic-gate 	consms_lq_t *lq;
918*7c478bd9Sstevel@tonic-gate 	int	max_buttons = 0;
919*7c478bd9Sstevel@tonic-gate 	int	max_wheels = 0;
920*7c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	/*
923*7c478bd9Sstevel@tonic-gate 	 * Check to see if the number of buttons
924*7c478bd9Sstevel@tonic-gate 	 * and the number of wheels have changed.
925*7c478bd9Sstevel@tonic-gate 	 */
926*7c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
927*7c478bd9Sstevel@tonic-gate 		max_buttons = CONSMS_MAX(max_buttons, lq->lq_num_buttons);
928*7c478bd9Sstevel@tonic-gate 		max_wheels = CONSMS_MAX(max_wheels, lq->lq_num_wheels);
929*7c478bd9Sstevel@tonic-gate 	}
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 	if (max_buttons != consms_state.consms_num_buttons) {
932*7c478bd9Sstevel@tonic-gate 		/*
933*7c478bd9Sstevel@tonic-gate 		 * Since the number of buttons have changed,
934*7c478bd9Sstevel@tonic-gate 		 * send a MOUSE_CAP_CHANGE_NUM_BUT dynamical
935*7c478bd9Sstevel@tonic-gate 		 * notification event to upper layer.
936*7c478bd9Sstevel@tonic-gate 		 */
937*7c478bd9Sstevel@tonic-gate 		consms_state.consms_num_buttons = max_buttons;
938*7c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL) {
939*7c478bd9Sstevel@tonic-gate 			if ((mp = consms_new_firm_event(
940*7c478bd9Sstevel@tonic-gate 			    MOUSE_CAP_CHANGE_NUM_BUT,
941*7c478bd9Sstevel@tonic-gate 			    consms_state.consms_num_buttons)) != NULL) {
942*7c478bd9Sstevel@tonic-gate 				putnext(upperqueue, mp);
943*7c478bd9Sstevel@tonic-gate 			}
944*7c478bd9Sstevel@tonic-gate 		}
945*7c478bd9Sstevel@tonic-gate 	}
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	if (max_wheels != consms_state.consms_num_wheels) {
948*7c478bd9Sstevel@tonic-gate 		/*
949*7c478bd9Sstevel@tonic-gate 		 * Since the number of wheels have changed,
950*7c478bd9Sstevel@tonic-gate 		 * send a MOUSE_CAP_CHANGE_NUM_WHEEL dynamical
951*7c478bd9Sstevel@tonic-gate 		 * notification event to upper layer.
952*7c478bd9Sstevel@tonic-gate 		 */
953*7c478bd9Sstevel@tonic-gate 		consms_state.consms_num_wheels = max_wheels;
954*7c478bd9Sstevel@tonic-gate 		if (upperqueue != NULL) {
955*7c478bd9Sstevel@tonic-gate 			if ((mp = consms_new_firm_event(
956*7c478bd9Sstevel@tonic-gate 			    MOUSE_CAP_CHANGE_NUM_WHEEL,
957*7c478bd9Sstevel@tonic-gate 			    consms_state.consms_num_wheels)) != NULL) {
958*7c478bd9Sstevel@tonic-gate 				putnext(upperqueue, mp);
959*7c478bd9Sstevel@tonic-gate 			}
960*7c478bd9Sstevel@tonic-gate 		}
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate }
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate /*
965*7c478bd9Sstevel@tonic-gate  * Allocate a dynamical notification event.
966*7c478bd9Sstevel@tonic-gate  */
967*7c478bd9Sstevel@tonic-gate static mblk_t *
968*7c478bd9Sstevel@tonic-gate consms_new_firm_event(int id, int value)
969*7c478bd9Sstevel@tonic-gate {
970*7c478bd9Sstevel@tonic-gate 	Firm_event *fep;
971*7c478bd9Sstevel@tonic-gate 	mblk_t	*tmp;
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
974*7c478bd9Sstevel@tonic-gate 		fep = (Firm_event *)tmp->b_wptr;
975*7c478bd9Sstevel@tonic-gate 		fep->id = id;
976*7c478bd9Sstevel@tonic-gate 		fep->pair_type = FE_PAIR_NONE;
977*7c478bd9Sstevel@tonic-gate 		fep->pair = NULL;
978*7c478bd9Sstevel@tonic-gate 		fep->value = value;
979*7c478bd9Sstevel@tonic-gate 		tmp->b_wptr += sizeof (Firm_event);
980*7c478bd9Sstevel@tonic-gate 	}
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	return (tmp);
983*7c478bd9Sstevel@tonic-gate }
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate /*
986*7c478bd9Sstevel@tonic-gate  * Start of dispatching interfaces as a multiplexor
987*7c478bd9Sstevel@tonic-gate  */
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate /*
990*7c478bd9Sstevel@tonic-gate  * There is a global msg list (consms_mux_msg),
991*7c478bd9Sstevel@tonic-gate  * which is used to link all ioctl messages from
992*7c478bd9Sstevel@tonic-gate  * upper layer, which are currently being processed.
993*7c478bd9Sstevel@tonic-gate  *
994*7c478bd9Sstevel@tonic-gate  * consms_mux_link_msg links a msg into the list,
995*7c478bd9Sstevel@tonic-gate  * consms_mux_unlink_msg unlinks a msg from the list,
996*7c478bd9Sstevel@tonic-gate  * consms_mux_find_msg finds a msg from the list
997*7c478bd9Sstevel@tonic-gate  * according to its unique id.
998*7c478bd9Sstevel@tonic-gate  *
999*7c478bd9Sstevel@tonic-gate  * The id of each msg is taken from stream's mp,
1000*7c478bd9Sstevel@tonic-gate  * so the id is supposed to be unique.
1001*7c478bd9Sstevel@tonic-gate  */
1002*7c478bd9Sstevel@tonic-gate static void
1003*7c478bd9Sstevel@tonic-gate consms_mux_link_msg(consms_msg_t *msg)
1004*7c478bd9Sstevel@tonic-gate {
1005*7c478bd9Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
1006*7c478bd9Sstevel@tonic-gate 	msg->msg_next = consms_mux_msg;
1007*7c478bd9Sstevel@tonic-gate 	consms_mux_msg = msg;
1008*7c478bd9Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
1009*7c478bd9Sstevel@tonic-gate }
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate static consms_msg_t *
1012*7c478bd9Sstevel@tonic-gate consms_mux_unlink_msg(uint_t msg_id)
1013*7c478bd9Sstevel@tonic-gate {
1014*7c478bd9Sstevel@tonic-gate 	consms_msg_t	*msg;
1015*7c478bd9Sstevel@tonic-gate 	consms_msg_t	*prev_msg;
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
1018*7c478bd9Sstevel@tonic-gate 	prev_msg = NULL;
1019*7c478bd9Sstevel@tonic-gate 	for (msg = consms_mux_msg; msg != NULL;
1020*7c478bd9Sstevel@tonic-gate 	    prev_msg = msg, msg = msg->msg_next) {
1021*7c478bd9Sstevel@tonic-gate 		if (msg->msg_id == msg_id)
1022*7c478bd9Sstevel@tonic-gate 			break;
1023*7c478bd9Sstevel@tonic-gate 	}
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	if (msg != NULL) {
1026*7c478bd9Sstevel@tonic-gate 		if (prev_msg != NULL) {
1027*7c478bd9Sstevel@tonic-gate 			prev_msg->msg_next = msg->msg_next;
1028*7c478bd9Sstevel@tonic-gate 		} else {
1029*7c478bd9Sstevel@tonic-gate 			consms_mux_msg = consms_mux_msg->msg_next;
1030*7c478bd9Sstevel@tonic-gate 		}
1031*7c478bd9Sstevel@tonic-gate 		msg->msg_next = NULL;
1032*7c478bd9Sstevel@tonic-gate 	}
1033*7c478bd9Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	return (msg);
1036*7c478bd9Sstevel@tonic-gate }
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate static consms_msg_t *
1039*7c478bd9Sstevel@tonic-gate consms_mux_find_msg(uint_t msg_id)
1040*7c478bd9Sstevel@tonic-gate {
1041*7c478bd9Sstevel@tonic-gate 	consms_msg_t	*msg;
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	mutex_enter(&consms_msg_lock);
1044*7c478bd9Sstevel@tonic-gate 	for (msg = consms_mux_msg; msg != NULL; msg = msg->msg_next) {
1045*7c478bd9Sstevel@tonic-gate 		if (msg->msg_id == msg_id)
1046*7c478bd9Sstevel@tonic-gate 			break;
1047*7c478bd9Sstevel@tonic-gate 	}
1048*7c478bd9Sstevel@tonic-gate 	mutex_exit(&consms_msg_lock);
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	return (msg);
1051*7c478bd9Sstevel@tonic-gate }
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate /*
1054*7c478bd9Sstevel@tonic-gate  * Received ACK or NAK from lower mice
1055*7c478bd9Sstevel@tonic-gate  *
1056*7c478bd9Sstevel@tonic-gate  * For non-transparent ioctl, the msg->msg_rsp_list
1057*7c478bd9Sstevel@tonic-gate  * is always NULL; for transparent ioctl, it
1058*7c478bd9Sstevel@tonic-gate  * remembers the M_COPYIN/M_COPYOUT request
1059*7c478bd9Sstevel@tonic-gate  * messages from lower mice. So here if msg->msg_rsp_list
1060*7c478bd9Sstevel@tonic-gate  * is NULL (after receiving all ACK/NAKs), we
1061*7c478bd9Sstevel@tonic-gate  * are done with this specific ioctl.
1062*7c478bd9Sstevel@tonic-gate  *
1063*7c478bd9Sstevel@tonic-gate  * As long as one of lower mice responds success,
1064*7c478bd9Sstevel@tonic-gate  * we treat it success for a ioctl.
1065*7c478bd9Sstevel@tonic-gate  */
1066*7c478bd9Sstevel@tonic-gate static void
1067*7c478bd9Sstevel@tonic-gate consms_mux_ack(consms_msg_t *msg, mblk_t *mp)
1068*7c478bd9Sstevel@tonic-gate {
1069*7c478bd9Sstevel@tonic-gate 	mblk_t	*ack_mp;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	/* increment response_nums */
1072*7c478bd9Sstevel@tonic-gate 	msg->msg_num_responses++;
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type == M_IOCACK) {
1075*7c478bd9Sstevel@tonic-gate 		/*
1076*7c478bd9Sstevel@tonic-gate 		 * Received ACK from lower, then
1077*7c478bd9Sstevel@tonic-gate 		 * this is the last step for both
1078*7c478bd9Sstevel@tonic-gate 		 * non-transparent and transparent
1079*7c478bd9Sstevel@tonic-gate 		 * ioctl. We only need to remember
1080*7c478bd9Sstevel@tonic-gate 		 * one of the ACKs, finally reply
1081*7c478bd9Sstevel@tonic-gate 		 * this ACK to upper layer for this
1082*7c478bd9Sstevel@tonic-gate 		 * specific ioctl.
1083*7c478bd9Sstevel@tonic-gate 		 */
1084*7c478bd9Sstevel@tonic-gate 		ASSERT(msg->msg_rsp_list == NULL);
1085*7c478bd9Sstevel@tonic-gate 		if (msg->msg_ack_mp == NULL) {
1086*7c478bd9Sstevel@tonic-gate 			msg->msg_ack_mp = mp;
1087*7c478bd9Sstevel@tonic-gate 			mp = NULL;
1088*7c478bd9Sstevel@tonic-gate 		}
1089*7c478bd9Sstevel@tonic-gate 	}
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate 	/*
1092*7c478bd9Sstevel@tonic-gate 	 * Check to see if all lower mice have responded
1093*7c478bd9Sstevel@tonic-gate 	 * to our dispatching ioctl.
1094*7c478bd9Sstevel@tonic-gate 	 */
1095*7c478bd9Sstevel@tonic-gate 	if (msg->msg_num_responses == msg->msg_num_requests) {
1096*7c478bd9Sstevel@tonic-gate 		if ((msg->msg_ack_mp == NULL) &&
1097*7c478bd9Sstevel@tonic-gate 		    (msg->msg_rsp_list == NULL)) {
1098*7c478bd9Sstevel@tonic-gate 			/*
1099*7c478bd9Sstevel@tonic-gate 			 * All are NAKed.
1100*7c478bd9Sstevel@tonic-gate 			 */
1101*7c478bd9Sstevel@tonic-gate 			ack_mp = mp;
1102*7c478bd9Sstevel@tonic-gate 			mp = NULL;
1103*7c478bd9Sstevel@tonic-gate 		} else if (msg->msg_rsp_list == NULL) {
1104*7c478bd9Sstevel@tonic-gate 			/*
1105*7c478bd9Sstevel@tonic-gate 			 * The last step and at least one ACKed.
1106*7c478bd9Sstevel@tonic-gate 			 */
1107*7c478bd9Sstevel@tonic-gate 			ack_mp = msg->msg_ack_mp;
1108*7c478bd9Sstevel@tonic-gate 			consms_mux_cache_states(msg->msg_request);
1109*7c478bd9Sstevel@tonic-gate 			consms_mux_max_wheel_report(ack_mp);
1110*7c478bd9Sstevel@tonic-gate 		} else {
1111*7c478bd9Sstevel@tonic-gate 			/*
1112*7c478bd9Sstevel@tonic-gate 			 * This is a NAK, but we have
1113*7c478bd9Sstevel@tonic-gate 			 * already received M_COPYIN
1114*7c478bd9Sstevel@tonic-gate 			 * or M_COPYOUT request from
1115*7c478bd9Sstevel@tonic-gate 			 * at least one of lower mice.
1116*7c478bd9Sstevel@tonic-gate 			 * (msg->msg_rsp_list != NULL)
1117*7c478bd9Sstevel@tonic-gate 			 *
1118*7c478bd9Sstevel@tonic-gate 			 * Still copyin or copyout.
1119*7c478bd9Sstevel@tonic-gate 			 */
1120*7c478bd9Sstevel@tonic-gate 			ack_mp = msg->msg_rsp_list->rsp_mp;
1121*7c478bd9Sstevel@tonic-gate 			consms_mux_max_wheel_report(ack_mp);
1122*7c478bd9Sstevel@tonic-gate 		}
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 		qreply(msg->msg_queue, ack_mp);
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 		if (msg->msg_rsp_list == NULL) {
1127*7c478bd9Sstevel@tonic-gate 			/*
1128*7c478bd9Sstevel@tonic-gate 			 * We are done with this ioctl.
1129*7c478bd9Sstevel@tonic-gate 			 */
1130*7c478bd9Sstevel@tonic-gate 			if (msg->msg_request)
1131*7c478bd9Sstevel@tonic-gate 				freemsg(msg->msg_request);
1132*7c478bd9Sstevel@tonic-gate 			(void) consms_mux_unlink_msg(msg->msg_id);
1133*7c478bd9Sstevel@tonic-gate 			kmem_free(msg, sizeof (*msg));
1134*7c478bd9Sstevel@tonic-gate 		}
1135*7c478bd9Sstevel@tonic-gate 	}
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 	if (mp) {
1138*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1139*7c478bd9Sstevel@tonic-gate 	}
1140*7c478bd9Sstevel@tonic-gate }
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate /*
1143*7c478bd9Sstevel@tonic-gate  * Received M_COPYIN or M_COPYOUT request from
1144*7c478bd9Sstevel@tonic-gate  * lower mice for transparent ioctl
1145*7c478bd9Sstevel@tonic-gate  *
1146*7c478bd9Sstevel@tonic-gate  * We remember each M_COPYIN/M_COPYOUT into the
1147*7c478bd9Sstevel@tonic-gate  * msg->msg_rsp_list, reply upper layer using the first
1148*7c478bd9Sstevel@tonic-gate  * M_COPYIN/M_COPYOUT in the list after receiving
1149*7c478bd9Sstevel@tonic-gate  * all responses from lower mice, even if some of
1150*7c478bd9Sstevel@tonic-gate  * them return NAKs.
1151*7c478bd9Sstevel@tonic-gate  */
1152*7c478bd9Sstevel@tonic-gate static void
1153*7c478bd9Sstevel@tonic-gate consms_mux_copyreq(queue_t *q, consms_msg_t *msg, mblk_t *mp)
1154*7c478bd9Sstevel@tonic-gate {
1155*7c478bd9Sstevel@tonic-gate 	consms_response_t	*rsp;
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	rsp = (consms_response_t *)kmem_zalloc(sizeof (*rsp), KM_SLEEP);
1158*7c478bd9Sstevel@tonic-gate 	rsp->rsp_mp = mp;
1159*7c478bd9Sstevel@tonic-gate 	rsp->rsp_queue = q;
1160*7c478bd9Sstevel@tonic-gate 	if (msg->msg_rsp_list) {
1161*7c478bd9Sstevel@tonic-gate 		rsp->rsp_next = msg->msg_rsp_list;
1162*7c478bd9Sstevel@tonic-gate 	}
1163*7c478bd9Sstevel@tonic-gate 	msg->msg_rsp_list = rsp;
1164*7c478bd9Sstevel@tonic-gate 	msg->msg_num_responses++;
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 	if (msg->msg_num_responses == msg->msg_num_requests) {
1167*7c478bd9Sstevel@tonic-gate 		consms_mux_max_wheel_report(msg->msg_rsp_list->rsp_mp);
1168*7c478bd9Sstevel@tonic-gate 		qreply(msg->msg_queue, msg->msg_rsp_list->rsp_mp);
1169*7c478bd9Sstevel@tonic-gate 	}
1170*7c478bd9Sstevel@tonic-gate }
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate /*
1173*7c478bd9Sstevel@tonic-gate  * Do the real job for updating M_COPYIN/M_COPYOUT
1174*7c478bd9Sstevel@tonic-gate  * request with the mp of M_IOCDATA, then put it
1175*7c478bd9Sstevel@tonic-gate  * down to lower mice.
1176*7c478bd9Sstevel@tonic-gate  */
1177*7c478bd9Sstevel@tonic-gate static void
1178*7c478bd9Sstevel@tonic-gate consms_mux_disp_iocdata(consms_response_t *rsp, mblk_t *mp)
1179*7c478bd9Sstevel@tonic-gate {
1180*7c478bd9Sstevel@tonic-gate 	mblk_t	*down_mp = rsp->rsp_mp;
1181*7c478bd9Sstevel@tonic-gate 	struct copyresp *copyresp = (struct copyresp *)mp->b_rptr;
1182*7c478bd9Sstevel@tonic-gate 	struct copyresp *newresp = (struct copyresp *)down_mp->b_rptr;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	/*
1185*7c478bd9Sstevel@tonic-gate 	 * Update the rval.
1186*7c478bd9Sstevel@tonic-gate 	 */
1187*7c478bd9Sstevel@tonic-gate 	newresp->cp_rval = copyresp->cp_rval;
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate 	/*
1190*7c478bd9Sstevel@tonic-gate 	 * Update the db_type to M_IOCDATA.
1191*7c478bd9Sstevel@tonic-gate 	 */
1192*7c478bd9Sstevel@tonic-gate 	down_mp->b_datap->db_type = mp->b_datap->db_type;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 	/*
1195*7c478bd9Sstevel@tonic-gate 	 * Update the b_cont.
1196*7c478bd9Sstevel@tonic-gate 	 */
1197*7c478bd9Sstevel@tonic-gate 	if (down_mp->b_cont != NULL) {
1198*7c478bd9Sstevel@tonic-gate 		freemsg(down_mp->b_cont);
1199*7c478bd9Sstevel@tonic-gate 		down_mp->b_cont = NULL;
1200*7c478bd9Sstevel@tonic-gate 	}
1201*7c478bd9Sstevel@tonic-gate 	if (mp->b_cont != NULL) {
1202*7c478bd9Sstevel@tonic-gate 		down_mp->b_cont = copymsg(mp->b_cont);
1203*7c478bd9Sstevel@tonic-gate 	}
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 	/*
1206*7c478bd9Sstevel@tonic-gate 	 * Put it down.
1207*7c478bd9Sstevel@tonic-gate 	 */
1208*7c478bd9Sstevel@tonic-gate 	(void) putq(WR(rsp->rsp_queue), down_mp);
1209*7c478bd9Sstevel@tonic-gate }
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate /*
1212*7c478bd9Sstevel@tonic-gate  * Dispatch M_IOCDATA down to all lower mice
1213*7c478bd9Sstevel@tonic-gate  * for transparent ioctl.
1214*7c478bd9Sstevel@tonic-gate  *
1215*7c478bd9Sstevel@tonic-gate  * We update each M_COPYIN/M_COPYOUT in the
1216*7c478bd9Sstevel@tonic-gate  * msg->msg_rsp_list with the M_IOCDATA.
1217*7c478bd9Sstevel@tonic-gate  */
1218*7c478bd9Sstevel@tonic-gate static void
1219*7c478bd9Sstevel@tonic-gate consms_mux_iocdata(consms_msg_t *msg, mblk_t *mp)
1220*7c478bd9Sstevel@tonic-gate {
1221*7c478bd9Sstevel@tonic-gate 	consms_response_t	*rsp;
1222*7c478bd9Sstevel@tonic-gate 	consms_response_t	*tmp;
1223*7c478bd9Sstevel@tonic-gate 	consms_response_t	*first;
1224*7c478bd9Sstevel@tonic-gate 	struct copyresp		*copyresp;
1225*7c478bd9Sstevel@tonic-gate 	int			request_nums;
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 	ASSERT(msg->msg_rsp_list != NULL);
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate 	/*
1230*7c478bd9Sstevel@tonic-gate 	 * We should remember the ioc data for
1231*7c478bd9Sstevel@tonic-gate 	 * VUIDSWHEELSTATE, and MSIOSRESOLUTION,
1232*7c478bd9Sstevel@tonic-gate 	 * for we will cache the wheel state and
1233*7c478bd9Sstevel@tonic-gate 	 * the screen resolution later if ACKed.
1234*7c478bd9Sstevel@tonic-gate 	 */
1235*7c478bd9Sstevel@tonic-gate 	copyresp = (struct copyresp *)mp->b_rptr;
1236*7c478bd9Sstevel@tonic-gate 	if ((copyresp->cp_cmd == VUIDSWHEELSTATE) ||
1237*7c478bd9Sstevel@tonic-gate 	    (copyresp->cp_cmd == MSIOSRESOLUTION)) {
1238*7c478bd9Sstevel@tonic-gate 		freemsg(msg->msg_request);
1239*7c478bd9Sstevel@tonic-gate 		msg->msg_request = copymsg(mp);
1240*7c478bd9Sstevel@tonic-gate 	}
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	/*
1243*7c478bd9Sstevel@tonic-gate 	 * Update request numbers and response numbers.
1244*7c478bd9Sstevel@tonic-gate 	 */
1245*7c478bd9Sstevel@tonic-gate 	msg->msg_num_requests = msg->msg_num_responses;
1246*7c478bd9Sstevel@tonic-gate 	msg->msg_num_responses = 0;
1247*7c478bd9Sstevel@tonic-gate 	request_nums = 1;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	/*
1250*7c478bd9Sstevel@tonic-gate 	 * Since we have use the first M_COPYIN/M_COPYOUT
1251*7c478bd9Sstevel@tonic-gate 	 * in the msg_rsp_list to reply upper layer, the mp
1252*7c478bd9Sstevel@tonic-gate 	 * of M_IOCDATA can be directly used for that.
1253*7c478bd9Sstevel@tonic-gate 	 */
1254*7c478bd9Sstevel@tonic-gate 	first = msg->msg_rsp_list;
1255*7c478bd9Sstevel@tonic-gate 	rsp = first->rsp_next;
1256*7c478bd9Sstevel@tonic-gate 	msg->msg_rsp_list = NULL;
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	for (rsp = first->rsp_next; rsp != NULL; ) {
1259*7c478bd9Sstevel@tonic-gate 		tmp = rsp;
1260*7c478bd9Sstevel@tonic-gate 		rsp = rsp->rsp_next;
1261*7c478bd9Sstevel@tonic-gate 		consms_mux_disp_iocdata(tmp, mp);
1262*7c478bd9Sstevel@tonic-gate 		kmem_free(tmp, sizeof (*tmp));
1263*7c478bd9Sstevel@tonic-gate 		request_nums++;
1264*7c478bd9Sstevel@tonic-gate 	}
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	/* Must set the request number before the last q. */
1267*7c478bd9Sstevel@tonic-gate 	msg->msg_num_requests = request_nums;
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 	/* the first one */
1270*7c478bd9Sstevel@tonic-gate 	(void) putq(WR(first->rsp_queue), mp);
1271*7c478bd9Sstevel@tonic-gate 	kmem_free(first, sizeof (*first));
1272*7c478bd9Sstevel@tonic-gate }
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate /*
1276*7c478bd9Sstevel@tonic-gate  * Here we update the number of wheels with
1277*7c478bd9Sstevel@tonic-gate  * the virtual mouse for VUIDGWHEELCOUNT ioctl.
1278*7c478bd9Sstevel@tonic-gate  */
1279*7c478bd9Sstevel@tonic-gate static void
1280*7c478bd9Sstevel@tonic-gate consms_mux_max_wheel_report(mblk_t *mp)
1281*7c478bd9Sstevel@tonic-gate {
1282*7c478bd9Sstevel@tonic-gate 	struct iocblk		*iocp;
1283*7c478bd9Sstevel@tonic-gate 	int			num_wheels;
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	if (mp == NULL || mp->b_cont == NULL)
1286*7c478bd9Sstevel@tonic-gate 		return;
1287*7c478bd9Sstevel@tonic-gate 
1288*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	if ((iocp->ioc_cmd == VUIDGWHEELCOUNT) &&
1291*7c478bd9Sstevel@tonic-gate 	    (mp->b_datap->db_type == M_COPYOUT)) {
1292*7c478bd9Sstevel@tonic-gate 		num_wheels = *(int *)mp->b_cont->b_rptr;
1293*7c478bd9Sstevel@tonic-gate 		if (num_wheels < consms_state.consms_num_wheels) {
1294*7c478bd9Sstevel@tonic-gate 			*(int *)mp->b_cont->b_rptr =
1295*7c478bd9Sstevel@tonic-gate 			    consms_state.consms_num_wheels;
1296*7c478bd9Sstevel@tonic-gate 		}
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate }
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate /*
1301*7c478bd9Sstevel@tonic-gate  * Update the virtual mouse state variables with
1302*7c478bd9Sstevel@tonic-gate  * the latest value from upper layer when these
1303*7c478bd9Sstevel@tonic-gate  * set ioctls return success. Thus we can update
1304*7c478bd9Sstevel@tonic-gate  * low mice with the latest state values during
1305*7c478bd9Sstevel@tonic-gate  * hotplug.
1306*7c478bd9Sstevel@tonic-gate  */
1307*7c478bd9Sstevel@tonic-gate static void
1308*7c478bd9Sstevel@tonic-gate consms_mux_cache_states(mblk_t *mp)
1309*7c478bd9Sstevel@tonic-gate {
1310*7c478bd9Sstevel@tonic-gate 	struct iocblk 		*iocp;
1311*7c478bd9Sstevel@tonic-gate 	Ms_parms		*parms;
1312*7c478bd9Sstevel@tonic-gate 	Ms_screen_resolution	*sr;
1313*7c478bd9Sstevel@tonic-gate 	wheel_state		*ws;
1314*7c478bd9Sstevel@tonic-gate 
1315*7c478bd9Sstevel@tonic-gate 	if (mp == NULL || mp->b_cont == NULL)
1316*7c478bd9Sstevel@tonic-gate 		return;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
1319*7c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
1320*7c478bd9Sstevel@tonic-gate 	case VUIDSFORMAT:
1321*7c478bd9Sstevel@tonic-gate 		consms_state.consms_vuid_format = *(int *)mp->b_cont->b_rptr;
1322*7c478bd9Sstevel@tonic-gate 		break;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	case MSIOSETPARMS:
1325*7c478bd9Sstevel@tonic-gate 		parms = (Ms_parms *)mp->b_cont->b_rptr;
1326*7c478bd9Sstevel@tonic-gate 		consms_state.consms_ms_parms = *parms;
1327*7c478bd9Sstevel@tonic-gate 		break;
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate 	case MSIOSRESOLUTION:
1330*7c478bd9Sstevel@tonic-gate 		sr = (Ms_screen_resolution *)mp->b_cont->b_rptr;
1331*7c478bd9Sstevel@tonic-gate 		consms_state.consms_ms_sr = *sr;
1332*7c478bd9Sstevel@tonic-gate 		break;
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	case VUIDSWHEELSTATE:
1335*7c478bd9Sstevel@tonic-gate 		ws = (wheel_state *)mp->b_cont->b_rptr;
1336*7c478bd9Sstevel@tonic-gate 		consms_state.consms_wheel_state_bf =
1337*7c478bd9Sstevel@tonic-gate 		    (ws->stateflags << ws->id) |
1338*7c478bd9Sstevel@tonic-gate 		    (consms_state.consms_wheel_state_bf & ~(1 << ws->id));
1339*7c478bd9Sstevel@tonic-gate 		break;
1340*7c478bd9Sstevel@tonic-gate 	}
1341*7c478bd9Sstevel@tonic-gate }
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate /*
1344*7c478bd9Sstevel@tonic-gate  * Dispatch ioctl mp (non-transparent and transparent)
1345*7c478bd9Sstevel@tonic-gate  * down to all lower mice.
1346*7c478bd9Sstevel@tonic-gate  *
1347*7c478bd9Sstevel@tonic-gate  * First, create a pending message for this mp, link it into
1348*7c478bd9Sstevel@tonic-gate  * the global messages list. Then wait for ACK/NAK for
1349*7c478bd9Sstevel@tonic-gate  * non-transparent ioctl, COPYIN/COPYOUT for transparent
1350*7c478bd9Sstevel@tonic-gate  * ioctl.
1351*7c478bd9Sstevel@tonic-gate  */
1352*7c478bd9Sstevel@tonic-gate static int
1353*7c478bd9Sstevel@tonic-gate consms_mux_disp_ioctl(queue_t *q, mblk_t *mp)
1354*7c478bd9Sstevel@tonic-gate {
1355*7c478bd9Sstevel@tonic-gate 	struct iocblk	*iocp;
1356*7c478bd9Sstevel@tonic-gate 	consms_msg_t	*msg;
1357*7c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
1358*7c478bd9Sstevel@tonic-gate 	mblk_t		*copy_mp;
1359*7c478bd9Sstevel@tonic-gate 	int		error = 0;
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
1362*7c478bd9Sstevel@tonic-gate 	msg = (consms_msg_t *)kmem_zalloc(sizeof (*msg), KM_SLEEP);
1363*7c478bd9Sstevel@tonic-gate 	msg->msg_id = iocp->ioc_id;
1364*7c478bd9Sstevel@tonic-gate 	msg->msg_request = mp;
1365*7c478bd9Sstevel@tonic-gate 	msg->msg_queue = q;
1366*7c478bd9Sstevel@tonic-gate 	msg->msg_num_requests = consms_state.consms_num_lqs;
1367*7c478bd9Sstevel@tonic-gate 	consms_mux_link_msg(msg);
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
1370*7c478bd9Sstevel@tonic-gate 		if ((copy_mp = copymsg(mp)) != NULL) {
1371*7c478bd9Sstevel@tonic-gate 			(void) putq(lq->lq_queue, copy_mp);
1372*7c478bd9Sstevel@tonic-gate 		} else {
1373*7c478bd9Sstevel@tonic-gate 			/*
1374*7c478bd9Sstevel@tonic-gate 			 * If copymsg fails, we ignore this lq and
1375*7c478bd9Sstevel@tonic-gate 			 * try next one. As long as one of them succeeds,
1376*7c478bd9Sstevel@tonic-gate 			 * we dispatch this ioctl down. And later as long
1377*7c478bd9Sstevel@tonic-gate 			 * as one of the lower drivers return success, we
1378*7c478bd9Sstevel@tonic-gate 			 * reply to this ioctl with success.
1379*7c478bd9Sstevel@tonic-gate 			 */
1380*7c478bd9Sstevel@tonic-gate 			msg->msg_num_requests--;
1381*7c478bd9Sstevel@tonic-gate 		}
1382*7c478bd9Sstevel@tonic-gate 	}
1383*7c478bd9Sstevel@tonic-gate 
1384*7c478bd9Sstevel@tonic-gate 	if (msg->msg_num_requests <= 0) {
1385*7c478bd9Sstevel@tonic-gate 		/*
1386*7c478bd9Sstevel@tonic-gate 		 * Since copymsg fails for all lqs, we NAK this ioctl.
1387*7c478bd9Sstevel@tonic-gate 		 */
1388*7c478bd9Sstevel@tonic-gate 		(void) consms_mux_unlink_msg(msg->msg_id);
1389*7c478bd9Sstevel@tonic-gate 		kmem_free(msg, sizeof (*msg));
1390*7c478bd9Sstevel@tonic-gate 		error = ENOMEM;
1391*7c478bd9Sstevel@tonic-gate 	}
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate 	return (error);
1394*7c478bd9Sstevel@tonic-gate }
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate /*
1397*7c478bd9Sstevel@tonic-gate  * Dispatch M_DATA and M_FLUSH message down to all
1398*7c478bd9Sstevel@tonic-gate  * lower mice, and there are no acknowledgements
1399*7c478bd9Sstevel@tonic-gate  * for them. Here we just copy the mp and then
1400*7c478bd9Sstevel@tonic-gate  * put it into the lower queues.
1401*7c478bd9Sstevel@tonic-gate  */
1402*7c478bd9Sstevel@tonic-gate static void
1403*7c478bd9Sstevel@tonic-gate consms_mux_disp_data(mblk_t *mp)
1404*7c478bd9Sstevel@tonic-gate {
1405*7c478bd9Sstevel@tonic-gate 	consms_lq_t	*lq;
1406*7c478bd9Sstevel@tonic-gate 	mblk_t		*copy_mp;
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate 	for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
1409*7c478bd9Sstevel@tonic-gate 		if ((copy_mp = copymsg(mp)) != NULL) {
1410*7c478bd9Sstevel@tonic-gate 			(void) putq(lq->lq_queue, copy_mp);
1411*7c478bd9Sstevel@tonic-gate 		}
1412*7c478bd9Sstevel@tonic-gate 	}
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
1415*7c478bd9Sstevel@tonic-gate }
1416