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 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
, 0) == 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
, void **result
)
331 case DDI_INFO_DEVT2DEVINFO
:
332 if (consms_dip
== NULL
) {
335 *result
= (void *) consms_dip
;
339 case DDI_INFO_DEVT2INSTANCE
:
352 consmsopen(queue_t
*q
, dev_t
*devp
, int flag
, int sflag
, cred_t
*crp
)
361 consmsclose(queue_t
*q
, int flag
, cred_t
*crp
)
369 * Put procedure for upper write queue.
372 consmsuwput(register queue_t
*q
, register mblk_t
*mp
)
374 struct iocblk
*iocbp
= (struct iocblk
*)mp
->b_rptr
;
378 switch (mp
->b_datap
->db_type
) {
385 if (*mp
->b_rptr
& FLUSHW
)
386 flushq(q
, FLUSHDATA
);
387 if (*mp
->b_rptr
& FLUSHR
)
388 flushq(RD(q
), FLUSHDATA
);
389 if (consms_state
.consms_num_lqs
> 0) {
390 consms_mux_disp_data(mp
);
393 * No lower queue; just reflect this back upstream.
395 *mp
->b_rptr
&= ~FLUSHW
;
396 if (*mp
->b_rptr
& FLUSHR
)
404 if (consms_state
.consms_num_lqs
> 0) {
405 consms_mux_disp_data(mp
);
412 if ((msg
= consms_mux_find_msg(iocbp
->ioc_id
)) != NULL
) {
413 consms_mux_iocdata(msg
, mp
);
426 * Pass an error message up.
428 mp
->b_datap
->db_type
= M_ERROR
;
433 mp
->b_rptr
= mp
->b_datap
->db_base
;
434 mp
->b_wptr
= mp
->b_rptr
+ sizeof (char);
435 *mp
->b_rptr
= (char)error
;
441 consmsioctl(register queue_t
*q
, register mblk_t
*mp
)
443 register struct iocblk
*iocp
;
447 iocp
= (struct iocblk
*)mp
->b_rptr
;
449 switch (iocp
->ioc_cmd
) {
453 mutex_enter(&consmslock
);
455 mutex_exit(&consmslock
);
460 mutex_enter(&consmslock
);
461 if ((error
= consms_punlink(q
, mp
)) != 0) {
462 mutex_exit(&consmslock
);
463 miocnak(q
, mp
, 0, error
);
466 mutex_exit(&consmslock
);
470 case MSIOBUTTONS
: /* query the number of buttons */
471 if ((consms_state
.consms_num_lqs
<= 0) ||
472 ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)) {
473 miocnak(q
, mp
, 0, ENOMEM
);
476 *(int *)datap
->b_wptr
= consms_state
.consms_num_buttons
;
477 datap
->b_wptr
+= sizeof (int);
482 iocp
->ioc_count
= sizeof (int);
487 * Pass this through, if there's something to pass it
488 * through to; otherwise, reject it.
490 if (consms_state
.consms_num_lqs
<= 0) {
491 miocnak(q
, mp
, 0, EINVAL
);
494 if ((error
= consms_mux_disp_ioctl(q
, mp
)) != 0)
495 miocnak(q
, mp
, 0, error
);
501 * Common exit path for calls that return a positive
502 * acknowledgment with a return value of 0.
504 miocack(q
, mp
, iocp
->ioc_count
, 0);
508 * Service procedure for lower write queue.
509 * Puts things on the queue below us, if it lets us.
512 consmslwserv(register queue_t
*q
)
516 while (canput(q
->q_next
) && (mp
= getq(q
)) != NULL
)
521 * Put procedure for lower read queue.
524 consmslrput(register queue_t
*q
, register mblk_t
*mp
)
526 struct iocblk
*iocbp
= (struct iocblk
*)mp
->b_rptr
;
527 struct copyreq
*copyreq
= (struct copyreq
*)mp
->b_rptr
;
529 consms_lq_t
*lq
= (consms_lq_t
*)q
->q_ptr
;
533 switch (mp
->b_datap
->db_type
) {
535 if (*mp
->b_rptr
& FLUSHW
)
536 flushq(WR(q
), FLUSHDATA
);
537 if (*mp
->b_rptr
& FLUSHR
)
538 flushq(q
, FLUSHDATA
);
539 if (upperqueue
!= NULL
)
540 putnext(upperqueue
, mp
); /* pass it through */
543 * No upper queue; just reflect this back downstream.
545 *mp
->b_rptr
&= ~FLUSHR
;
546 if (*mp
->b_rptr
& FLUSHW
)
554 if (upperqueue
!= NULL
)
555 putnext(upperqueue
, mp
);
558 consms_idle_stamp
= gethrestime_sec();
564 * First, check to see if this device
565 * is still being initialized.
567 if (lq
->lq_ioc_reply_func
!= NULL
) {
568 mutex_enter(&consmslock
);
569 lq
->lq_ioc_reply_func(lq
, mp
);
570 mutex_exit(&consmslock
);
576 * This is normal ioctl ack for upper layer.
578 if ((msg
= consms_mux_find_msg(iocbp
->ioc_id
)) != NULL
) {
579 consms_mux_ack(msg
, mp
);
583 consms_idle_stamp
= gethrestime_sec();
588 if ((msg
= consms_mux_find_msg(copyreq
->cq_id
)) != NULL
) {
589 consms_mux_copyreq(q
, msg
, mp
);
592 consms_idle_stamp
= gethrestime_sec();
598 freemsg(mp
); /* anything useful here? */
605 consms_kstat_update(kstat_t
*ksp
, int rw
)
607 if (rw
== KSTAT_WRITE
)
610 consms_kstat
.idle_sec
.value
.l
= gethrestime_sec() - consms_idle_stamp
;
616 consms_punlink(queue_t
*q
, mblk_t
*mp
)
618 struct linkblk
*linkp
;
620 consms_lq_t
*prev_lq
;
622 ASSERT(MUTEX_HELD(&consmslock
));
624 linkp
= (struct linkblk
*)mp
->b_cont
->b_rptr
;
627 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
628 if (lq
->lq_queue
== linkp
->l_qbot
) {
630 prev_lq
->lq_next
= lq
->lq_next
;
632 consms_state
.consms_lqs
= lq
->lq_next
;
633 kmem_free(lq
, sizeof (*lq
));
634 consms_state
.consms_num_lqs
--;
637 * Check to see if mouse capabilities
651 * Link a specific mouse into our mouse list.
654 consms_plink(queue_t
*q
, mblk_t
*mp
)
656 struct linkblk
*linkp
;
660 ASSERT(MUTEX_HELD(&consmslock
));
662 linkp
= (struct linkblk
*)mp
->b_cont
->b_rptr
;
663 lowq
= linkp
->l_qbot
;
665 lq
= kmem_zalloc(sizeof (*lq
), KM_SLEEP
);
667 lowq
->q_ptr
= (void *)lq
;
668 OTHERQ(lowq
)->q_ptr
= (void *)lq
;
670 lq
->lq_pending_plink
= mp
;
671 lq
->lq_pending_queue
= q
;
674 * Set the number of buttons to 3 by default
675 * in case the following MSIOBUTTONS ioctl fails.
677 lq
->lq_num_buttons
= 3;
680 * Begin to initialize this mouse.
682 lq
->lq_state
= LQS_START
;
683 consms_lqs_ack_complete(lq
, NULL
);
687 * Initialize the newly hotplugged-in mouse,
688 * e.g. get the number of buttons, set event
689 * format. Then we add it into our list.
692 consms_lqs_ack_complete(consms_lq_t
*lq
, mblk_t
*mp
)
695 boolean_t skipped
= B_FALSE
;
697 Ms_screen_resolution
*sr
;
700 ASSERT(MUTEX_HELD(&consmslock
));
703 * We try each ioctl even if the previous one fails
704 * until we reach LQS_DONE, and then add this lq
707 * If the message allocation fails, we skip this ioctl,
708 * set skipped flag to B_TRUE in order to skip the ioctl
709 * result, then we try next ioctl, go to next state.
711 while ((lq
->lq_state
< LQS_DONE
) && (req
== NULL
)) {
712 switch (lq
->lq_state
) {
715 * First, issue MSIOBUTTONS ioctl
716 * to get the number of buttons.
718 req
= mkiocb(MSIOBUTTONS
);
719 if (req
&& ((req
->b_cont
= allocb(sizeof (int),
720 BPRI_MED
)) == NULL
)) {
729 case LQS_BUTTON_COUNT_PENDING
:
730 if (!skipped
&& mp
&& mp
->b_cont
&&
731 (mp
->b_datap
->db_type
== M_IOCACK
))
733 *(int *)mp
->b_cont
->b_rptr
;
736 * Second, issue VUIDGWHEELCOUNT ioctl
737 * to get the count of wheels.
739 req
= mkiocb(VUIDGWHEELCOUNT
);
740 if (req
&& ((req
->b_cont
= allocb(sizeof (int),
741 BPRI_MED
)) == NULL
)) {
750 case LQS_WHEEL_COUNT_PENDING
:
751 if (!skipped
&& mp
&& mp
->b_cont
&&
752 (mp
->b_datap
->db_type
== M_IOCACK
))
754 *(int *)mp
->b_cont
->b_rptr
;
757 * Third, issue VUIDSFORMAT ioctl
758 * to set the event format.
760 req
= mkiocb(VUIDSFORMAT
);
761 if (req
&& ((req
->b_cont
= allocb(sizeof (int),
762 BPRI_MED
)) == NULL
)) {
767 *(int *)req
->b_cont
->b_wptr
=
768 consms_state
.consms_vuid_format
;
769 req
->b_cont
->b_wptr
+= sizeof (int);
774 case LQS_SET_VUID_FORMAT_PENDING
:
776 * Fourth, issue VUIDSWHEELSTATE ioctl
777 * to set the wheel state (enable or disable).
779 req
= mkiocb(VUIDSWHEELSTATE
);
780 if (req
&& ((req
->b_cont
= allocb(sizeof (wheel_state
),
781 BPRI_MED
)) == NULL
)) {
786 ws
= (wheel_state
*)req
->b_cont
->b_wptr
;
787 ws
->vers
= VUID_WHEEL_STATE_VERS
;
788 ws
->id
= 0; /* the first wheel */
790 consms_state
.consms_wheel_state_bf
& 1;
791 req
->b_cont
->b_wptr
+= sizeof (wheel_state
);
796 case LQS_SET_WHEEL_STATE_PENDING
:
798 * Fifth, issue MSIOSETPARMS ioctl
799 * to set the parameters for USB mouse.
801 req
= mkiocb(MSIOSETPARMS
);
802 if (req
&& ((req
->b_cont
= allocb(sizeof (Ms_parms
),
803 BPRI_MED
)) == NULL
)) {
808 params
= (Ms_parms
*)req
->b_cont
->b_wptr
;
809 *params
= consms_state
.consms_ms_parms
;
810 req
->b_cont
->b_wptr
+= sizeof (Ms_parms
);
815 case LQS_SET_PARMS_PENDING
:
817 * Sixth, issue MSIOSRESOLUTION ioctl
818 * to set the screen resolution for absolute mouse.
820 req
= mkiocb(MSIOSRESOLUTION
);
821 if (req
&& ((req
->b_cont
=
822 allocb(sizeof (Ms_screen_resolution
),
823 BPRI_MED
)) == NULL
)) {
829 (Ms_screen_resolution
*)req
->b_cont
->b_wptr
;
830 *sr
= consms_state
.consms_ms_sr
;
831 req
->b_cont
->b_wptr
+=
832 sizeof (Ms_screen_resolution
);
837 case LQS_SET_RESOLUTION_PENDING
:
839 * All jobs are done, lq->lq_state is turned into
840 * LQS_DONE, and this lq is added into our list.
848 if (lq
->lq_state
< LQS_DONE
) {
849 lq
->lq_ioc_reply_func
= consms_lqs_ack_complete
;
850 (void) putq(lq
->lq_queue
, req
);
855 * Add this specific lq into our list, finally reply
856 * the previous pending I_PLINK ioctl. Also check to
857 * see if mouse capabilities have changed, and send
858 * a dynamical notification event to upper layer if
862 consms_add_lq(consms_lq_t
*lq
)
866 ASSERT(MUTEX_HELD(&consmslock
));
868 lq
->lq_ioc_reply_func
= NULL
;
869 iocp
= (struct iocblk
*)lq
->lq_pending_plink
->b_rptr
;
873 lq
->lq_pending_plink
->b_datap
->db_type
= M_IOCACK
;
875 /* Reply to the I_PLINK ioctl. */
876 qreply(lq
->lq_pending_queue
, lq
->lq_pending_plink
);
878 lq
->lq_pending_plink
= NULL
;
879 lq
->lq_pending_queue
= NULL
;
882 * Add this lq into list.
884 consms_state
.consms_num_lqs
++;
886 lq
->lq_next
= consms_state
.consms_lqs
;
887 consms_state
.consms_lqs
= lq
;
890 * Check to see if mouse capabilities
899 consms_check_caps(void)
907 * Check to see if the number of buttons
908 * and the number of wheels have changed.
910 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
911 max_buttons
= CONSMS_MAX(max_buttons
, lq
->lq_num_buttons
);
912 max_wheels
= CONSMS_MAX(max_wheels
, lq
->lq_num_wheels
);
915 if (max_buttons
!= consms_state
.consms_num_buttons
) {
917 * Since the number of buttons have changed,
918 * send a MOUSE_CAP_CHANGE_NUM_BUT dynamical
919 * notification event to upper layer.
921 consms_state
.consms_num_buttons
= max_buttons
;
922 if (upperqueue
!= NULL
) {
923 if ((mp
= consms_new_firm_event(
924 MOUSE_CAP_CHANGE_NUM_BUT
,
925 consms_state
.consms_num_buttons
)) != NULL
) {
926 putnext(upperqueue
, mp
);
931 if (max_wheels
!= consms_state
.consms_num_wheels
) {
933 * Since the number of wheels have changed,
934 * send a MOUSE_CAP_CHANGE_NUM_WHEEL dynamical
935 * notification event to upper layer.
937 consms_state
.consms_num_wheels
= max_wheels
;
938 if (upperqueue
!= NULL
) {
939 if ((mp
= consms_new_firm_event(
940 MOUSE_CAP_CHANGE_NUM_WHEEL
,
941 consms_state
.consms_num_wheels
)) != NULL
) {
942 putnext(upperqueue
, mp
);
949 * Allocate a dynamical notification event.
952 consms_new_firm_event(ushort_t id
, int value
)
957 if ((tmp
= allocb(sizeof (Firm_event
), BPRI_HI
)) != NULL
) {
958 fep
= (Firm_event
*)tmp
->b_wptr
;
960 fep
->pair_type
= FE_PAIR_NONE
;
963 tmp
->b_wptr
+= sizeof (Firm_event
);
970 * Start of dispatching interfaces as a multiplexor
974 * There is a global msg list (consms_mux_msg),
975 * which is used to link all ioctl messages from
976 * upper layer, which are currently being processed.
978 * consms_mux_link_msg links a msg into the list,
979 * consms_mux_unlink_msg unlinks a msg from the list,
980 * consms_mux_find_msg finds a msg from the list
981 * according to its unique id.
983 * The id of each msg is taken from stream's mp,
984 * so the id is supposed to be unique.
987 consms_mux_link_msg(consms_msg_t
*msg
)
989 mutex_enter(&consms_msg_lock
);
990 msg
->msg_next
= consms_mux_msg
;
991 consms_mux_msg
= msg
;
992 mutex_exit(&consms_msg_lock
);
995 static consms_msg_t
*
996 consms_mux_unlink_msg(uint_t msg_id
)
999 consms_msg_t
*prev_msg
;
1001 mutex_enter(&consms_msg_lock
);
1003 for (msg
= consms_mux_msg
; msg
!= NULL
;
1004 prev_msg
= msg
, msg
= msg
->msg_next
) {
1005 if (msg
->msg_id
== msg_id
)
1010 if (prev_msg
!= NULL
) {
1011 prev_msg
->msg_next
= msg
->msg_next
;
1013 consms_mux_msg
= consms_mux_msg
->msg_next
;
1015 msg
->msg_next
= NULL
;
1017 mutex_exit(&consms_msg_lock
);
1022 static consms_msg_t
*
1023 consms_mux_find_msg(uint_t msg_id
)
1027 mutex_enter(&consms_msg_lock
);
1028 for (msg
= consms_mux_msg
; msg
!= NULL
; msg
= msg
->msg_next
) {
1029 if (msg
->msg_id
== msg_id
)
1032 mutex_exit(&consms_msg_lock
);
1038 * Received ACK or NAK from lower mice
1040 * For non-transparent ioctl, the msg->msg_rsp_list
1041 * is always NULL; for transparent ioctl, it
1042 * remembers the M_COPYIN/M_COPYOUT request
1043 * messages from lower mice. So here if msg->msg_rsp_list
1044 * is NULL (after receiving all ACK/NAKs), we
1045 * are done with this specific ioctl.
1047 * As long as one of lower mice responds success,
1048 * we treat it success for a ioctl.
1051 consms_mux_ack(consms_msg_t
*msg
, mblk_t
*mp
)
1055 /* increment response_nums */
1056 msg
->msg_num_responses
++;
1058 if (mp
->b_datap
->db_type
== M_IOCACK
) {
1060 * Received ACK from lower, then
1061 * this is the last step for both
1062 * non-transparent and transparent
1063 * ioctl. We only need to remember
1064 * one of the ACKs, finally reply
1065 * this ACK to upper layer for this
1068 ASSERT(msg
->msg_rsp_list
== NULL
);
1069 if (msg
->msg_ack_mp
== NULL
) {
1070 msg
->msg_ack_mp
= mp
;
1076 * Check to see if all lower mice have responded
1077 * to our dispatching ioctl.
1079 if (msg
->msg_num_responses
== msg
->msg_num_requests
) {
1080 if ((msg
->msg_ack_mp
== NULL
) &&
1081 (msg
->msg_rsp_list
== NULL
)) {
1087 } else if (msg
->msg_rsp_list
== NULL
) {
1089 * The last step and at least one ACKed.
1091 ack_mp
= msg
->msg_ack_mp
;
1092 consms_mux_cache_states(msg
->msg_request
);
1093 consms_mux_max_wheel_report(ack_mp
);
1096 * This is a NAK, but we have
1097 * already received M_COPYIN
1098 * or M_COPYOUT request from
1099 * at least one of lower mice.
1100 * (msg->msg_rsp_list != NULL)
1102 * Still copyin or copyout.
1104 ack_mp
= msg
->msg_rsp_list
->rsp_mp
;
1105 consms_mux_max_wheel_report(ack_mp
);
1108 qreply(msg
->msg_queue
, ack_mp
);
1110 if (msg
->msg_rsp_list
== NULL
) {
1112 * We are done with this ioctl.
1114 if (msg
->msg_request
)
1115 freemsg(msg
->msg_request
);
1116 (void) consms_mux_unlink_msg(msg
->msg_id
);
1117 kmem_free(msg
, sizeof (*msg
));
1127 * Received M_COPYIN or M_COPYOUT request from
1128 * lower mice for transparent ioctl
1130 * We remember each M_COPYIN/M_COPYOUT into the
1131 * msg->msg_rsp_list, reply upper layer using the first
1132 * M_COPYIN/M_COPYOUT in the list after receiving
1133 * all responses from lower mice, even if some of
1137 consms_mux_copyreq(queue_t
*q
, consms_msg_t
*msg
, mblk_t
*mp
)
1139 consms_response_t
*rsp
;
1141 rsp
= (consms_response_t
*)kmem_zalloc(sizeof (*rsp
), KM_SLEEP
);
1144 if (msg
->msg_rsp_list
) {
1145 rsp
->rsp_next
= msg
->msg_rsp_list
;
1147 msg
->msg_rsp_list
= rsp
;
1148 msg
->msg_num_responses
++;
1150 if (msg
->msg_num_responses
== msg
->msg_num_requests
) {
1151 consms_mux_max_wheel_report(msg
->msg_rsp_list
->rsp_mp
);
1152 qreply(msg
->msg_queue
, msg
->msg_rsp_list
->rsp_mp
);
1157 * Do the real job for updating M_COPYIN/M_COPYOUT
1158 * request with the mp of M_IOCDATA, then put it
1159 * down to lower mice.
1162 consms_mux_disp_iocdata(consms_response_t
*rsp
, mblk_t
*mp
)
1164 mblk_t
*down_mp
= rsp
->rsp_mp
;
1165 struct copyresp
*copyresp
= (struct copyresp
*)mp
->b_rptr
;
1166 struct copyresp
*newresp
= (struct copyresp
*)down_mp
->b_rptr
;
1171 newresp
->cp_rval
= copyresp
->cp_rval
;
1174 * Update the db_type to M_IOCDATA.
1176 down_mp
->b_datap
->db_type
= mp
->b_datap
->db_type
;
1179 * Update the b_cont.
1181 if (down_mp
->b_cont
!= NULL
) {
1182 freemsg(down_mp
->b_cont
);
1183 down_mp
->b_cont
= NULL
;
1185 if (mp
->b_cont
!= NULL
) {
1186 down_mp
->b_cont
= copymsg(mp
->b_cont
);
1192 (void) putq(WR(rsp
->rsp_queue
), down_mp
);
1196 * Dispatch M_IOCDATA down to all lower mice
1197 * for transparent ioctl.
1199 * We update each M_COPYIN/M_COPYOUT in the
1200 * msg->msg_rsp_list with the M_IOCDATA.
1203 consms_mux_iocdata(consms_msg_t
*msg
, mblk_t
*mp
)
1205 consms_response_t
*rsp
;
1206 consms_response_t
*tmp
;
1207 consms_response_t
*first
;
1208 struct copyresp
*copyresp
;
1211 ASSERT(msg
->msg_rsp_list
!= NULL
);
1214 * We should remember the ioc data for
1215 * VUIDSWHEELSTATE, and MSIOSRESOLUTION,
1216 * for we will cache the wheel state and
1217 * the screen resolution later if ACKed.
1219 copyresp
= (struct copyresp
*)mp
->b_rptr
;
1220 if ((copyresp
->cp_cmd
== VUIDSWHEELSTATE
) ||
1221 (copyresp
->cp_cmd
== MSIOSRESOLUTION
)) {
1222 freemsg(msg
->msg_request
);
1223 msg
->msg_request
= copymsg(mp
);
1227 * Update request numbers and response numbers.
1229 msg
->msg_num_requests
= msg
->msg_num_responses
;
1230 msg
->msg_num_responses
= 0;
1234 * Since we have use the first M_COPYIN/M_COPYOUT
1235 * in the msg_rsp_list to reply upper layer, the mp
1236 * of M_IOCDATA can be directly used for that.
1238 first
= msg
->msg_rsp_list
;
1239 rsp
= first
->rsp_next
;
1240 msg
->msg_rsp_list
= NULL
;
1242 for (rsp
= first
->rsp_next
; rsp
!= NULL
; ) {
1244 rsp
= rsp
->rsp_next
;
1245 consms_mux_disp_iocdata(tmp
, mp
);
1246 kmem_free(tmp
, sizeof (*tmp
));
1250 /* Must set the request number before the last q. */
1251 msg
->msg_num_requests
= request_nums
;
1254 (void) putq(WR(first
->rsp_queue
), mp
);
1255 kmem_free(first
, sizeof (*first
));
1260 * Here we update the number of wheels with
1261 * the virtual mouse for VUIDGWHEELCOUNT ioctl.
1264 consms_mux_max_wheel_report(mblk_t
*mp
)
1266 struct iocblk
*iocp
;
1269 if (mp
== NULL
|| mp
->b_cont
== NULL
)
1272 iocp
= (struct iocblk
*)mp
->b_rptr
;
1274 if ((iocp
->ioc_cmd
== VUIDGWHEELCOUNT
) &&
1275 (mp
->b_datap
->db_type
== M_COPYOUT
)) {
1276 num_wheels
= *(int *)mp
->b_cont
->b_rptr
;
1277 if (num_wheels
< consms_state
.consms_num_wheels
) {
1278 *(int *)mp
->b_cont
->b_rptr
=
1279 consms_state
.consms_num_wheels
;
1285 * Update the virtual mouse state variables with
1286 * the latest value from upper layer when these
1287 * set ioctls return success. Thus we can update
1288 * low mice with the latest state values during
1292 consms_mux_cache_states(mblk_t
*mp
)
1294 struct iocblk
*iocp
;
1296 Ms_screen_resolution
*sr
;
1299 if (mp
== NULL
|| mp
->b_cont
== NULL
)
1302 iocp
= (struct iocblk
*)mp
->b_rptr
;
1303 switch (iocp
->ioc_cmd
) {
1305 consms_state
.consms_vuid_format
= *(int *)mp
->b_cont
->b_rptr
;
1309 parms
= (Ms_parms
*)mp
->b_cont
->b_rptr
;
1310 consms_state
.consms_ms_parms
= *parms
;
1313 case MSIOSRESOLUTION
:
1314 sr
= (Ms_screen_resolution
*)mp
->b_cont
->b_rptr
;
1315 consms_state
.consms_ms_sr
= *sr
;
1318 case VUIDSWHEELSTATE
:
1319 ws
= (wheel_state
*)mp
->b_cont
->b_rptr
;
1320 consms_state
.consms_wheel_state_bf
=
1321 (ws
->stateflags
<< ws
->id
) |
1322 (consms_state
.consms_wheel_state_bf
& ~(1 << ws
->id
));
1328 * Dispatch ioctl mp (non-transparent and transparent)
1329 * down to all lower mice.
1331 * First, create a pending message for this mp, link it into
1332 * the global messages list. Then wait for ACK/NAK for
1333 * non-transparent ioctl, COPYIN/COPYOUT for transparent
1337 consms_mux_disp_ioctl(queue_t
*q
, mblk_t
*mp
)
1339 struct iocblk
*iocp
;
1345 iocp
= (struct iocblk
*)mp
->b_rptr
;
1346 msg
= (consms_msg_t
*)kmem_zalloc(sizeof (*msg
), KM_SLEEP
);
1347 msg
->msg_id
= iocp
->ioc_id
;
1348 msg
->msg_request
= mp
;
1350 msg
->msg_num_requests
= consms_state
.consms_num_lqs
;
1351 consms_mux_link_msg(msg
);
1353 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
1354 if ((copy_mp
= copymsg(mp
)) != NULL
) {
1355 (void) putq(lq
->lq_queue
, copy_mp
);
1358 * If copymsg fails, we ignore this lq and
1359 * try next one. As long as one of them succeeds,
1360 * we dispatch this ioctl down. And later as long
1361 * as one of the lower drivers return success, we
1362 * reply to this ioctl with success.
1364 msg
->msg_num_requests
--;
1368 if (msg
->msg_num_requests
<= 0) {
1370 * Since copymsg fails for all lqs, we NAK this ioctl.
1372 (void) consms_mux_unlink_msg(msg
->msg_id
);
1373 kmem_free(msg
, sizeof (*msg
));
1381 * Dispatch M_DATA and M_FLUSH message down to all
1382 * lower mice, and there are no acknowledgements
1383 * for them. Here we just copy the mp and then
1384 * put it into the lower queues.
1387 consms_mux_disp_data(mblk_t
*mp
)
1392 for (lq
= consms_state
.consms_lqs
; lq
!= NULL
; lq
= lq
->lq_next
) {
1393 if ((copy_mp
= copymsg(mp
)) != NULL
) {
1394 (void) putq(lq
->lq_queue
, copy_mp
);