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 /* 22*7187Shh224818 * 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 #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Console mouse driver for Sun. 300Sstevel@tonic-gate * The console "zs" port is linked under us, with the "ms" module pushed 310Sstevel@tonic-gate * on top of it. 320Sstevel@tonic-gate * 330Sstevel@tonic-gate * This device merely provides a way to have "/dev/mouse" automatically 340Sstevel@tonic-gate * have the "ms" module present. Due to problems with the way the "specfs" 350Sstevel@tonic-gate * file system works, you can't use an indirect device (a "stat" on 360Sstevel@tonic-gate * "/dev/mouse" won't get the right snode, so you won't get the right time 370Sstevel@tonic-gate * of last access), and due to problems with the kernel window system code, 380Sstevel@tonic-gate * you can't use a "cons"-like driver ("/dev/mouse" won't be a streams device, 390Sstevel@tonic-gate * even though operations on it get turned into operations on the real stream). 400Sstevel@tonic-gate * 410Sstevel@tonic-gate * This module supports multiple mice connected to the system at the same time. 420Sstevel@tonic-gate * All the mice are linked under consms, and act as a mouse with replicated 430Sstevel@tonic-gate * clicks. Only USB and PS/2 mouse are supported to be virtual mouse now. 440Sstevel@tonic-gate */ 450Sstevel@tonic-gate 460Sstevel@tonic-gate #include <sys/types.h> 470Sstevel@tonic-gate #include <sys/param.h> 480Sstevel@tonic-gate #include <sys/stropts.h> 490Sstevel@tonic-gate #include <sys/stream.h> 500Sstevel@tonic-gate #include <sys/strsun.h> 510Sstevel@tonic-gate #include <sys/conf.h> 520Sstevel@tonic-gate #include <sys/stat.h> 530Sstevel@tonic-gate #include <sys/errno.h> 540Sstevel@tonic-gate #include <sys/modctl.h> 550Sstevel@tonic-gate #include <sys/consdev.h> 560Sstevel@tonic-gate #include <sys/ddi.h> 570Sstevel@tonic-gate #include <sys/sunddi.h> 580Sstevel@tonic-gate #include <sys/kstat.h> 590Sstevel@tonic-gate #include <sys/vuid_wheel.h> 600Sstevel@tonic-gate #include <sys/msio.h> 610Sstevel@tonic-gate #include <sys/consms.h> 620Sstevel@tonic-gate 630Sstevel@tonic-gate static void consms_plink(queue_t *, mblk_t *); 640Sstevel@tonic-gate static int consms_punlink(queue_t *, mblk_t *); 650Sstevel@tonic-gate static void 660Sstevel@tonic-gate consms_lqs_ack_complete(consms_lq_t *, mblk_t *); 670Sstevel@tonic-gate static void consms_add_lq(consms_lq_t *); 680Sstevel@tonic-gate static void consms_check_caps(void); 69*7187Shh224818 static mblk_t *consms_new_firm_event(ushort_t, int); 700Sstevel@tonic-gate 710Sstevel@tonic-gate static void consms_mux_max_wheel_report(mblk_t *); 720Sstevel@tonic-gate static void consms_mux_cache_states(mblk_t *); 730Sstevel@tonic-gate static void consms_mux_link_msg(consms_msg_t *); 740Sstevel@tonic-gate static consms_msg_t *consms_mux_unlink_msg(uint_t); 750Sstevel@tonic-gate static consms_msg_t *consms_mux_find_msg(uint_t); 760Sstevel@tonic-gate 770Sstevel@tonic-gate static void consms_mux_iocdata(consms_msg_t *, mblk_t *); 780Sstevel@tonic-gate static void consms_mux_disp_iocdata(consms_response_t *, mblk_t *); 790Sstevel@tonic-gate static int consms_mux_disp_ioctl(queue_t *, mblk_t *); 800Sstevel@tonic-gate static void consms_mux_copyreq(queue_t *, consms_msg_t *, mblk_t *); 810Sstevel@tonic-gate static void consms_mux_ack(consms_msg_t *, mblk_t *); 820Sstevel@tonic-gate static void consms_mux_disp_data(mblk_t *); 830Sstevel@tonic-gate 840Sstevel@tonic-gate 850Sstevel@tonic-gate static int consmsopen(); 860Sstevel@tonic-gate static int consmsclose(); 870Sstevel@tonic-gate static void consmsuwput(); 880Sstevel@tonic-gate static void consmslrput(); 890Sstevel@tonic-gate static void consmslwserv(); 900Sstevel@tonic-gate 910Sstevel@tonic-gate static struct module_info consmsm_info = { 920Sstevel@tonic-gate 0, 930Sstevel@tonic-gate "consms", 940Sstevel@tonic-gate 0, 950Sstevel@tonic-gate 1024, 960Sstevel@tonic-gate 2048, 970Sstevel@tonic-gate 128 980Sstevel@tonic-gate }; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate static struct qinit consmsurinit = { 1010Sstevel@tonic-gate putq, 1020Sstevel@tonic-gate (int (*)())NULL, 1030Sstevel@tonic-gate consmsopen, 1040Sstevel@tonic-gate consmsclose, 1050Sstevel@tonic-gate (int (*)())NULL, 1060Sstevel@tonic-gate &consmsm_info, 1070Sstevel@tonic-gate NULL 1080Sstevel@tonic-gate }; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate static struct qinit consmsuwinit = { 1110Sstevel@tonic-gate (int (*)())consmsuwput, 1120Sstevel@tonic-gate (int (*)())NULL, 1130Sstevel@tonic-gate consmsopen, 1140Sstevel@tonic-gate consmsclose, 1150Sstevel@tonic-gate (int (*)())NULL, 1160Sstevel@tonic-gate &consmsm_info, 1170Sstevel@tonic-gate NULL 1180Sstevel@tonic-gate }; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate static struct qinit consmslrinit = { 1210Sstevel@tonic-gate (int (*)())consmslrput, 1220Sstevel@tonic-gate (int (*)())NULL, 1230Sstevel@tonic-gate (int (*)())NULL, 1240Sstevel@tonic-gate (int (*)())NULL, 1250Sstevel@tonic-gate (int (*)())NULL, 1260Sstevel@tonic-gate &consmsm_info, 1270Sstevel@tonic-gate NULL 1280Sstevel@tonic-gate }; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate static struct qinit consmslwinit = { 1310Sstevel@tonic-gate putq, 1320Sstevel@tonic-gate (int (*)())consmslwserv, 1330Sstevel@tonic-gate (int (*)())NULL, 1340Sstevel@tonic-gate (int (*)())NULL, 1350Sstevel@tonic-gate (int (*)())NULL, 1360Sstevel@tonic-gate &consmsm_info, 1370Sstevel@tonic-gate NULL 1380Sstevel@tonic-gate }; 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate static struct streamtab consms_str_info = { 1410Sstevel@tonic-gate &consmsurinit, 1420Sstevel@tonic-gate &consmsuwinit, 1430Sstevel@tonic-gate &consmslrinit, 1440Sstevel@tonic-gate &consmslwinit, 1450Sstevel@tonic-gate }; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate static void consmsioctl(queue_t *q, mblk_t *mp); 1480Sstevel@tonic-gate static int consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1490Sstevel@tonic-gate void **result); 1500Sstevel@tonic-gate static int consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1510Sstevel@tonic-gate static int consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 1520Sstevel@tonic-gate static int consms_kstat_update(kstat_t *, int); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* 1550Sstevel@tonic-gate * Module global data are protected by the per-module inner perimeter. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate static queue_t *upperqueue; /* regular mouse queue above us */ 1580Sstevel@tonic-gate static dev_info_t *consms_dip; /* private copy of devinfo pointer */ 1590Sstevel@tonic-gate static long consms_idle_stamp; /* seconds tstamp of latest mouse op */ 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate static consms_msg_t *consms_mux_msg; /* ioctl messages being processed */ 1620Sstevel@tonic-gate static kmutex_t consms_msg_lock; /* protect ioctl messages list */ 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate static consms_state_t consms_state; /* the global virtual mouse state */ 1650Sstevel@tonic-gate static kmutex_t consmslock; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate /* 1690Sstevel@tonic-gate * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements. In 1700Sstevel@tonic-gate * this case we use this type for a single element because the ioctl code 1710Sstevel@tonic-gate * for it knows how to handle mixed kernel/user data models. Also, it 1720Sstevel@tonic-gate * will be easier to add new statistics later. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate static struct { 1750Sstevel@tonic-gate kstat_named_t idle_sec; /* seconds since last user op */ 1760Sstevel@tonic-gate } consms_kstat = { 1770Sstevel@tonic-gate { "idle_sec", KSTAT_DATA_LONG, } 1780Sstevel@tonic-gate }; 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate static struct cb_ops cb_consms_ops = { 1820Sstevel@tonic-gate nulldev, /* cb_open */ 1830Sstevel@tonic-gate nulldev, /* cb_close */ 1840Sstevel@tonic-gate nodev, /* cb_strategy */ 1850Sstevel@tonic-gate nodev, /* cb_print */ 1860Sstevel@tonic-gate nodev, /* cb_dump */ 1870Sstevel@tonic-gate nodev, /* cb_read */ 1880Sstevel@tonic-gate nodev, /* cb_write */ 1890Sstevel@tonic-gate nodev, /* cb_ioctl */ 1900Sstevel@tonic-gate nodev, /* cb_devmap */ 1910Sstevel@tonic-gate nodev, /* cb_mmap */ 1920Sstevel@tonic-gate nodev, /* cb_segmap */ 1930Sstevel@tonic-gate nochpoll, /* cb_chpoll */ 1940Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1950Sstevel@tonic-gate &consms_str_info, /* cb_stream */ 1960Sstevel@tonic-gate D_MP | D_MTPERMOD /* cb_flag */ 1970Sstevel@tonic-gate }; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate static struct dev_ops consms_ops = { 2000Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 2010Sstevel@tonic-gate 0, /* devo_refcnt */ 2020Sstevel@tonic-gate consms_info, /* devo_getinfo */ 2030Sstevel@tonic-gate nulldev, /* devo_identify */ 2040Sstevel@tonic-gate nulldev, /* devo_probe */ 2050Sstevel@tonic-gate consms_attach, /* devo_attach */ 2060Sstevel@tonic-gate consms_detach, /* devo_detach */ 2070Sstevel@tonic-gate nodev, /* devo_reset */ 2080Sstevel@tonic-gate &(cb_consms_ops), /* devo_cb_ops */ 2090Sstevel@tonic-gate (struct bus_ops *)NULL, /* devo_bus_ops */ 2100Sstevel@tonic-gate NULL /* devo_power */ 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 */ 2200Sstevel@tonic-gate "Mouse Driver for Sun 'consms' %I%", 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 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 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 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 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, 277*7187Shh224818 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 967*7187Shh224818 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 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 * 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 * 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 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 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 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 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 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 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 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 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