10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51662Sqz150045 * Common Development and Distribution License (the "License").
61662Sqz150045 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
227187Shh224818 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * Console mouse driver for Sun.
290Sstevel@tonic-gate * The console "zs" port is linked under us, with the "ms" module pushed
300Sstevel@tonic-gate * on top of it.
310Sstevel@tonic-gate *
320Sstevel@tonic-gate * This device merely provides a way to have "/dev/mouse" automatically
330Sstevel@tonic-gate * have the "ms" module present. Due to problems with the way the "specfs"
340Sstevel@tonic-gate * file system works, you can't use an indirect device (a "stat" on
350Sstevel@tonic-gate * "/dev/mouse" won't get the right snode, so you won't get the right time
360Sstevel@tonic-gate * of last access), and due to problems with the kernel window system code,
370Sstevel@tonic-gate * you can't use a "cons"-like driver ("/dev/mouse" won't be a streams device,
380Sstevel@tonic-gate * even though operations on it get turned into operations on the real stream).
390Sstevel@tonic-gate *
400Sstevel@tonic-gate * This module supports multiple mice connected to the system at the same time.
410Sstevel@tonic-gate * All the mice are linked under consms, and act as a mouse with replicated
420Sstevel@tonic-gate * clicks. Only USB and PS/2 mouse are supported to be virtual mouse now.
430Sstevel@tonic-gate */
440Sstevel@tonic-gate
450Sstevel@tonic-gate #include <sys/types.h>
460Sstevel@tonic-gate #include <sys/param.h>
470Sstevel@tonic-gate #include <sys/stropts.h>
480Sstevel@tonic-gate #include <sys/stream.h>
490Sstevel@tonic-gate #include <sys/strsun.h>
500Sstevel@tonic-gate #include <sys/conf.h>
510Sstevel@tonic-gate #include <sys/stat.h>
520Sstevel@tonic-gate #include <sys/errno.h>
530Sstevel@tonic-gate #include <sys/modctl.h>
540Sstevel@tonic-gate #include <sys/consdev.h>
550Sstevel@tonic-gate #include <sys/ddi.h>
560Sstevel@tonic-gate #include <sys/sunddi.h>
570Sstevel@tonic-gate #include <sys/kstat.h>
580Sstevel@tonic-gate #include <sys/vuid_wheel.h>
590Sstevel@tonic-gate #include <sys/msio.h>
600Sstevel@tonic-gate #include <sys/consms.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate static void consms_plink(queue_t *, mblk_t *);
630Sstevel@tonic-gate static int consms_punlink(queue_t *, mblk_t *);
640Sstevel@tonic-gate static void
650Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *, mblk_t *);
660Sstevel@tonic-gate static void consms_add_lq(consms_lq_t *);
670Sstevel@tonic-gate static void consms_check_caps(void);
687187Shh224818 static mblk_t *consms_new_firm_event(ushort_t, int);
690Sstevel@tonic-gate
700Sstevel@tonic-gate static void consms_mux_max_wheel_report(mblk_t *);
710Sstevel@tonic-gate static void consms_mux_cache_states(mblk_t *);
720Sstevel@tonic-gate static void consms_mux_link_msg(consms_msg_t *);
730Sstevel@tonic-gate static consms_msg_t *consms_mux_unlink_msg(uint_t);
740Sstevel@tonic-gate static consms_msg_t *consms_mux_find_msg(uint_t);
750Sstevel@tonic-gate
760Sstevel@tonic-gate static void consms_mux_iocdata(consms_msg_t *, mblk_t *);
770Sstevel@tonic-gate static void consms_mux_disp_iocdata(consms_response_t *, mblk_t *);
780Sstevel@tonic-gate static int consms_mux_disp_ioctl(queue_t *, mblk_t *);
790Sstevel@tonic-gate static void consms_mux_copyreq(queue_t *, consms_msg_t *, mblk_t *);
800Sstevel@tonic-gate static void consms_mux_ack(consms_msg_t *, mblk_t *);
810Sstevel@tonic-gate static void consms_mux_disp_data(mblk_t *);
820Sstevel@tonic-gate
830Sstevel@tonic-gate
840Sstevel@tonic-gate static int consmsopen();
850Sstevel@tonic-gate static int consmsclose();
860Sstevel@tonic-gate static void consmsuwput();
870Sstevel@tonic-gate static void consmslrput();
880Sstevel@tonic-gate static void consmslwserv();
890Sstevel@tonic-gate
900Sstevel@tonic-gate static struct module_info consmsm_info = {
910Sstevel@tonic-gate 0,
920Sstevel@tonic-gate "consms",
930Sstevel@tonic-gate 0,
940Sstevel@tonic-gate 1024,
950Sstevel@tonic-gate 2048,
960Sstevel@tonic-gate 128
970Sstevel@tonic-gate };
980Sstevel@tonic-gate
990Sstevel@tonic-gate static struct qinit consmsurinit = {
1000Sstevel@tonic-gate putq,
1010Sstevel@tonic-gate (int (*)())NULL,
1020Sstevel@tonic-gate consmsopen,
1030Sstevel@tonic-gate consmsclose,
1040Sstevel@tonic-gate (int (*)())NULL,
1050Sstevel@tonic-gate &consmsm_info,
1060Sstevel@tonic-gate NULL
1070Sstevel@tonic-gate };
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate static struct qinit consmsuwinit = {
1100Sstevel@tonic-gate (int (*)())consmsuwput,
1110Sstevel@tonic-gate (int (*)())NULL,
1120Sstevel@tonic-gate consmsopen,
1130Sstevel@tonic-gate consmsclose,
1140Sstevel@tonic-gate (int (*)())NULL,
1150Sstevel@tonic-gate &consmsm_info,
1160Sstevel@tonic-gate NULL
1170Sstevel@tonic-gate };
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate static struct qinit consmslrinit = {
1200Sstevel@tonic-gate (int (*)())consmslrput,
1210Sstevel@tonic-gate (int (*)())NULL,
1220Sstevel@tonic-gate (int (*)())NULL,
1230Sstevel@tonic-gate (int (*)())NULL,
1240Sstevel@tonic-gate (int (*)())NULL,
1250Sstevel@tonic-gate &consmsm_info,
1260Sstevel@tonic-gate NULL
1270Sstevel@tonic-gate };
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate static struct qinit consmslwinit = {
1300Sstevel@tonic-gate putq,
1310Sstevel@tonic-gate (int (*)())consmslwserv,
1320Sstevel@tonic-gate (int (*)())NULL,
1330Sstevel@tonic-gate (int (*)())NULL,
1340Sstevel@tonic-gate (int (*)())NULL,
1350Sstevel@tonic-gate &consmsm_info,
1360Sstevel@tonic-gate NULL
1370Sstevel@tonic-gate };
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate static struct streamtab consms_str_info = {
1400Sstevel@tonic-gate &consmsurinit,
1410Sstevel@tonic-gate &consmsuwinit,
1420Sstevel@tonic-gate &consmslrinit,
1430Sstevel@tonic-gate &consmslwinit,
1440Sstevel@tonic-gate };
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate static void consmsioctl(queue_t *q, mblk_t *mp);
1470Sstevel@tonic-gate static int consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1480Sstevel@tonic-gate void **result);
1490Sstevel@tonic-gate static int consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
1500Sstevel@tonic-gate static int consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
1510Sstevel@tonic-gate static int consms_kstat_update(kstat_t *, int);
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate * Module global data are protected by the per-module inner perimeter.
1550Sstevel@tonic-gate */
1560Sstevel@tonic-gate static queue_t *upperqueue; /* regular mouse queue above us */
1570Sstevel@tonic-gate static dev_info_t *consms_dip; /* private copy of devinfo pointer */
1580Sstevel@tonic-gate static long consms_idle_stamp; /* seconds tstamp of latest mouse op */
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate static consms_msg_t *consms_mux_msg; /* ioctl messages being processed */
1610Sstevel@tonic-gate static kmutex_t consms_msg_lock; /* protect ioctl messages list */
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate static consms_state_t consms_state; /* the global virtual mouse state */
1640Sstevel@tonic-gate static kmutex_t consmslock;
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements. In
1690Sstevel@tonic-gate * this case we use this type for a single element because the ioctl code
1700Sstevel@tonic-gate * for it knows how to handle mixed kernel/user data models. Also, it
1710Sstevel@tonic-gate * will be easier to add new statistics later.
1720Sstevel@tonic-gate */
1730Sstevel@tonic-gate static struct {
1740Sstevel@tonic-gate kstat_named_t idle_sec; /* seconds since last user op */
1750Sstevel@tonic-gate } consms_kstat = {
1760Sstevel@tonic-gate { "idle_sec", KSTAT_DATA_LONG, }
1770Sstevel@tonic-gate };
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate static struct cb_ops cb_consms_ops = {
1810Sstevel@tonic-gate nulldev, /* cb_open */
1820Sstevel@tonic-gate nulldev, /* cb_close */
1830Sstevel@tonic-gate nodev, /* cb_strategy */
1840Sstevel@tonic-gate nodev, /* cb_print */
1850Sstevel@tonic-gate nodev, /* cb_dump */
1860Sstevel@tonic-gate nodev, /* cb_read */
1870Sstevel@tonic-gate nodev, /* cb_write */
1880Sstevel@tonic-gate nodev, /* cb_ioctl */
1890Sstevel@tonic-gate nodev, /* cb_devmap */
1900Sstevel@tonic-gate nodev, /* cb_mmap */
1910Sstevel@tonic-gate nodev, /* cb_segmap */
1920Sstevel@tonic-gate nochpoll, /* cb_chpoll */
1930Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
1940Sstevel@tonic-gate &consms_str_info, /* cb_stream */
1950Sstevel@tonic-gate D_MP | D_MTPERMOD /* cb_flag */
1960Sstevel@tonic-gate };
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate static struct dev_ops consms_ops = {
1990Sstevel@tonic-gate DEVO_REV, /* devo_rev */
2000Sstevel@tonic-gate 0, /* devo_refcnt */
2010Sstevel@tonic-gate consms_info, /* devo_getinfo */
2020Sstevel@tonic-gate nulldev, /* devo_identify */
2030Sstevel@tonic-gate nulldev, /* devo_probe */
2040Sstevel@tonic-gate consms_attach, /* devo_attach */
2050Sstevel@tonic-gate consms_detach, /* devo_detach */
2060Sstevel@tonic-gate nodev, /* devo_reset */
2070Sstevel@tonic-gate &(cb_consms_ops), /* devo_cb_ops */
2080Sstevel@tonic-gate (struct bus_ops *)NULL, /* devo_bus_ops */
209*7656SSherry.Moore@Sun.COM NULL, /* devo_power */
210*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */
2110Sstevel@tonic-gate };
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate * Module linkage information for the kernel.
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate static struct modldrv modldrv = {
2190Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */
220*7656SSherry.Moore@Sun.COM "Mouse Driver for Sun 'consms' 5.57",
2210Sstevel@tonic-gate &consms_ops, /* driver ops */
2220Sstevel@tonic-gate };
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate static struct modlinkage modlinkage = {
2250Sstevel@tonic-gate MODREV_1,
2260Sstevel@tonic-gate (void *)&modldrv,
2270Sstevel@tonic-gate NULL
2280Sstevel@tonic-gate };
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate int
_init(void)2310Sstevel@tonic-gate _init(void)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate int error;
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate mutex_init(&consmslock, NULL, MUTEX_DRIVER, NULL);
2360Sstevel@tonic-gate mutex_init(&consms_msg_lock, NULL, MUTEX_DRIVER, NULL);
2370Sstevel@tonic-gate error = mod_install(&modlinkage);
2380Sstevel@tonic-gate if (error != 0) {
2390Sstevel@tonic-gate mutex_destroy(&consmslock);
2400Sstevel@tonic-gate mutex_destroy(&consms_msg_lock);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate return (error);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate int
_fini(void)2460Sstevel@tonic-gate _fini(void)
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate int error;
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate error = mod_remove(&modlinkage);
2510Sstevel@tonic-gate if (error != 0)
2520Sstevel@tonic-gate return (error);
2530Sstevel@tonic-gate mutex_destroy(&consmslock);
2540Sstevel@tonic-gate mutex_destroy(&consms_msg_lock);
2550Sstevel@tonic-gate return (0);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2590Sstevel@tonic-gate _info(struct modinfo *modinfop)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate static int
consms_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2650Sstevel@tonic-gate consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate kstat_t *ksp;
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate switch (cmd) {
2700Sstevel@tonic-gate case DDI_ATTACH:
2710Sstevel@tonic-gate break;
2720Sstevel@tonic-gate default:
2730Sstevel@tonic-gate return (DDI_FAILURE);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate if (ddi_create_minor_node(devi, "mouse", S_IFCHR,
2777187Shh224818 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
2780Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL);
2790Sstevel@tonic-gate return (-1);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate consms_dip = devi;
2820Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1);
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate ksp = kstat_create("consms", 0, "activity", "misc", KSTAT_TYPE_NAMED,
2850Sstevel@tonic-gate sizeof (consms_kstat) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
2860Sstevel@tonic-gate if (ksp) {
2870Sstevel@tonic-gate ksp->ks_data = (void *)&consms_kstat;
2880Sstevel@tonic-gate ksp->ks_update = consms_kstat_update;
2890Sstevel@tonic-gate kstat_install(ksp);
2900Sstevel@tonic-gate consms_idle_stamp = gethrestime_sec(); /* initial value */
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate consms_state.consms_lqs = NULL;
2940Sstevel@tonic-gate consms_state.consms_num_lqs = 0;
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate /* default consms state values */
2970Sstevel@tonic-gate consms_state.consms_vuid_format = VUID_FIRM_EVENT;
2980Sstevel@tonic-gate consms_state.consms_num_buttons = 0;
2990Sstevel@tonic-gate consms_state.consms_num_wheels = 0;
3000Sstevel@tonic-gate consms_state.consms_wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
3010Sstevel@tonic-gate consms_state.consms_ms_parms.jitter_thresh =
3020Sstevel@tonic-gate CONSMS_PARMS_DEFAULT_JITTER;
3030Sstevel@tonic-gate consms_state.consms_ms_parms.speed_limit =
3040Sstevel@tonic-gate CONSMS_PARMS_DEFAULT_SPEED_LIMIT;
3050Sstevel@tonic-gate consms_state.consms_ms_parms.speed_law =
3060Sstevel@tonic-gate CONSMS_PARMS_DEFAULT_SPEED_LAW;
3070Sstevel@tonic-gate consms_state.consms_ms_sr.height = CONSMS_SR_DEFAULT_HEIGHT;
3080Sstevel@tonic-gate consms_state.consms_ms_sr.width = CONSMS_SR_DEFAULT_WIDTH;
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate return (DDI_SUCCESS);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /*ARGSUSED*/
3140Sstevel@tonic-gate static int
consms_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)3150Sstevel@tonic-gate consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate switch (cmd) {
3180Sstevel@tonic-gate case DDI_DETACH:
3190Sstevel@tonic-gate default:
3200Sstevel@tonic-gate return (DDI_FAILURE);
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate /*ARGSUSED*/
3250Sstevel@tonic-gate static int
consms_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3260Sstevel@tonic-gate consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
3270Sstevel@tonic-gate void **result)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate register int error;
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate switch (infocmd) {
3320Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
3330Sstevel@tonic-gate if (consms_dip == NULL) {
3340Sstevel@tonic-gate error = DDI_FAILURE;
3350Sstevel@tonic-gate } else {
3360Sstevel@tonic-gate *result = (void *) consms_dip;
3370Sstevel@tonic-gate error = DDI_SUCCESS;
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate break;
3400Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
3410Sstevel@tonic-gate *result = (void *)0;
3420Sstevel@tonic-gate error = DDI_SUCCESS;
3430Sstevel@tonic-gate break;
3440Sstevel@tonic-gate default:
3450Sstevel@tonic-gate error = DDI_FAILURE;
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate return (error);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate /*ARGSUSED*/
3520Sstevel@tonic-gate static int
consmsopen(q,devp,flag,sflag,crp)3530Sstevel@tonic-gate consmsopen(q, devp, flag, sflag, crp)
3540Sstevel@tonic-gate queue_t *q;
3550Sstevel@tonic-gate dev_t *devp;
3560Sstevel@tonic-gate int flag, sflag;
3570Sstevel@tonic-gate cred_t *crp;
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate upperqueue = q;
3600Sstevel@tonic-gate qprocson(q);
3610Sstevel@tonic-gate return (0);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate /*ARGSUSED*/
3650Sstevel@tonic-gate static int
consmsclose(q,flag,crp)3660Sstevel@tonic-gate consmsclose(q, flag, crp)
3670Sstevel@tonic-gate queue_t *q;
3680Sstevel@tonic-gate int flag;
3690Sstevel@tonic-gate cred_t *crp;
3700Sstevel@tonic-gate {
3710Sstevel@tonic-gate qprocsoff(q);
3720Sstevel@tonic-gate upperqueue = NULL;
3730Sstevel@tonic-gate return (0);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate /*
3770Sstevel@tonic-gate * Put procedure for upper write queue.
3780Sstevel@tonic-gate */
3790Sstevel@tonic-gate static void
consmsuwput(q,mp)3800Sstevel@tonic-gate consmsuwput(q, mp)
3810Sstevel@tonic-gate register queue_t *q;
3820Sstevel@tonic-gate register mblk_t *mp;
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate struct iocblk *iocbp = (struct iocblk *)mp->b_rptr;
3850Sstevel@tonic-gate consms_msg_t *msg;
3860Sstevel@tonic-gate int error = 0;
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate switch (mp->b_datap->db_type) {
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate case M_IOCTL:
3910Sstevel@tonic-gate consmsioctl(q, mp);
3920Sstevel@tonic-gate break;
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate case M_FLUSH:
3950Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW)
3960Sstevel@tonic-gate flushq(q, FLUSHDATA);
3970Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
3980Sstevel@tonic-gate flushq(RD(q), FLUSHDATA);
3990Sstevel@tonic-gate if (consms_state.consms_num_lqs > 0) {
4000Sstevel@tonic-gate consms_mux_disp_data(mp);
4010Sstevel@tonic-gate } else {
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * No lower queue; just reflect this back upstream.
4040Sstevel@tonic-gate */
4050Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
4060Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
4070Sstevel@tonic-gate qreply(q, mp);
4080Sstevel@tonic-gate else
4090Sstevel@tonic-gate freemsg(mp);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate break;
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate case M_DATA:
4140Sstevel@tonic-gate if (consms_state.consms_num_lqs > 0) {
4150Sstevel@tonic-gate consms_mux_disp_data(mp);
4160Sstevel@tonic-gate } else {
417829Sry162471 freemsg(mp);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate break;
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate case M_IOCDATA:
4220Sstevel@tonic-gate if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
4230Sstevel@tonic-gate consms_mux_iocdata(msg, mp);
4240Sstevel@tonic-gate } else {
4250Sstevel@tonic-gate error = EINVAL;
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate break;
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate default:
4300Sstevel@tonic-gate error = EINVAL;
4310Sstevel@tonic-gate break;
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate if (error) {
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate * Pass an error message up.
4370Sstevel@tonic-gate */
4380Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR;
4390Sstevel@tonic-gate if (mp->b_cont) {
4400Sstevel@tonic-gate freemsg(mp->b_cont);
4410Sstevel@tonic-gate mp->b_cont = NULL;
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base;
4440Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char);
4450Sstevel@tonic-gate *mp->b_rptr = (char)error;
4460Sstevel@tonic-gate qreply(q, mp);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate static void
consmsioctl(q,mp)4510Sstevel@tonic-gate consmsioctl(q, mp)
4520Sstevel@tonic-gate register queue_t *q;
4530Sstevel@tonic-gate register mblk_t *mp;
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate register struct iocblk *iocp;
4560Sstevel@tonic-gate int error;
4570Sstevel@tonic-gate mblk_t *datap;
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate switch (iocp->ioc_cmd) {
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate case I_LINK:
4640Sstevel@tonic-gate case I_PLINK:
4650Sstevel@tonic-gate mutex_enter(&consmslock);
4660Sstevel@tonic-gate consms_plink(q, mp);
4670Sstevel@tonic-gate mutex_exit(&consmslock);
4680Sstevel@tonic-gate return;
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate case I_UNLINK:
4710Sstevel@tonic-gate case I_PUNLINK:
4720Sstevel@tonic-gate mutex_enter(&consmslock);
4730Sstevel@tonic-gate if ((error = consms_punlink(q, mp)) != 0) {
4740Sstevel@tonic-gate mutex_exit(&consmslock);
4750Sstevel@tonic-gate miocnak(q, mp, 0, error);
4760Sstevel@tonic-gate return;
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate mutex_exit(&consmslock);
4790Sstevel@tonic-gate iocp->ioc_count = 0;
4800Sstevel@tonic-gate break;
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate case MSIOBUTTONS: /* query the number of buttons */
4830Sstevel@tonic-gate if ((consms_state.consms_num_lqs <= 0) ||
4840Sstevel@tonic-gate ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)) {
4850Sstevel@tonic-gate miocnak(q, mp, 0, ENOMEM);
4860Sstevel@tonic-gate return;
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate *(int *)datap->b_wptr = consms_state.consms_num_buttons;
4890Sstevel@tonic-gate datap->b_wptr += sizeof (int);
4900Sstevel@tonic-gate if (mp->b_cont) {
4910Sstevel@tonic-gate freemsg(mp->b_cont);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate mp->b_cont = datap;
4940Sstevel@tonic-gate iocp->ioc_count = sizeof (int);
4950Sstevel@tonic-gate break;
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate default:
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * Pass this through, if there's something to pass it
5000Sstevel@tonic-gate * through to; otherwise, reject it.
5010Sstevel@tonic-gate */
5020Sstevel@tonic-gate if (consms_state.consms_num_lqs <= 0) {
5030Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
5040Sstevel@tonic-gate return;
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate if ((error = consms_mux_disp_ioctl(q, mp)) != 0)
5070Sstevel@tonic-gate miocnak(q, mp, 0, error);
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate return;
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate /*
5130Sstevel@tonic-gate * Common exit path for calls that return a positive
5140Sstevel@tonic-gate * acknowledgment with a return value of 0.
5150Sstevel@tonic-gate */
5160Sstevel@tonic-gate miocack(q, mp, iocp->ioc_count, 0);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate /*
5200Sstevel@tonic-gate * Service procedure for lower write queue.
5210Sstevel@tonic-gate * Puts things on the queue below us, if it lets us.
5220Sstevel@tonic-gate */
5230Sstevel@tonic-gate static void
consmslwserv(q)5240Sstevel@tonic-gate consmslwserv(q)
5250Sstevel@tonic-gate register queue_t *q;
5260Sstevel@tonic-gate {
5270Sstevel@tonic-gate register mblk_t *mp;
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate while (canput(q->q_next) && (mp = getq(q)) != NULL)
5300Sstevel@tonic-gate putnext(q, mp);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate * Put procedure for lower read queue.
5350Sstevel@tonic-gate */
5360Sstevel@tonic-gate static void
consmslrput(q,mp)5370Sstevel@tonic-gate consmslrput(q, mp)
5380Sstevel@tonic-gate register queue_t *q;
5390Sstevel@tonic-gate register mblk_t *mp;
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate struct iocblk *iocbp = (struct iocblk *)mp->b_rptr;
5420Sstevel@tonic-gate struct copyreq *copyreq = (struct copyreq *)mp->b_rptr;
5430Sstevel@tonic-gate consms_msg_t *msg;
5440Sstevel@tonic-gate consms_lq_t *lq = (consms_lq_t *)q->q_ptr;
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate ASSERT(lq != NULL);
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate switch (mp->b_datap->db_type) {
5490Sstevel@tonic-gate case M_FLUSH:
5500Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW)
5510Sstevel@tonic-gate flushq(WR(q), FLUSHDATA);
5520Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
5530Sstevel@tonic-gate flushq(q, FLUSHDATA);
5540Sstevel@tonic-gate if (upperqueue != NULL)
5550Sstevel@tonic-gate putnext(upperqueue, mp); /* pass it through */
5560Sstevel@tonic-gate else {
5570Sstevel@tonic-gate /*
5580Sstevel@tonic-gate * No upper queue; just reflect this back downstream.
5590Sstevel@tonic-gate */
5600Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHR;
5610Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW)
5620Sstevel@tonic-gate qreply(q, mp);
5630Sstevel@tonic-gate else
5640Sstevel@tonic-gate freemsg(mp);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate break;
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate case M_DATA:
5690Sstevel@tonic-gate if (upperqueue != NULL)
5700Sstevel@tonic-gate putnext(upperqueue, mp);
5710Sstevel@tonic-gate else
5720Sstevel@tonic-gate freemsg(mp);
5730Sstevel@tonic-gate consms_idle_stamp = gethrestime_sec();
5740Sstevel@tonic-gate break;
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate case M_IOCACK:
5770Sstevel@tonic-gate case M_IOCNAK:
5780Sstevel@tonic-gate /*
5790Sstevel@tonic-gate * First, check to see if this device
5800Sstevel@tonic-gate * is still being initialized.
5810Sstevel@tonic-gate */
5820Sstevel@tonic-gate if (lq->lq_ioc_reply_func != NULL) {
5830Sstevel@tonic-gate mutex_enter(&consmslock);
5840Sstevel@tonic-gate lq->lq_ioc_reply_func(lq, mp);
5850Sstevel@tonic-gate mutex_exit(&consmslock);
5860Sstevel@tonic-gate freemsg(mp);
5870Sstevel@tonic-gate break;
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate /*
5910Sstevel@tonic-gate * This is normal ioctl ack for upper layer.
5920Sstevel@tonic-gate */
5930Sstevel@tonic-gate if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
5940Sstevel@tonic-gate consms_mux_ack(msg, mp);
5950Sstevel@tonic-gate } else {
5960Sstevel@tonic-gate freemsg(mp);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate consms_idle_stamp = gethrestime_sec();
5990Sstevel@tonic-gate break;
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate case M_COPYIN:
6020Sstevel@tonic-gate case M_COPYOUT:
6030Sstevel@tonic-gate if ((msg = consms_mux_find_msg(copyreq->cq_id)) != NULL) {
6040Sstevel@tonic-gate consms_mux_copyreq(q, msg, mp);
6050Sstevel@tonic-gate } else
6060Sstevel@tonic-gate freemsg(mp);
6070Sstevel@tonic-gate consms_idle_stamp = gethrestime_sec();
6080Sstevel@tonic-gate break;
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate case M_ERROR:
6110Sstevel@tonic-gate case M_HANGUP:
6120Sstevel@tonic-gate default:
6130Sstevel@tonic-gate freemsg(mp); /* anything useful here? */
6140Sstevel@tonic-gate break;
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate /* ARGSUSED */
6190Sstevel@tonic-gate static int
consms_kstat_update(kstat_t * ksp,int rw)6200Sstevel@tonic-gate consms_kstat_update(kstat_t *ksp, int rw)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate if (rw == KSTAT_WRITE)
6230Sstevel@tonic-gate return (EACCES);
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate consms_kstat.idle_sec.value.l = gethrestime_sec() - consms_idle_stamp;
6260Sstevel@tonic-gate return (0);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate /*ARGSUSED*/
6300Sstevel@tonic-gate static int
consms_punlink(queue_t * q,mblk_t * mp)6310Sstevel@tonic-gate consms_punlink(queue_t *q, mblk_t *mp)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate struct linkblk *linkp;
6340Sstevel@tonic-gate consms_lq_t *lq;
6350Sstevel@tonic-gate consms_lq_t *prev_lq;
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate ASSERT(MUTEX_HELD(&consmslock));
6380Sstevel@tonic-gate
6390Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr;
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate prev_lq = NULL;
6420Sstevel@tonic-gate for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
6430Sstevel@tonic-gate if (lq->lq_queue == linkp->l_qbot) {
6440Sstevel@tonic-gate if (prev_lq)
6450Sstevel@tonic-gate prev_lq->lq_next = lq->lq_next;
6460Sstevel@tonic-gate else
6470Sstevel@tonic-gate consms_state.consms_lqs = lq->lq_next;
6480Sstevel@tonic-gate kmem_free(lq, sizeof (*lq));
6490Sstevel@tonic-gate consms_state.consms_num_lqs--;
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate /*
6520Sstevel@tonic-gate * Check to see if mouse capabilities
6530Sstevel@tonic-gate * have changed.
6540Sstevel@tonic-gate */
6550Sstevel@tonic-gate consms_check_caps();
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate return (0);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate prev_lq = lq;
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate return (EINVAL);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate * Link a specific mouse into our mouse list.
6670Sstevel@tonic-gate */
6680Sstevel@tonic-gate static void
consms_plink(queue_t * q,mblk_t * mp)6690Sstevel@tonic-gate consms_plink(queue_t *q, mblk_t *mp)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate struct linkblk *linkp;
6720Sstevel@tonic-gate consms_lq_t *lq;
6730Sstevel@tonic-gate queue_t *lowq;
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate ASSERT(MUTEX_HELD(&consmslock));
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr;
6780Sstevel@tonic-gate lowq = linkp->l_qbot;
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate lq = kmem_zalloc(sizeof (*lq), KM_SLEEP);
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate lowq->q_ptr = (void *)lq;
6830Sstevel@tonic-gate OTHERQ(lowq)->q_ptr = (void *)lq;
6840Sstevel@tonic-gate lq->lq_queue = lowq;
6850Sstevel@tonic-gate lq->lq_pending_plink = mp;
6860Sstevel@tonic-gate lq->lq_pending_queue = q;
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /*
6890Sstevel@tonic-gate * Set the number of buttons to 3 by default
6900Sstevel@tonic-gate * in case the following MSIOBUTTONS ioctl fails.
6910Sstevel@tonic-gate */
6920Sstevel@tonic-gate lq->lq_num_buttons = 3;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate /*
6950Sstevel@tonic-gate * Begin to initialize this mouse.
6960Sstevel@tonic-gate */
6970Sstevel@tonic-gate lq->lq_state = LQS_START;
6980Sstevel@tonic-gate consms_lqs_ack_complete(lq, NULL);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate * Initialize the newly hotplugged-in mouse,
7030Sstevel@tonic-gate * e.g. get the number of buttons, set event
7040Sstevel@tonic-gate * format. Then we add it into our list.
7050Sstevel@tonic-gate */
7060Sstevel@tonic-gate static void
consms_lqs_ack_complete(consms_lq_t * lq,mblk_t * mp)7070Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *lq, mblk_t *mp)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate mblk_t *req = NULL;
7100Sstevel@tonic-gate boolean_t skipped = B_FALSE;
7110Sstevel@tonic-gate wheel_state *ws;
7120Sstevel@tonic-gate Ms_screen_resolution *sr;
7130Sstevel@tonic-gate Ms_parms *params;
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate ASSERT(MUTEX_HELD(&consmslock));
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate /*
7180Sstevel@tonic-gate * We try each ioctl even if the previous one fails
7190Sstevel@tonic-gate * until we reach LQS_DONE, and then add this lq
7200Sstevel@tonic-gate * into our lq list.
7210Sstevel@tonic-gate *
7220Sstevel@tonic-gate * If the message allocation fails, we skip this ioctl,
7230Sstevel@tonic-gate * set skipped flag to B_TRUE in order to skip the ioctl
7240Sstevel@tonic-gate * result, then we try next ioctl, go to next state.
7250Sstevel@tonic-gate */
7260Sstevel@tonic-gate while ((lq->lq_state < LQS_DONE) && (req == NULL)) {
7270Sstevel@tonic-gate switch (lq->lq_state) {
7280Sstevel@tonic-gate case LQS_START:
7290Sstevel@tonic-gate /*
7300Sstevel@tonic-gate * First, issue MSIOBUTTONS ioctl
7310Sstevel@tonic-gate * to get the number of buttons.
7320Sstevel@tonic-gate */
7330Sstevel@tonic-gate req = mkiocb(MSIOBUTTONS);
7340Sstevel@tonic-gate if (req && ((req->b_cont = allocb(sizeof (int),
7350Sstevel@tonic-gate BPRI_MED)) == NULL)) {
7360Sstevel@tonic-gate freemsg(req);
7370Sstevel@tonic-gate req = NULL;
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate if (req == NULL)
7400Sstevel@tonic-gate skipped = B_TRUE;
7410Sstevel@tonic-gate lq->lq_state++;
7420Sstevel@tonic-gate break;
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate case LQS_BUTTON_COUNT_PENDING:
7450Sstevel@tonic-gate if (!skipped && mp && mp->b_cont &&
7460Sstevel@tonic-gate (mp->b_datap->db_type == M_IOCACK))
7470Sstevel@tonic-gate lq->lq_num_buttons =
7480Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr;
7490Sstevel@tonic-gate
7500Sstevel@tonic-gate /*
7510Sstevel@tonic-gate * Second, issue VUIDGWHEELCOUNT ioctl
7520Sstevel@tonic-gate * to get the count of wheels.
7530Sstevel@tonic-gate */
7540Sstevel@tonic-gate req = mkiocb(VUIDGWHEELCOUNT);
7550Sstevel@tonic-gate if (req && ((req->b_cont = allocb(sizeof (int),
7560Sstevel@tonic-gate BPRI_MED)) == NULL)) {
7570Sstevel@tonic-gate freemsg(req);
7580Sstevel@tonic-gate req = NULL;
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate if (req == NULL)
7610Sstevel@tonic-gate skipped = B_TRUE;
7620Sstevel@tonic-gate lq->lq_state++;
7630Sstevel@tonic-gate break;
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate case LQS_WHEEL_COUNT_PENDING:
7660Sstevel@tonic-gate if (!skipped && mp && mp->b_cont &&
7670Sstevel@tonic-gate (mp->b_datap->db_type == M_IOCACK))
7680Sstevel@tonic-gate lq->lq_num_wheels =
7690Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr;
7700Sstevel@tonic-gate
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate * Third, issue VUIDSFORMAT ioctl
7730Sstevel@tonic-gate * to set the event format.
7740Sstevel@tonic-gate */
7750Sstevel@tonic-gate req = mkiocb(VUIDSFORMAT);
7760Sstevel@tonic-gate if (req && ((req->b_cont = allocb(sizeof (int),
7770Sstevel@tonic-gate BPRI_MED)) == NULL)) {
7780Sstevel@tonic-gate freemsg(req);
7790Sstevel@tonic-gate req = NULL;
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate if (req) {
7820Sstevel@tonic-gate *(int *)req->b_cont->b_wptr =
7830Sstevel@tonic-gate consms_state.consms_vuid_format;
7840Sstevel@tonic-gate req->b_cont->b_wptr += sizeof (int);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate lq->lq_state++;
7870Sstevel@tonic-gate break;
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate case LQS_SET_VUID_FORMAT_PENDING:
7900Sstevel@tonic-gate /*
7910Sstevel@tonic-gate * Fourth, issue VUIDSWHEELSTATE ioctl
7920Sstevel@tonic-gate * to set the wheel state (enable or disable).
7930Sstevel@tonic-gate */
7940Sstevel@tonic-gate req = mkiocb(VUIDSWHEELSTATE);
7950Sstevel@tonic-gate if (req && ((req->b_cont = allocb(sizeof (wheel_state),
7960Sstevel@tonic-gate BPRI_MED)) == NULL)) {
7970Sstevel@tonic-gate freemsg(req);
7980Sstevel@tonic-gate req = NULL;
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate if (req) {
8010Sstevel@tonic-gate ws = (wheel_state *)req->b_cont->b_wptr;
8020Sstevel@tonic-gate ws->vers = VUID_WHEEL_STATE_VERS;
8030Sstevel@tonic-gate ws->id = 0; /* the first wheel */
8040Sstevel@tonic-gate ws->stateflags =
8050Sstevel@tonic-gate consms_state.consms_wheel_state_bf & 1;
8060Sstevel@tonic-gate req->b_cont->b_wptr += sizeof (wheel_state);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate lq->lq_state++;
8090Sstevel@tonic-gate break;
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate case LQS_SET_WHEEL_STATE_PENDING:
8120Sstevel@tonic-gate /*
8131662Sqz150045 * Fifth, issue MSIOSETPARMS ioctl
8141662Sqz150045 * to set the parameters for USB mouse.
8151662Sqz150045 */
8161662Sqz150045 req = mkiocb(MSIOSETPARMS);
8171662Sqz150045 if (req && ((req->b_cont = allocb(sizeof (Ms_parms),
8181662Sqz150045 BPRI_MED)) == NULL)) {
8191662Sqz150045 freemsg(req);
8201662Sqz150045 req = NULL;
8211662Sqz150045 }
8221662Sqz150045 if (req) {
8231662Sqz150045 params = (Ms_parms *)req->b_cont->b_wptr;
8241662Sqz150045 *params = consms_state.consms_ms_parms;
8251662Sqz150045 req->b_cont->b_wptr += sizeof (Ms_parms);
8261662Sqz150045 }
8271662Sqz150045 lq->lq_state++;
8281662Sqz150045 break;
8291662Sqz150045
8301662Sqz150045 case LQS_SET_PARMS_PENDING:
8311662Sqz150045 /*
8321662Sqz150045 * Sixth, issue MSIOSRESOLUTION ioctl
8330Sstevel@tonic-gate * to set the screen resolution for absolute mouse.
8340Sstevel@tonic-gate */
8350Sstevel@tonic-gate req = mkiocb(MSIOSRESOLUTION);
8360Sstevel@tonic-gate if (req && ((req->b_cont =
8370Sstevel@tonic-gate allocb(sizeof (Ms_screen_resolution),
8380Sstevel@tonic-gate BPRI_MED)) == NULL)) {
8390Sstevel@tonic-gate freemsg(req);
8400Sstevel@tonic-gate req = NULL;
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate if (req) {
8430Sstevel@tonic-gate sr =
8440Sstevel@tonic-gate (Ms_screen_resolution *)req->b_cont->b_wptr;
8450Sstevel@tonic-gate *sr = consms_state.consms_ms_sr;
8460Sstevel@tonic-gate req->b_cont->b_wptr +=
8470Sstevel@tonic-gate sizeof (Ms_screen_resolution);
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate lq->lq_state++;
8500Sstevel@tonic-gate break;
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate case LQS_SET_RESOLUTION_PENDING:
8530Sstevel@tonic-gate /*
8540Sstevel@tonic-gate * All jobs are done, lq->lq_state is turned into
8550Sstevel@tonic-gate * LQS_DONE, and this lq is added into our list.
8560Sstevel@tonic-gate */
8570Sstevel@tonic-gate lq->lq_state++;
8580Sstevel@tonic-gate consms_add_lq(lq);
8590Sstevel@tonic-gate break;
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate if (lq->lq_state < LQS_DONE) {
8640Sstevel@tonic-gate lq->lq_ioc_reply_func = consms_lqs_ack_complete;
8650Sstevel@tonic-gate (void) putq(lq->lq_queue, req);
8660Sstevel@tonic-gate }
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate * Add this specific lq into our list, finally reply
8710Sstevel@tonic-gate * the previous pending I_PLINK ioctl. Also check to
8720Sstevel@tonic-gate * see if mouse capabilities have changed, and send
8730Sstevel@tonic-gate * a dynamical notification event to upper layer if
8740Sstevel@tonic-gate * necessary.
8750Sstevel@tonic-gate */
8760Sstevel@tonic-gate static void
consms_add_lq(consms_lq_t * lq)8770Sstevel@tonic-gate consms_add_lq(consms_lq_t *lq)
8780Sstevel@tonic-gate {
8790Sstevel@tonic-gate struct iocblk *iocp;
8800Sstevel@tonic-gate
8810Sstevel@tonic-gate ASSERT(MUTEX_HELD(&consmslock));
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate lq->lq_ioc_reply_func = NULL;
8840Sstevel@tonic-gate iocp = (struct iocblk *)lq->lq_pending_plink->b_rptr;
8850Sstevel@tonic-gate iocp->ioc_error = 0;
8860Sstevel@tonic-gate iocp->ioc_count = 0;
8870Sstevel@tonic-gate iocp->ioc_rval = 0;
8880Sstevel@tonic-gate lq->lq_pending_plink->b_datap->db_type = M_IOCACK;
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate /* Reply to the I_PLINK ioctl. */
8910Sstevel@tonic-gate qreply(lq->lq_pending_queue, lq->lq_pending_plink);
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate lq->lq_pending_plink = NULL;
8940Sstevel@tonic-gate lq->lq_pending_queue = NULL;
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate /*
8970Sstevel@tonic-gate * Add this lq into list.
8980Sstevel@tonic-gate */
8990Sstevel@tonic-gate consms_state.consms_num_lqs++;
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate lq->lq_next = consms_state.consms_lqs;
9020Sstevel@tonic-gate consms_state.consms_lqs = lq;
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate /*
9050Sstevel@tonic-gate * Check to see if mouse capabilities
9060Sstevel@tonic-gate * have changed.
9070Sstevel@tonic-gate */
9080Sstevel@tonic-gate consms_check_caps();
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate static void
consms_check_caps(void)9140Sstevel@tonic-gate consms_check_caps(void)
9150Sstevel@tonic-gate {
9160Sstevel@tonic-gate consms_lq_t *lq;
9170Sstevel@tonic-gate int max_buttons = 0;
9180Sstevel@tonic-gate int max_wheels = 0;
9190Sstevel@tonic-gate mblk_t *mp;
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate /*
9220Sstevel@tonic-gate * Check to see if the number of buttons
9230Sstevel@tonic-gate * and the number of wheels have changed.
9240Sstevel@tonic-gate */
9250Sstevel@tonic-gate for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
9260Sstevel@tonic-gate max_buttons = CONSMS_MAX(max_buttons, lq->lq_num_buttons);
9270Sstevel@tonic-gate max_wheels = CONSMS_MAX(max_wheels, lq->lq_num_wheels);
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate if (max_buttons != consms_state.consms_num_buttons) {
9310Sstevel@tonic-gate /*
9320Sstevel@tonic-gate * Since the number of buttons have changed,
9330Sstevel@tonic-gate * send a MOUSE_CAP_CHANGE_NUM_BUT dynamical
9340Sstevel@tonic-gate * notification event to upper layer.
9350Sstevel@tonic-gate */
9360Sstevel@tonic-gate consms_state.consms_num_buttons = max_buttons;
9370Sstevel@tonic-gate if (upperqueue != NULL) {
9380Sstevel@tonic-gate if ((mp = consms_new_firm_event(
9390Sstevel@tonic-gate MOUSE_CAP_CHANGE_NUM_BUT,
9400Sstevel@tonic-gate consms_state.consms_num_buttons)) != NULL) {
9410Sstevel@tonic-gate putnext(upperqueue, mp);
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate if (max_wheels != consms_state.consms_num_wheels) {
9470Sstevel@tonic-gate /*
9480Sstevel@tonic-gate * Since the number of wheels have changed,
9490Sstevel@tonic-gate * send a MOUSE_CAP_CHANGE_NUM_WHEEL dynamical
9500Sstevel@tonic-gate * notification event to upper layer.
9510Sstevel@tonic-gate */
9520Sstevel@tonic-gate consms_state.consms_num_wheels = max_wheels;
9530Sstevel@tonic-gate if (upperqueue != NULL) {
9540Sstevel@tonic-gate if ((mp = consms_new_firm_event(
9550Sstevel@tonic-gate MOUSE_CAP_CHANGE_NUM_WHEEL,
9560Sstevel@tonic-gate consms_state.consms_num_wheels)) != NULL) {
9570Sstevel@tonic-gate putnext(upperqueue, mp);
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate
9630Sstevel@tonic-gate /*
9640Sstevel@tonic-gate * Allocate a dynamical notification event.
9650Sstevel@tonic-gate */
9660Sstevel@tonic-gate static mblk_t *
consms_new_firm_event(ushort_t id,int value)9677187Shh224818 consms_new_firm_event(ushort_t id, int value)
9680Sstevel@tonic-gate {
9690Sstevel@tonic-gate Firm_event *fep;
9700Sstevel@tonic-gate mblk_t *tmp;
9710Sstevel@tonic-gate
9720Sstevel@tonic-gate if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
9730Sstevel@tonic-gate fep = (Firm_event *)tmp->b_wptr;
9740Sstevel@tonic-gate fep->id = id;
9750Sstevel@tonic-gate fep->pair_type = FE_PAIR_NONE;
9760Sstevel@tonic-gate fep->pair = NULL;
9770Sstevel@tonic-gate fep->value = value;
9780Sstevel@tonic-gate tmp->b_wptr += sizeof (Firm_event);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate return (tmp);
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate
9840Sstevel@tonic-gate /*
9850Sstevel@tonic-gate * Start of dispatching interfaces as a multiplexor
9860Sstevel@tonic-gate */
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate /*
9890Sstevel@tonic-gate * There is a global msg list (consms_mux_msg),
9900Sstevel@tonic-gate * which is used to link all ioctl messages from
9910Sstevel@tonic-gate * upper layer, which are currently being processed.
9920Sstevel@tonic-gate *
9930Sstevel@tonic-gate * consms_mux_link_msg links a msg into the list,
9940Sstevel@tonic-gate * consms_mux_unlink_msg unlinks a msg from the list,
9950Sstevel@tonic-gate * consms_mux_find_msg finds a msg from the list
9960Sstevel@tonic-gate * according to its unique id.
9970Sstevel@tonic-gate *
9980Sstevel@tonic-gate * The id of each msg is taken from stream's mp,
9990Sstevel@tonic-gate * so the id is supposed to be unique.
10000Sstevel@tonic-gate */
10010Sstevel@tonic-gate static void
consms_mux_link_msg(consms_msg_t * msg)10020Sstevel@tonic-gate consms_mux_link_msg(consms_msg_t *msg)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate mutex_enter(&consms_msg_lock);
10050Sstevel@tonic-gate msg->msg_next = consms_mux_msg;
10060Sstevel@tonic-gate consms_mux_msg = msg;
10070Sstevel@tonic-gate mutex_exit(&consms_msg_lock);
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate
10100Sstevel@tonic-gate static consms_msg_t *
consms_mux_unlink_msg(uint_t msg_id)10110Sstevel@tonic-gate consms_mux_unlink_msg(uint_t msg_id)
10120Sstevel@tonic-gate {
10130Sstevel@tonic-gate consms_msg_t *msg;
10140Sstevel@tonic-gate consms_msg_t *prev_msg;
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate mutex_enter(&consms_msg_lock);
10170Sstevel@tonic-gate prev_msg = NULL;
10180Sstevel@tonic-gate for (msg = consms_mux_msg; msg != NULL;
10190Sstevel@tonic-gate prev_msg = msg, msg = msg->msg_next) {
10200Sstevel@tonic-gate if (msg->msg_id == msg_id)
10210Sstevel@tonic-gate break;
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate if (msg != NULL) {
10250Sstevel@tonic-gate if (prev_msg != NULL) {
10260Sstevel@tonic-gate prev_msg->msg_next = msg->msg_next;
10270Sstevel@tonic-gate } else {
10280Sstevel@tonic-gate consms_mux_msg = consms_mux_msg->msg_next;
10290Sstevel@tonic-gate }
10300Sstevel@tonic-gate msg->msg_next = NULL;
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate mutex_exit(&consms_msg_lock);
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate return (msg);
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate static consms_msg_t *
consms_mux_find_msg(uint_t msg_id)10380Sstevel@tonic-gate consms_mux_find_msg(uint_t msg_id)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate consms_msg_t *msg;
10410Sstevel@tonic-gate
10420Sstevel@tonic-gate mutex_enter(&consms_msg_lock);
10430Sstevel@tonic-gate for (msg = consms_mux_msg; msg != NULL; msg = msg->msg_next) {
10440Sstevel@tonic-gate if (msg->msg_id == msg_id)
10450Sstevel@tonic-gate break;
10460Sstevel@tonic-gate }
10470Sstevel@tonic-gate mutex_exit(&consms_msg_lock);
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate return (msg);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate * Received ACK or NAK from lower mice
10540Sstevel@tonic-gate *
10550Sstevel@tonic-gate * For non-transparent ioctl, the msg->msg_rsp_list
10560Sstevel@tonic-gate * is always NULL; for transparent ioctl, it
10570Sstevel@tonic-gate * remembers the M_COPYIN/M_COPYOUT request
10580Sstevel@tonic-gate * messages from lower mice. So here if msg->msg_rsp_list
10590Sstevel@tonic-gate * is NULL (after receiving all ACK/NAKs), we
10600Sstevel@tonic-gate * are done with this specific ioctl.
10610Sstevel@tonic-gate *
10620Sstevel@tonic-gate * As long as one of lower mice responds success,
10630Sstevel@tonic-gate * we treat it success for a ioctl.
10640Sstevel@tonic-gate */
10650Sstevel@tonic-gate static void
consms_mux_ack(consms_msg_t * msg,mblk_t * mp)10660Sstevel@tonic-gate consms_mux_ack(consms_msg_t *msg, mblk_t *mp)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate mblk_t *ack_mp;
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate /* increment response_nums */
10710Sstevel@tonic-gate msg->msg_num_responses++;
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate if (mp->b_datap->db_type == M_IOCACK) {
10740Sstevel@tonic-gate /*
10750Sstevel@tonic-gate * Received ACK from lower, then
10760Sstevel@tonic-gate * this is the last step for both
10770Sstevel@tonic-gate * non-transparent and transparent
10780Sstevel@tonic-gate * ioctl. We only need to remember
10790Sstevel@tonic-gate * one of the ACKs, finally reply
10800Sstevel@tonic-gate * this ACK to upper layer for this
10810Sstevel@tonic-gate * specific ioctl.
10820Sstevel@tonic-gate */
10830Sstevel@tonic-gate ASSERT(msg->msg_rsp_list == NULL);
10840Sstevel@tonic-gate if (msg->msg_ack_mp == NULL) {
10850Sstevel@tonic-gate msg->msg_ack_mp = mp;
10860Sstevel@tonic-gate mp = NULL;
10870Sstevel@tonic-gate }
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate /*
10910Sstevel@tonic-gate * Check to see if all lower mice have responded
10920Sstevel@tonic-gate * to our dispatching ioctl.
10930Sstevel@tonic-gate */
10940Sstevel@tonic-gate if (msg->msg_num_responses == msg->msg_num_requests) {
10950Sstevel@tonic-gate if ((msg->msg_ack_mp == NULL) &&
10960Sstevel@tonic-gate (msg->msg_rsp_list == NULL)) {
10970Sstevel@tonic-gate /*
10980Sstevel@tonic-gate * All are NAKed.
10990Sstevel@tonic-gate */
11000Sstevel@tonic-gate ack_mp = mp;
11010Sstevel@tonic-gate mp = NULL;
11020Sstevel@tonic-gate } else if (msg->msg_rsp_list == NULL) {
11030Sstevel@tonic-gate /*
11040Sstevel@tonic-gate * The last step and at least one ACKed.
11050Sstevel@tonic-gate */
11060Sstevel@tonic-gate ack_mp = msg->msg_ack_mp;
11070Sstevel@tonic-gate consms_mux_cache_states(msg->msg_request);
11080Sstevel@tonic-gate consms_mux_max_wheel_report(ack_mp);
11090Sstevel@tonic-gate } else {
11100Sstevel@tonic-gate /*
11110Sstevel@tonic-gate * This is a NAK, but we have
11120Sstevel@tonic-gate * already received M_COPYIN
11130Sstevel@tonic-gate * or M_COPYOUT request from
11140Sstevel@tonic-gate * at least one of lower mice.
11150Sstevel@tonic-gate * (msg->msg_rsp_list != NULL)
11160Sstevel@tonic-gate *
11170Sstevel@tonic-gate * Still copyin or copyout.
11180Sstevel@tonic-gate */
11190Sstevel@tonic-gate ack_mp = msg->msg_rsp_list->rsp_mp;
11200Sstevel@tonic-gate consms_mux_max_wheel_report(ack_mp);
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate
11230Sstevel@tonic-gate qreply(msg->msg_queue, ack_mp);
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate if (msg->msg_rsp_list == NULL) {
11260Sstevel@tonic-gate /*
11270Sstevel@tonic-gate * We are done with this ioctl.
11280Sstevel@tonic-gate */
11290Sstevel@tonic-gate if (msg->msg_request)
11300Sstevel@tonic-gate freemsg(msg->msg_request);
11310Sstevel@tonic-gate (void) consms_mux_unlink_msg(msg->msg_id);
11320Sstevel@tonic-gate kmem_free(msg, sizeof (*msg));
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate if (mp) {
11370Sstevel@tonic-gate freemsg(mp);
11380Sstevel@tonic-gate }
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate /*
11420Sstevel@tonic-gate * Received M_COPYIN or M_COPYOUT request from
11430Sstevel@tonic-gate * lower mice for transparent ioctl
11440Sstevel@tonic-gate *
11450Sstevel@tonic-gate * We remember each M_COPYIN/M_COPYOUT into the
11460Sstevel@tonic-gate * msg->msg_rsp_list, reply upper layer using the first
11470Sstevel@tonic-gate * M_COPYIN/M_COPYOUT in the list after receiving
11480Sstevel@tonic-gate * all responses from lower mice, even if some of
11490Sstevel@tonic-gate * them return NAKs.
11500Sstevel@tonic-gate */
11510Sstevel@tonic-gate static void
consms_mux_copyreq(queue_t * q,consms_msg_t * msg,mblk_t * mp)11520Sstevel@tonic-gate consms_mux_copyreq(queue_t *q, consms_msg_t *msg, mblk_t *mp)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate consms_response_t *rsp;
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate rsp = (consms_response_t *)kmem_zalloc(sizeof (*rsp), KM_SLEEP);
11570Sstevel@tonic-gate rsp->rsp_mp = mp;
11580Sstevel@tonic-gate rsp->rsp_queue = q;
11590Sstevel@tonic-gate if (msg->msg_rsp_list) {
11600Sstevel@tonic-gate rsp->rsp_next = msg->msg_rsp_list;
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate msg->msg_rsp_list = rsp;
11630Sstevel@tonic-gate msg->msg_num_responses++;
11640Sstevel@tonic-gate
11650Sstevel@tonic-gate if (msg->msg_num_responses == msg->msg_num_requests) {
11660Sstevel@tonic-gate consms_mux_max_wheel_report(msg->msg_rsp_list->rsp_mp);
11670Sstevel@tonic-gate qreply(msg->msg_queue, msg->msg_rsp_list->rsp_mp);
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate * Do the real job for updating M_COPYIN/M_COPYOUT
11730Sstevel@tonic-gate * request with the mp of M_IOCDATA, then put it
11740Sstevel@tonic-gate * down to lower mice.
11750Sstevel@tonic-gate */
11760Sstevel@tonic-gate static void
consms_mux_disp_iocdata(consms_response_t * rsp,mblk_t * mp)11770Sstevel@tonic-gate consms_mux_disp_iocdata(consms_response_t *rsp, mblk_t *mp)
11780Sstevel@tonic-gate {
11790Sstevel@tonic-gate mblk_t *down_mp = rsp->rsp_mp;
11800Sstevel@tonic-gate struct copyresp *copyresp = (struct copyresp *)mp->b_rptr;
11810Sstevel@tonic-gate struct copyresp *newresp = (struct copyresp *)down_mp->b_rptr;
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate /*
11840Sstevel@tonic-gate * Update the rval.
11850Sstevel@tonic-gate */
11860Sstevel@tonic-gate newresp->cp_rval = copyresp->cp_rval;
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate /*
11890Sstevel@tonic-gate * Update the db_type to M_IOCDATA.
11900Sstevel@tonic-gate */
11910Sstevel@tonic-gate down_mp->b_datap->db_type = mp->b_datap->db_type;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /*
11940Sstevel@tonic-gate * Update the b_cont.
11950Sstevel@tonic-gate */
11960Sstevel@tonic-gate if (down_mp->b_cont != NULL) {
11970Sstevel@tonic-gate freemsg(down_mp->b_cont);
11980Sstevel@tonic-gate down_mp->b_cont = NULL;
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate if (mp->b_cont != NULL) {
12010Sstevel@tonic-gate down_mp->b_cont = copymsg(mp->b_cont);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate /*
12050Sstevel@tonic-gate * Put it down.
12060Sstevel@tonic-gate */
12070Sstevel@tonic-gate (void) putq(WR(rsp->rsp_queue), down_mp);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate
12100Sstevel@tonic-gate /*
12110Sstevel@tonic-gate * Dispatch M_IOCDATA down to all lower mice
12120Sstevel@tonic-gate * for transparent ioctl.
12130Sstevel@tonic-gate *
12140Sstevel@tonic-gate * We update each M_COPYIN/M_COPYOUT in the
12150Sstevel@tonic-gate * msg->msg_rsp_list with the M_IOCDATA.
12160Sstevel@tonic-gate */
12170Sstevel@tonic-gate static void
consms_mux_iocdata(consms_msg_t * msg,mblk_t * mp)12180Sstevel@tonic-gate consms_mux_iocdata(consms_msg_t *msg, mblk_t *mp)
12190Sstevel@tonic-gate {
12200Sstevel@tonic-gate consms_response_t *rsp;
12210Sstevel@tonic-gate consms_response_t *tmp;
12220Sstevel@tonic-gate consms_response_t *first;
12230Sstevel@tonic-gate struct copyresp *copyresp;
12240Sstevel@tonic-gate int request_nums;
12250Sstevel@tonic-gate
12260Sstevel@tonic-gate ASSERT(msg->msg_rsp_list != NULL);
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate /*
12290Sstevel@tonic-gate * We should remember the ioc data for
12300Sstevel@tonic-gate * VUIDSWHEELSTATE, and MSIOSRESOLUTION,
12310Sstevel@tonic-gate * for we will cache the wheel state and
12320Sstevel@tonic-gate * the screen resolution later if ACKed.
12330Sstevel@tonic-gate */
12340Sstevel@tonic-gate copyresp = (struct copyresp *)mp->b_rptr;
12350Sstevel@tonic-gate if ((copyresp->cp_cmd == VUIDSWHEELSTATE) ||
12360Sstevel@tonic-gate (copyresp->cp_cmd == MSIOSRESOLUTION)) {
12370Sstevel@tonic-gate freemsg(msg->msg_request);
12380Sstevel@tonic-gate msg->msg_request = copymsg(mp);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate /*
12420Sstevel@tonic-gate * Update request numbers and response numbers.
12430Sstevel@tonic-gate */
12440Sstevel@tonic-gate msg->msg_num_requests = msg->msg_num_responses;
12450Sstevel@tonic-gate msg->msg_num_responses = 0;
12460Sstevel@tonic-gate request_nums = 1;
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate * Since we have use the first M_COPYIN/M_COPYOUT
12500Sstevel@tonic-gate * in the msg_rsp_list to reply upper layer, the mp
12510Sstevel@tonic-gate * of M_IOCDATA can be directly used for that.
12520Sstevel@tonic-gate */
12530Sstevel@tonic-gate first = msg->msg_rsp_list;
12540Sstevel@tonic-gate rsp = first->rsp_next;
12550Sstevel@tonic-gate msg->msg_rsp_list = NULL;
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate for (rsp = first->rsp_next; rsp != NULL; ) {
12580Sstevel@tonic-gate tmp = rsp;
12590Sstevel@tonic-gate rsp = rsp->rsp_next;
12600Sstevel@tonic-gate consms_mux_disp_iocdata(tmp, mp);
12610Sstevel@tonic-gate kmem_free(tmp, sizeof (*tmp));
12620Sstevel@tonic-gate request_nums++;
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate /* Must set the request number before the last q. */
12660Sstevel@tonic-gate msg->msg_num_requests = request_nums;
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate /* the first one */
12690Sstevel@tonic-gate (void) putq(WR(first->rsp_queue), mp);
12700Sstevel@tonic-gate kmem_free(first, sizeof (*first));
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate
12740Sstevel@tonic-gate /*
12750Sstevel@tonic-gate * Here we update the number of wheels with
12760Sstevel@tonic-gate * the virtual mouse for VUIDGWHEELCOUNT ioctl.
12770Sstevel@tonic-gate */
12780Sstevel@tonic-gate static void
consms_mux_max_wheel_report(mblk_t * mp)12790Sstevel@tonic-gate consms_mux_max_wheel_report(mblk_t *mp)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate struct iocblk *iocp;
12820Sstevel@tonic-gate int num_wheels;
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate if (mp == NULL || mp->b_cont == NULL)
12850Sstevel@tonic-gate return;
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
12880Sstevel@tonic-gate
12890Sstevel@tonic-gate if ((iocp->ioc_cmd == VUIDGWHEELCOUNT) &&
12900Sstevel@tonic-gate (mp->b_datap->db_type == M_COPYOUT)) {
12910Sstevel@tonic-gate num_wheels = *(int *)mp->b_cont->b_rptr;
12920Sstevel@tonic-gate if (num_wheels < consms_state.consms_num_wheels) {
12930Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr =
12940Sstevel@tonic-gate consms_state.consms_num_wheels;
12950Sstevel@tonic-gate }
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate /*
13000Sstevel@tonic-gate * Update the virtual mouse state variables with
13010Sstevel@tonic-gate * the latest value from upper layer when these
13020Sstevel@tonic-gate * set ioctls return success. Thus we can update
13030Sstevel@tonic-gate * low mice with the latest state values during
13040Sstevel@tonic-gate * hotplug.
13050Sstevel@tonic-gate */
13060Sstevel@tonic-gate static void
consms_mux_cache_states(mblk_t * mp)13070Sstevel@tonic-gate consms_mux_cache_states(mblk_t *mp)
13080Sstevel@tonic-gate {
13090Sstevel@tonic-gate struct iocblk *iocp;
13100Sstevel@tonic-gate Ms_parms *parms;
13110Sstevel@tonic-gate Ms_screen_resolution *sr;
13120Sstevel@tonic-gate wheel_state *ws;
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate if (mp == NULL || mp->b_cont == NULL)
13150Sstevel@tonic-gate return;
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
13180Sstevel@tonic-gate switch (iocp->ioc_cmd) {
13190Sstevel@tonic-gate case VUIDSFORMAT:
13200Sstevel@tonic-gate consms_state.consms_vuid_format = *(int *)mp->b_cont->b_rptr;
13210Sstevel@tonic-gate break;
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate case MSIOSETPARMS:
13240Sstevel@tonic-gate parms = (Ms_parms *)mp->b_cont->b_rptr;
13250Sstevel@tonic-gate consms_state.consms_ms_parms = *parms;
13260Sstevel@tonic-gate break;
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate case MSIOSRESOLUTION:
13290Sstevel@tonic-gate sr = (Ms_screen_resolution *)mp->b_cont->b_rptr;
13300Sstevel@tonic-gate consms_state.consms_ms_sr = *sr;
13310Sstevel@tonic-gate break;
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate case VUIDSWHEELSTATE:
13340Sstevel@tonic-gate ws = (wheel_state *)mp->b_cont->b_rptr;
13350Sstevel@tonic-gate consms_state.consms_wheel_state_bf =
13360Sstevel@tonic-gate (ws->stateflags << ws->id) |
13370Sstevel@tonic-gate (consms_state.consms_wheel_state_bf & ~(1 << ws->id));
13380Sstevel@tonic-gate break;
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate /*
13430Sstevel@tonic-gate * Dispatch ioctl mp (non-transparent and transparent)
13440Sstevel@tonic-gate * down to all lower mice.
13450Sstevel@tonic-gate *
13460Sstevel@tonic-gate * First, create a pending message for this mp, link it into
13470Sstevel@tonic-gate * the global messages list. Then wait for ACK/NAK for
13480Sstevel@tonic-gate * non-transparent ioctl, COPYIN/COPYOUT for transparent
13490Sstevel@tonic-gate * ioctl.
13500Sstevel@tonic-gate */
13510Sstevel@tonic-gate static int
consms_mux_disp_ioctl(queue_t * q,mblk_t * mp)13520Sstevel@tonic-gate consms_mux_disp_ioctl(queue_t *q, mblk_t *mp)
13530Sstevel@tonic-gate {
13540Sstevel@tonic-gate struct iocblk *iocp;
13550Sstevel@tonic-gate consms_msg_t *msg;
13560Sstevel@tonic-gate consms_lq_t *lq;
13570Sstevel@tonic-gate mblk_t *copy_mp;
13580Sstevel@tonic-gate int error = 0;
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
13610Sstevel@tonic-gate msg = (consms_msg_t *)kmem_zalloc(sizeof (*msg), KM_SLEEP);
13620Sstevel@tonic-gate msg->msg_id = iocp->ioc_id;
13630Sstevel@tonic-gate msg->msg_request = mp;
13640Sstevel@tonic-gate msg->msg_queue = q;
13650Sstevel@tonic-gate msg->msg_num_requests = consms_state.consms_num_lqs;
13660Sstevel@tonic-gate consms_mux_link_msg(msg);
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
13690Sstevel@tonic-gate if ((copy_mp = copymsg(mp)) != NULL) {
13700Sstevel@tonic-gate (void) putq(lq->lq_queue, copy_mp);
13710Sstevel@tonic-gate } else {
13720Sstevel@tonic-gate /*
13730Sstevel@tonic-gate * If copymsg fails, we ignore this lq and
13740Sstevel@tonic-gate * try next one. As long as one of them succeeds,
13750Sstevel@tonic-gate * we dispatch this ioctl down. And later as long
13760Sstevel@tonic-gate * as one of the lower drivers return success, we
13770Sstevel@tonic-gate * reply to this ioctl with success.
13780Sstevel@tonic-gate */
13790Sstevel@tonic-gate msg->msg_num_requests--;
13800Sstevel@tonic-gate }
13810Sstevel@tonic-gate }
13820Sstevel@tonic-gate
13830Sstevel@tonic-gate if (msg->msg_num_requests <= 0) {
13840Sstevel@tonic-gate /*
13850Sstevel@tonic-gate * Since copymsg fails for all lqs, we NAK this ioctl.
13860Sstevel@tonic-gate */
13870Sstevel@tonic-gate (void) consms_mux_unlink_msg(msg->msg_id);
13880Sstevel@tonic-gate kmem_free(msg, sizeof (*msg));
13890Sstevel@tonic-gate error = ENOMEM;
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate return (error);
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate
13950Sstevel@tonic-gate /*
13960Sstevel@tonic-gate * Dispatch M_DATA and M_FLUSH message down to all
13970Sstevel@tonic-gate * lower mice, and there are no acknowledgements
13980Sstevel@tonic-gate * for them. Here we just copy the mp and then
13990Sstevel@tonic-gate * put it into the lower queues.
14000Sstevel@tonic-gate */
14010Sstevel@tonic-gate static void
consms_mux_disp_data(mblk_t * mp)14020Sstevel@tonic-gate consms_mux_disp_data(mblk_t *mp)
14030Sstevel@tonic-gate {
14040Sstevel@tonic-gate consms_lq_t *lq;
14050Sstevel@tonic-gate mblk_t *copy_mp;
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
14080Sstevel@tonic-gate if ((copy_mp = copymsg(mp)) != NULL) {
14090Sstevel@tonic-gate (void) putq(lq->lq_queue, copy_mp);
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate }
14120Sstevel@tonic-gate
14130Sstevel@tonic-gate freemsg(mp);
14140Sstevel@tonic-gate }
1415