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