Home | History | Annotate | Download | only in io
      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();
     85 static int	consmsclose();
     86 static void	consmsuwput();
     87 static void	consmslrput();
     88 static void	consmslwserv();
     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 	(int (*)())consmsuwput,
    111 	(int (*)())NULL,
    112 	consmsopen,
    113 	consmsclose,
    114 	(int (*)())NULL,
    115 	&consmsm_info,
    116 	NULL
    117 };
    118 
    119 static struct qinit consmslrinit = {
    120 	(int (*)())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 	(int (*)())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
    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(ushort_t 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</