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