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