4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * Console mouse driver for Sun.
29 * The console "zs" port is linked under us, with the "ms" module pushed
32 * This device merely provides a way to have "/dev/mouse" automatically
33 * have the "ms" module present. Due to problems with the way the "specfs"
34 * file system works, you can't use an indirect device (a "stat" on
35 * "/dev/mouse" won't get the right snode, so you won't get the right time
36 * of last access), and due to problems with the kernel window system code,
37 * you can't use a "cons"-like driver ("/dev/mouse" won't be a streams device,
38 * even though operations on it get turned into operations on the real stream).
40 * This module supports multiple mice connected to the system at the same time.
41 * All the mice are linked under consms, and act as a mouse with replicated
42 * clicks. Only USB and PS/2 mouse are supported to be virtual mouse now.
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/stropts.h>
48 #include <sys/stream.h>
49 #include <sys/strsun.h>
52 #include <sys/errno.h>
53 #include <sys/modctl.h>
54 #include <sys/consdev.h>
56 #include <sys/sunddi.h>
57 #include <sys/kstat.h>
58 #include <sys/vuid_wheel.h>
60 #include <sys/consms.h>
62 static void consms_plink(queue_t
*, mblk_t
*);
63 static int consms_punlink(queue_t
*, mblk_t
*);
65 consms_lqs_ack_complete(consms_lq_t
*, mblk_t
*);
66 static void consms_add_lq(consms_lq_t
*);
67 static void consms_check_caps(void);
68 static mblk_t
*consms_new_firm_event(ushort_t
, int);
70 static void consms_mux_max_wheel_report(mblk_t
*);
71 static void consms_mux_cache_states(mblk_t
*);
72 static void consms_mux_link_msg(consms_msg_t
*);
73 static consms_msg_t
*consms_mux_unlink_msg(uint_t
);
74 static consms_msg_t
*consms_mux_find_msg(uint_t
);
76 static void consms_mux_iocdata(consms_msg_t
*, mblk_t
*);
77 static void consms_mux_disp_iocdata(consms_response_t
*, mblk_t
*);
78 static int consms_mux_disp_ioctl(queue_t
*, mblk_t
*);
79 static void consms_mux_copyreq(queue_t
*, consms_msg_t
*, mblk_t
*);
80 static void consms_mux_ack(consms_msg_t
*, mblk_t
*);
81 static void consms_mux_disp_data(mblk_t
*);
84 static int consmsopen();
85 static int consmsclose();
86 static void consmsuwput();
87 static void consmslrput();
88 static void consmslwserv();
90 static struct module_info consmsm_info
= {
99 static struct qinit consmsurinit
= {
109 static struct qinit consmsuwinit
= {
110 (int (*)())consmsuwput
,
119 static struct qinit consmslrinit
= {
120 (int (*)())consmslrput
,
129 static struct qinit consmslwinit
= {
131 (int (*)())consmslwserv
,
139 static struct streamtab consms_str_info
= {
146 static void consmsioctl(queue_t
*q
, mblk_t
*mp
);
147 static int consms_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
149 static int consms_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
);
150 static int consms_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
);
151 static int consms_kstat_update(kstat_t
*, int);
154 * Module global data are protected by the per-module inner perimeter.
156 static queue_t
*upperqueue
; /* regular mouse queue above us */
157 static dev_info_t
*consms_dip
; /* private copy of devinfo pointer */
158 static long consms_idle_stamp
; /* seconds tstamp of latest mouse op */
160 static consms_msg_t
*consms_mux_msg
; /* ioctl messages being processed */
161 static kmutex_t consms_msg_lock
; /* protect ioctl messages list */
163 static consms_state_t consms_state
; /* the global virtual mouse state */
164 static kmutex_t consmslock
;
168 * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements. In
169 * this case we use this type for a single element because the ioctl code
170 * for it knows how to handle mixed kernel/user data models. Also, it
171 * will be easier to add new statistics later.
174 kstat_named_t idle_sec
; /* seconds since last user op */
176 { "idle_sec", KSTAT_DATA_LONG
, }
180 static struct cb_ops cb_consms_ops
= {
181 nulldev
, /* cb_open */
182 nulldev
, /* cb_close */
183 nodev
, /* cb_strategy */
184 nodev
, /* cb_print */
187 nodev
, /* cb_write */
188 nodev
, /* cb_ioctl */
189 nodev
, /* cb_devmap */
191 nodev
, /* cb_segmap */
192 nochpoll
, /* cb_chpoll */
193 ddi_prop_op
, /* cb_prop_op */
194 &consms_str_info
, /* cb_stream */
195 D_MP
| D_MTPERMOD
/* cb_flag */
198 static struct dev_ops consms_ops
= {
199 DEVO_REV
, /* devo_rev */
201 consms_info
, /* devo_getinfo */
202 nulldev
, /* devo_identify */
203 nulldev
, /* devo_probe */
204 consms_attach
, /* devo_attach */
205 consms_detach
, /* devo_detach */
206 nodev
, /* devo_reset */
207 &(cb_consms_ops
), /* devo_cb_ops */
208 (struct bus_ops
*)NULL
, /* devo_bus_ops */
209 NULL
, /* devo_power */
210 ddi_quiesce_not_needed
, /* devo_quiesce */
215 * Module linkage information for the kernel.
218 static struct modldrv modldrv
= {
219 &mod_driverops
, /* Type of module. This one is a pseudo driver */
220 "Mouse Driver for Sun 'consms' 5.57",
221 &consms_ops
, /* driver ops */
224 static struct modlinkage modlinkage
= {
235 mutex_init(&consmslock
, NULL
, MUTEX_DRIVER
, NULL
);
236 mutex_init(&consms_msg_lock
, NULL
, MUTEX_DRIVER
, NULL
);
237 error
= mod_install(&modlinkage
);
239 mutex_destroy(&consmslock
);
240 mutex_destroy(&consms_msg_lock
);
250 error
= mod_remove(&modlinkage
);
253 mutex_destroy(&consmslock
);
254 mutex_destroy(&consms_msg_lock
);
259 _info(struct modinfo
*modinfop
)
261 return (mod_info(&modlinkage
, modinfop
));
265 consms_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
273 return (DDI_FAILURE
);
276 if (ddi_create_minor_node(devi
, "mouse", S_IFCHR
,
277 0, DDI_PSEUDO
, NULL
) == DDI_FAILURE
) {
278 ddi_remove_minor_node(devi
, NULL
);
282 (void) ddi_prop_update_int(DDI_DEV_T_NONE
, devi
, DDI_NO_AUTODETACH
, 1);
284 ksp
= kstat_create("consms", 0, "activity", "misc", KSTAT_TYPE_NAMED
,
285 sizeof (consms_kstat
) / sizeof (kstat_named_t
), KSTAT_FLAG_VIRTUAL
);
287 ksp
->ks_data
= (void *)&consms_kstat
;
288 ksp
->ks_update
= consms_kstat_update
;
290 consms_idle_stamp
= gethrestime_sec(); /* initial value */
293 consms_state
.consms_lqs
= NULL
;
294 consms_state
.consms_num_lqs
= 0;
296 /* default consms state values */
297 consms_state
.consms_vuid_format
= VUID_FIRM_EVENT
;
298 consms_state
.consms_num_buttons
= 0;
299 consms_state
.consms_num_wheels
= 0;
300 consms_state
.consms_wheel_state_bf
|= VUID_WHEEL_STATE_ENABLED
;
301 consms_state
.consms_ms_parms
.jitter_thresh
=
302 CONSMS_PARMS_DEFAULT_JITTER
;
303 consms_state
.consms_ms_parms
.speed_limit
=
304 CONSMS_PARMS_DEFAULT_SPEED_LIMIT
;
305 consms_state
.consms_ms_parms
.speed_law
=
306 CONSMS_PARMS_DEFAULT_SPEED_LAW
;
307 consms_state
.consms_ms_sr
.height
= CONSMS_SR_DEFAULT_HEIGHT
;
308 consms_state
.consms_ms_sr
.width
= CONSMS_SR_DEFAULT_WIDTH
;
310 return (DDI_SUCCESS
);
315 consms_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
320 return (DDI_FAILURE
);
326 consms_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
332 case DDI_INFO_DEVT2DEVINFO
:
333 if (consms_dip
== NULL
) {
336 *result
= (void *) consms_dip
;
340 case DDI_INFO_DEVT2INSTANCE
:
353 consmsopen(q
, devp
, flag
, sflag
, crp
)
366 consmsclose(q
, flag
, crp
)
377 * Put procedure for upper write queue.
384 struct iocblk
*iocbp
= (struct iocblk
*)mp
->b_rptr
;
388 switch (mp
->b_datap
->db_type
) {
395 if (*mp
->b_rptr
& FLUSHW
)
396 flushq(q
, FLUSHDATA
);
397 if (*mp
->b_rptr
& FLUSHR
)
398 flushq(RD(q
), FLUSHDATA
);
399 if (consms_state
.consms_num_lqs
> 0) {
400 consms_mux_disp_data(mp
);
403 * No lower queue; just reflect this back upstream.
405 *mp
->b_rptr
&= ~FLUSHW
;
406 if (*mp
->b_rptr
& FLUSHR
)
414 if (consms_state
.consms_num_lqs
> 0) {
415 consms_mux_disp_data(mp
);
422 if ((msg
= consms_mux_find_msg(iocbp
->ioc_id
)) != NULL
) {
423 consms_mux_iocdata(msg
, mp
);
436 * Pass an error message up.
438 mp
->b_datap
->db_type
= M_ERROR
;
443 mp
->b_rptr
= mp
->b_datap
->db_base
;
444 mp
->b_wptr
= mp
->b_rptr
+ sizeof (char);
445 *mp
->b_rptr
= (char)error
;
455 register struct iocblk
*iocp
;
459 iocp
= (struct iocblk
*)mp
->b_rptr
;
461 switch (iocp
->ioc_cmd
) {
465 mutex_enter(&consmslock
);
467 mutex_exit(&consmslock
);
472 mutex_enter(&consmslock
);
473 if ((error
= consms_punlink(q
, mp
)) != 0) {
474 mutex_exit(&consmslock
);
475 miocnak(q
, mp
, 0, error
);
478 mutex_exit(&consmslock
);
482 case MSIOBUTTONS
: /* query the number of buttons */
483 if ((consms_state
.consms_num_lqs
<= 0) ||
484 ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)) {
485 miocnak(q
, mp
, 0, ENOMEM
);
488 *(int *)datap
->b_wptr
= consms_state
.consms_num_buttons
;
489 datap
->b_wptr
+= sizeof (int);
494 iocp
->ioc_count
= sizeof (int);
499 * Pass this through, if there's something to pass it
500 * through to; otherwise, reject it.
502 if (consms_state
.consms_num_lqs
<= 0) {
503 miocnak(q
, mp
, 0, EINVAL
);
506 if ((error
= consms_mux_disp_ioctl(q
, mp
)) != 0)
507 miocnak(q
, mp
, 0, error
);
513 * Common exit path for calls that return a positive
514 * acknowledgment with a return value of 0.
516 miocack(q
, mp
, iocp
->ioc_count
, 0);
520 * Service procedure for lower write queue.
521 * Puts things on the queue below us, if it lets us.
529 while (canput(q
->q_next
) && (mp
= getq(q
)) != NULL
)
534 * Put procedure for lower read queue.
541 struct iocblk
*iocbp
= (struct iocblk
*)mp
->b_rptr
;
542 struct copyreq
*copyreq
= (struct copyreq
*)mp
->b_rptr
;
544 consms_lq_t
*lq
= (consms_lq_t
*)q
->q_ptr
;
548 switch (mp
->b_datap
->db_type
) {
550 if (*mp
->b_rptr
& FLUSHW
)
551 flushq(WR(q
), FLUSHDATA
);
552 if (*mp
->b_rptr
& FLUSHR
)
553 flushq(q
, FLUSHDATA
);
554 if (upperqueue
!= NULL
)
555 putnext(upperqueue
, mp
); /* pass it through */
558 * No upper queue; just reflect this back downstream.
560 *mp
->b_rptr
&= ~FLUSHR
;
561 if (*mp
->b_rptr
& FLUSHW
)
569 if (upperqueue
!= NULL
)
570 putnext(upperqueue
, mp
);
573 consms_idle_stamp
= gethrestime_sec();
579 * First, check to see if this device
580 * is still being initialized.
582 if (lq
->lq_ioc_reply_func
!= NULL
) {
583 mutex_enter(&consmslock
);
584 lq
->lq_ioc_reply_func(lq
, mp
);
585 mutex_exit(&consmslock
);
591 * This is normal ioctl ack for upper layer.
593 if ((msg
= consms_mux_find_msg(iocbp
->ioc_id
)) != NULL
) {
594 consms_mux_ack(msg
, mp
);
598 consms_idle_stamp
= gethrestime_sec();
603 if ((msg
= consms_mux_find_msg(copyreq
->cq_id
)) != NULL
) {
604 consms_mux_copyreq(q
, msg
, mp
);
607 consms_idle_stamp
= gethrestime_sec();
613 freemsg(mp
); /* anything useful here? */
620 consms_kstat_update(kstat_t
*ksp
, int rw
)
622 if (rw
== KSTAT_WRITE
)
625 consms_kstat
.idle_sec
.value
.l
= gethrestime_sec() - consms_idle_stamp
;
631 consms_punlink(queue_t
*q
, mblk_t
*mp
)
633 struct linkblk
*linkp
;
635 consms_lq_t
*prev_lq
;
637 ASSERT(MUTEX_HELD(&consmslock
));
639 linkp
= (struct linkblk
*)mp
->b_cont
->b_rptr
;
642 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
643 if (lq
->lq_queue
== linkp
->l_qbot
) {
645 prev_lq
->lq_next
= lq
->lq_next
;
647 consms_state
.consms_lqs
= lq
->lq_next
;
648 kmem_free(lq
, sizeof (*lq
));
649 consms_state
.consms_num_lqs
--;
652 * Check to see if mouse capabilities
666 * Link a specific mouse into our mouse list.
669 consms_plink(queue_t
*q
, mblk_t
*mp
)
671 struct linkblk
*linkp
;
675 ASSERT(MUTEX_HELD(&consmslock
));
677 linkp
= (struct linkblk
*)mp
->b_cont
->b_rptr
;
678 lowq
= linkp
->l_qbot
;
680 lq
= kmem_zalloc(sizeof (*lq
), KM_SLEEP
);
682 lowq
->q_ptr
= (void *)lq
;
683 OTHERQ(lowq
)->q_ptr
= (void *)lq
;
685 lq
->lq_pending_plink
= mp
;
686 lq
->lq_pending_queue
= q
;
689 * Set the number of buttons to 3 by default
690 * in case the following MSIOBUTTONS ioctl fails.
692 lq
->lq_num_buttons
= 3;
695 * Begin to initialize this mouse.
697 lq
->lq_state
= LQS_START
;
698 consms_lqs_ack_complete(lq
, NULL
);
702 * Initialize the newly hotplugged-in mouse,
703 * e.g. get the number of buttons, set event
704 * format. Then we add it into our list.
707 consms_lqs_ack_complete(consms_lq_t
*lq
, mblk_t
*mp
)
710 boolean_t skipped
= B_FALSE
;
712 Ms_screen_resolution
*sr
;
715 ASSERT(MUTEX_HELD(&consmslock
));
718 * We try each ioctl even if the previous one fails
719 * until we reach LQS_DONE, and then add this lq
722 * If the message allocation fails, we skip this ioctl,
723 * set skipped flag to B_TRUE in order to skip the ioctl
724 * result, then we try next ioctl, go to next state.
726 while ((lq
->lq_state
< LQS_DONE
) && (req
== NULL
)) {
727 switch (lq
->lq_state
) {
730 * First, issue MSIOBUTTONS ioctl
731 * to get the number of buttons.
733 req
= mkiocb(MSIOBUTTONS
);
734 if (req
&& ((req
->b_cont
= allocb(sizeof (int),
735 BPRI_MED
)) == NULL
)) {
744 case LQS_BUTTON_COUNT_PENDING
:
745 if (!skipped
&& mp
&& mp
->b_cont
&&
746 (mp
->b_datap
->db_type
== M_IOCACK
))
748 *(int *)mp
->b_cont
->b_rptr
;
751 * Second, issue VUIDGWHEELCOUNT ioctl
752 * to get the count of wheels.
754 req
= mkiocb(VUIDGWHEELCOUNT
);
755 if (req
&& ((req
->b_cont
= allocb(sizeof (int),
756 BPRI_MED
)) == NULL
)) {
765 case LQS_WHEEL_COUNT_PENDING
:
766 if (!skipped
&& mp
&& mp
->b_cont
&&
767 (mp
->b_datap
->db_type
== M_IOCACK
))
769 *(int *)mp
->b_cont
->b_rptr
;
772 * Third, issue VUIDSFORMAT ioctl
773 * to set the event format.
775 req
= mkiocb(VUIDSFORMAT
);
776 if (req
&& ((req
->b_cont
= allocb(sizeof (int),
777 BPRI_MED
)) == NULL
)) {
782 *(int *)req
->b_cont
->b_wptr
=
783 consms_state
.consms_vuid_format
;
784 req
->b_cont
->b_wptr
+= sizeof (int);
789 case LQS_SET_VUID_FORMAT_PENDING
:
791 * Fourth, issue VUIDSWHEELSTATE ioctl
792 * to set the wheel state (enable or disable).
794 req
= mkiocb(VUIDSWHEELSTATE
);
795 if (req
&& ((req
->b_cont
= allocb(sizeof (wheel_state
),
796 BPRI_MED
)) == NULL
)) {
801 ws
= (wheel_state
*)req
->b_cont
->b_wptr
;
802 ws
->vers
= VUID_WHEEL_STATE_VERS
;
803 ws
->id
= 0; /* the first wheel */
805 consms_state
.consms_wheel_state_bf
& 1;
806 req
->b_cont
->b_wptr
+= sizeof (wheel_state
);
811 case LQS_SET_WHEEL_STATE_PENDING
:
813 * Fifth, issue MSIOSETPARMS ioctl
814 * to set the parameters for USB mouse.
816 req
= mkiocb(MSIOSETPARMS
);
817 if (req
&& ((req
->b_cont
= allocb(sizeof (Ms_parms
),
818 BPRI_MED
)) == NULL
)) {
823 params
= (Ms_parms
*)req
->b_cont
->b_wptr
;
824 *params
= consms_state
.consms_ms_parms
;
825 req
->b_cont
->b_wptr
+= sizeof (Ms_parms
);
830 case LQS_SET_PARMS_PENDING
:
832 * Sixth, issue MSIOSRESOLUTION ioctl
833 * to set the screen resolution for absolute mouse.
835 req
= mkiocb(MSIOSRESOLUTION
);
836 if (req
&& ((req
->b_cont
=
837 allocb(sizeof (Ms_screen_resolution
),
838 BPRI_MED
)) == NULL
)) {
844 (Ms_screen_resolution
*)req
->b_cont
->b_wptr
;
845 *sr
= consms_state
.consms_ms_sr
;
846 req
->b_cont
->b_wptr
+=
847 sizeof (Ms_screen_resolution
);
852 case LQS_SET_RESOLUTION_PENDING
:
854 * All jobs are done, lq->lq_state is turned into
855 * LQS_DONE, and this lq is added into our list.
863 if (lq
->lq_state
< LQS_DONE
) {
864 lq
->lq_ioc_reply_func
= consms_lqs_ack_complete
;
865 (void) putq(lq
->lq_queue
, req
);
870 * Add this specific lq into our list, finally reply
871 * the previous pending I_PLINK ioctl. Also check to
872 * see if mouse capabilities have changed, and send
873 * a dynamical notification event to upper layer if
877 consms_add_lq(consms_lq_t
*lq
)
881 ASSERT(MUTEX_HELD(&consmslock
));
883 lq
->lq_ioc_reply_func
= NULL
;
884 iocp
= (struct iocblk
*)lq
->lq_pending_plink
->b_rptr
;
888 lq
->lq_pending_plink
->b_datap
->db_type
= M_IOCACK
;
890 /* Reply to the I_PLINK ioctl. */
891 qreply(lq
->lq_pending_queue
, lq
->lq_pending_plink
);
893 lq
->lq_pending_plink
= NULL
;
894 lq
->lq_pending_queue
= NULL
;
897 * Add this lq into list.
899 consms_state
.consms_num_lqs
++;
901 lq
->lq_next
= consms_state
.consms_lqs
;
902 consms_state
.consms_lqs
= lq
;
905 * Check to see if mouse capabilities
914 consms_check_caps(void)
922 * Check to see if the number of buttons
923 * and the number of wheels have changed.
925 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
926 max_buttons
= CONSMS_MAX(max_buttons
, lq
->lq_num_buttons
);
927 max_wheels
= CONSMS_MAX(max_wheels
, lq
->lq_num_wheels
);
930 if (max_buttons
!= consms_state
.consms_num_buttons
) {
932 * Since the number of buttons have changed,
933 * send a MOUSE_CAP_CHANGE_NUM_BUT dynamical
934 * notification event to upper layer.
936 consms_state
.consms_num_buttons
= max_buttons
;
937 if (upperqueue
!= NULL
) {
938 if ((mp
= consms_new_firm_event(
939 MOUSE_CAP_CHANGE_NUM_BUT
,
940 consms_state
.consms_num_buttons
)) != NULL
) {
941 putnext(upperqueue
, mp
);
946 if (max_wheels
!= consms_state
.consms_num_wheels
) {
948 * Since the number of wheels have changed,
949 * send a MOUSE_CAP_CHANGE_NUM_WHEEL dynamical
950 * notification event to upper layer.
952 consms_state
.consms_num_wheels
= max_wheels
;
953 if (upperqueue
!= NULL
) {
954 if ((mp
= consms_new_firm_event(
955 MOUSE_CAP_CHANGE_NUM_WHEEL
,
956 consms_state
.consms_num_wheels
)) != NULL
) {
957 putnext(upperqueue
, mp
);
964 * Allocate a dynamical notification event.
967 consms_new_firm_event(ushort_t id
, int value
)
972 if ((tmp
= allocb(sizeof (Firm_event
), BPRI_HI
)) != NULL
) {
973 fep
= (Firm_event
*)tmp
->b_wptr
;
975 fep
->pair_type
= FE_PAIR_NONE
;
978 tmp
->b_wptr
+= sizeof (Firm_event
);
985 * Start of dispatching interfaces as a multiplexor
989 * There is a global msg list (consms_mux_msg),
990 * which is used to link all ioctl messages from
991 * upper layer, which are currently being processed.
993 * consms_mux_link_msg links a msg into the list,
994 * consms_mux_unlink_msg unlinks a msg from the list,
995 * consms_mux_find_msg finds a msg from the list
996 * according to its unique id.
998 * The id of each msg is taken from stream's mp,
999 * so the id is supposed to be unique.
1002 consms_mux_link_msg(consms_msg_t
*msg
)
1004 mutex_enter(&consms_msg_lock
);
1005 msg
->msg_next
= consms_mux_msg
;
1006 consms_mux_msg
= msg
;
1007 mutex_exit(&consms_msg_lock
);
1010 static consms_msg_t
*
1011 consms_mux_unlink_msg(uint_t msg_id
)
1014 consms_msg_t
*prev_msg
;
1016 mutex_enter(&consms_msg_lock
);
1018 for (msg
= consms_mux_msg
; msg
!= NULL
;
1019 prev_msg
= msg
, msg
= msg
->msg_next
) {
1020 if (msg
->msg_id
== msg_id
)
1025 if (prev_msg
!= NULL
) {
1026 prev_msg
->msg_next
= msg
->msg_next
;
1028 consms_mux_msg
= consms_mux_msg
->msg_next
;
1030 msg
->msg_next
= NULL
;
1032 mutex_exit(&consms_msg_lock
);
1037 static consms_msg_t
*
1038 consms_mux_find_msg(uint_t msg_id
)
1042 mutex_enter(&consms_msg_lock
);
1043 for (msg
= consms_mux_msg
; msg
!= NULL
; msg
= msg
->msg_next
) {
1044 if (msg
->msg_id
== msg_id
)
1047 mutex_exit(&consms_msg_lock
);
1053 * Received ACK or NAK from lower mice
1055 * For non-transparent ioctl, the msg->msg_rsp_list
1056 * is always NULL; for transparent ioctl, it
1057 * remembers the M_COPYIN/M_COPYOUT request
1058 * messages from lower mice. So here if msg->msg_rsp_list
1059 * is NULL (after receiving all ACK/NAKs), we
1060 * are done with this specific ioctl.
1062 * As long as one of lower mice responds success,
1063 * we treat it success for a ioctl.
1066 consms_mux_ack(consms_msg_t
*msg
, mblk_t
*mp
)
1070 /* increment response_nums */
1071 msg
->msg_num_responses
++;
1073 if (mp
->b_datap
->db_type
== M_IOCACK
) {
1075 * Received ACK from lower, then
1076 * this is the last step for both
1077 * non-transparent and transparent
1078 * ioctl. We only need to remember
1079 * one of the ACKs, finally reply
1080 * this ACK to upper layer for this
1083 ASSERT(msg
->msg_rsp_list
== NULL
);
1084 if (msg
->msg_ack_mp
== NULL
) {
1085 msg
->msg_ack_mp
= mp
;
1091 * Check to see if all lower mice have responded
1092 * to our dispatching ioctl.
1094 if (msg
->msg_num_responses
== msg
->msg_num_requests
) {
1095 if ((msg
->msg_ack_mp
== NULL
) &&
1096 (msg
->msg_rsp_list
== NULL
)) {
1102 } else if (msg
->msg_rsp_list
== NULL
) {
1104 * The last step and at least one ACKed.
1106 ack_mp
= msg
->msg_ack_mp
;
1107 consms_mux_cache_states(msg
->msg_request
);
1108 consms_mux_max_wheel_report(ack_mp
);
1111 * This is a NAK, but we have
1112 * already received M_COPYIN
1113 * or M_COPYOUT request from
1114 * at least one of lower mice.
1115 * (msg->msg_rsp_list != NULL)
1117 * Still copyin or copyout.
1119 ack_mp
= msg
->msg_rsp_list
->rsp_mp
;
1120 consms_mux_max_wheel_report(ack_mp
);
1123 qreply(msg
->msg_queue
, ack_mp
);
1125 if (msg
->msg_rsp_list
== NULL
) {
1127 * We are done with this ioctl.
1129 if (msg
->msg_request
)
1130 freemsg(msg
->msg_request
);
1131 (void) consms_mux_unlink_msg(msg
->msg_id
);
1132 kmem_free(msg
, sizeof (*msg
));
1142 * Received M_COPYIN or M_COPYOUT request from
1143 * lower mice for transparent ioctl
1145 * We remember each M_COPYIN/M_COPYOUT into the
1146 * msg->msg_rsp_list, reply upper layer using the first
1147 * M_COPYIN/M_COPYOUT in the list after receiving
1148 * all responses from lower mice, even if some of
1152 consms_mux_copyreq(queue_t
*q
, consms_msg_t
*msg
, mblk_t
*mp
)
1154 consms_response_t
*rsp
;
1156 rsp
= (consms_response_t
*)kmem_zalloc(sizeof (*rsp
), KM_SLEEP
);
1159 if (msg
->msg_rsp_list
) {
1160 rsp
->rsp_next
= msg
->msg_rsp_list
;
1162 msg
->msg_rsp_list
= rsp
;
1163 msg
->msg_num_responses
++;
1165 if (msg
->msg_num_responses
== msg
->msg_num_requests
) {
1166 consms_mux_max_wheel_report(msg
->msg_rsp_list
->rsp_mp
);
1167 qreply(msg
->msg_queue
, msg
->msg_rsp_list
->rsp_mp
);
1172 * Do the real job for updating M_COPYIN/M_COPYOUT
1173 * request with the mp of M_IOCDATA, then put it
1174 * down to lower mice.
1177 consms_mux_disp_iocdata(consms_response_t
*rsp
, mblk_t
*mp
)
1179 mblk_t
*down_mp
= rsp
->rsp_mp
;
1180 struct copyresp
*copyresp
= (struct copyresp
*)mp
->b_rptr
;
1181 struct copyresp
*newresp
= (struct copyresp
*)down_mp
->b_rptr
;
1186 newresp
->cp_rval
= copyresp
->cp_rval
;
1189 * Update the db_type to M_IOCDATA.
1191 down_mp
->b_datap
->db_type
= mp
->b_datap
->db_type
;
1194 * Update the b_cont.
1196 if (down_mp
->b_cont
!= NULL
) {
1197 freemsg(down_mp
->b_cont
);
1198 down_mp
->b_cont
= NULL
;
1200 if (mp
->b_cont
!= NULL
) {
1201 down_mp
->b_cont
= copymsg(mp
->b_cont
);
1207 (void) putq(WR(rsp
->rsp_queue
), down_mp
);
1211 * Dispatch M_IOCDATA down to all lower mice
1212 * for transparent ioctl.
1214 * We update each M_COPYIN/M_COPYOUT in the
1215 * msg->msg_rsp_list with the M_IOCDATA.
1218 consms_mux_iocdata(consms_msg_t
*msg
, mblk_t
*mp
)
1220 consms_response_t
*rsp
;
1221 consms_response_t
*tmp
;
1222 consms_response_t
*first
;
1223 struct copyresp
*copyresp
;
1226 ASSERT(msg
->msg_rsp_list
!= NULL
);
1229 * We should remember the ioc data for
1230 * VUIDSWHEELSTATE, and MSIOSRESOLUTION,
1231 * for we will cache the wheel state and
1232 * the screen resolution later if ACKed.
1234 copyresp
= (struct copyresp
*)mp
->b_rptr
;
1235 if ((copyresp
->cp_cmd
== VUIDSWHEELSTATE
) ||
1236 (copyresp
->cp_cmd
== MSIOSRESOLUTION
)) {
1237 freemsg(msg
->msg_request
);
1238 msg
->msg_request
= copymsg(mp
);
1242 * Update request numbers and response numbers.
1244 msg
->msg_num_requests
= msg
->msg_num_responses
;
1245 msg
->msg_num_responses
= 0;
1249 * Since we have use the first M_COPYIN/M_COPYOUT
1250 * in the msg_rsp_list to reply upper layer, the mp
1251 * of M_IOCDATA can be directly used for that.
1253 first
= msg
->msg_rsp_list
;
1254 rsp
= first
->rsp_next
;
1255 msg
->msg_rsp_list
= NULL
;
1257 for (rsp
= first
->rsp_next
; rsp
!= NULL
; ) {
1259 rsp
= rsp
->rsp_next
;
1260 consms_mux_disp_iocdata(tmp
, mp
);
1261 kmem_free(tmp
, sizeof (*tmp
));
1265 /* Must set the request number before the last q. */
1266 msg
->msg_num_requests
= request_nums
;
1269 (void) putq(WR(first
->rsp_queue
), mp
);
1270 kmem_free(first
, sizeof (*first
));
1275 * Here we update the number of wheels with
1276 * the virtual mouse for VUIDGWHEELCOUNT ioctl.
1279 consms_mux_max_wheel_report(mblk_t
*mp
)
1281 struct iocblk
*iocp
;
1284 if (mp
== NULL
|| mp
->b_cont
== NULL
)
1287 iocp
= (struct iocblk
*)mp
->b_rptr
;
1289 if ((iocp
->ioc_cmd
== VUIDGWHEELCOUNT
) &&
1290 (mp
->b_datap
->db_type
== M_COPYOUT
)) {
1291 num_wheels
= *(int *)mp
->b_cont
->b_rptr
;
1292 if (num_wheels
< consms_state
.consms_num_wheels
) {
1293 *(int *)mp
->b_cont
->b_rptr
=
1294 consms_state
.consms_num_wheels
;
1300 * Update the virtual mouse state variables with
1301 * the latest value from upper layer when these
1302 * set ioctls return success. Thus we can update
1303 * low mice with the latest state values during
1307 consms_mux_cache_states(mblk_t
*mp
)
1309 struct iocblk
*iocp
;
1311 Ms_screen_resolution
*sr
;
1314 if (mp
== NULL
|| mp
->b_cont
== NULL
)
1317 iocp
= (struct iocblk
*)mp
->b_rptr
;
1318 switch (iocp
->ioc_cmd
) {
1320 consms_state
.consms_vuid_format
= *(int *)mp
->b_cont
->b_rptr
;
1324 parms
= (Ms_parms
*)mp
->b_cont
->b_rptr
;
1325 consms_state
.consms_ms_parms
= *parms
;
1328 case MSIOSRESOLUTION
:
1329 sr
= (Ms_screen_resolution
*)mp
->b_cont
->b_rptr
;
1330 consms_state
.consms_ms_sr
= *sr
;
1333 case VUIDSWHEELSTATE
:
1334 ws
= (wheel_state
*)mp
->b_cont
->b_rptr
;
1335 consms_state
.consms_wheel_state_bf
=
1336 (ws
->stateflags
<< ws
->id
) |
1337 (consms_state
.consms_wheel_state_bf
& ~(1 << ws
->id
));
1343 * Dispatch ioctl mp (non-transparent and transparent)
1344 * down to all lower mice.
1346 * First, create a pending message for this mp, link it into
1347 * the global messages list. Then wait for ACK/NAK for
1348 * non-transparent ioctl, COPYIN/COPYOUT for transparent
1352 consms_mux_disp_ioctl(queue_t
*q
, mblk_t
*mp
)
1354 struct iocblk
*iocp
;
1360 iocp
= (struct iocblk
*)mp
->b_rptr
;
1361 msg
= (consms_msg_t
*)kmem_zalloc(sizeof (*msg
), KM_SLEEP
);
1362 msg
->msg_id
= iocp
->ioc_id
;
1363 msg
->msg_request
= mp
;
1365 msg
->msg_num_requests
= consms_state
.consms_num_lqs
;
1366 consms_mux_link_msg(msg
);
1368 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
1369 if ((copy_mp
= copymsg(mp
)) != NULL
) {
1370 (void) putq(lq
->lq_queue
, copy_mp
);
1373 * If copymsg fails, we ignore this lq and
1374 * try next one. As long as one of them succeeds,
1375 * we dispatch this ioctl down. And later as long
1376 * as one of the lower drivers return success, we
1377 * reply to this ioctl with success.
1379 msg
->msg_num_requests
--;
1383 if (msg
->msg_num_requests
<= 0) {
1385 * Since copymsg fails for all lqs, we NAK this ioctl.
1387 (void) consms_mux_unlink_msg(msg
->msg_id
);
1388 kmem_free(msg
, sizeof (*msg
));
1396 * Dispatch M_DATA and M_FLUSH message down to all
1397 * lower mice, and there are no acknowledgements
1398 * for them. Here we just copy the mp and then
1399 * put it into the lower queues.
1402 consms_mux_disp_data(mblk_t
*mp
)
1407 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
1408 if ((copy_mp
= copymsg(mp
)) != NULL
) {
1409 (void) putq(lq
->lq_queue
, copy_mp
);