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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * VUIDMICE module: put mouse events into vuid format
31 #include <sys/param.h>
32 #include <sys/stream.h>
33 #include <sys/stropts.h>
34 #include <sys/strsun.h>
35 #include <sys/errno.h>
36 #include <sys/debug.h>
37 #include <sys/cmn_err.h>
39 #include <sys/vuid_event.h>
41 #include <sys/vuid_wheel.h>
45 #include <sys/modctl.h>
49 #include <sys/sunddi.h>
51 static int vuidmice_open(queue_t
*const, const dev_t
*const,
52 const int, const int, const cred_t
*const);
53 static int vuidmice_close(queue_t
*const, const int, const cred_t
*const);
54 static int vuidmice_rput(queue_t
*const, mblk_t
*);
55 static int vuidmice_rsrv(queue_t
*const);
56 static int vuidmice_wput(queue_t
*const, mblk_t
*);
57 static void vuidmice_miocdata(queue_t
*const, mblk_t
*);
58 static int vuidmice_handle_wheel_resolution_ioctl(queue_t
*const,
61 static int vuidmice_service_wheel_info(mblk_t
*);
62 static int vuidmice_service_wheel_state(queue_t
*, mblk_t
*, uint_t
);
64 void VUID_QUEUE(queue_t
*const, mblk_t
*);
65 int VUID_OPEN(queue_t
*const);
66 void VUID_CLOSE(queue_t
*const);
68 static kmutex_t vuidmice_lock
;
70 static struct module_info vuidmice_iinfo
= {
79 static struct qinit vuidmice_rinit
= {
89 static struct module_info vuidmice_oinfo
= {
98 static struct qinit vuidmice_winit
= {
108 struct streamtab vuidmice_info
= {
116 * This is the loadable module wrapper.
120 * D_MTQPAIR effectively makes the module single threaded.
121 * There can be only one thread active in the module at any time.
122 * It may be a read or write thread.
124 #define VUIDMICE_CONF_FLAG (D_MP | D_MTQPAIR)
126 static struct fmodsw fsw
= {
132 static struct modlstrmod modlstrmod
= {
134 "mouse events to vuid events",
139 * Module linkage information for the kernel.
141 static struct modlinkage modlinkage
= {
147 static int module_open
= 0; /* allow only one open of this module */
154 mutex_init(&vuidmice_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
155 if ((rc
= mod_install(&modlinkage
)) != 0) {
156 mutex_destroy(&vuidmice_lock
);
166 if ((rc
= mod_remove(&modlinkage
)) == 0)
167 mutex_destroy(&vuidmice_lock
);
172 _info(struct modinfo
*modinfop
)
174 return (mod_info(&modlinkage
, modinfop
));
180 vuidmice_open(queue_t
*const qp
, const dev_t
*const devp
,
181 const int oflag
, const int sflag
, const cred_t
*const crp
)
183 if (qp
->q_ptr
!= NULL
)
184 return (0); /* reopen */
186 mutex_enter(&vuidmice_lock
);
188 /* Allow only 1 open of this module */
190 mutex_exit(&vuidmice_lock
);
195 mutex_exit(&vuidmice_lock
);
198 * Both the read and write queues share the same state structures.
200 qp
->q_ptr
= kmem_zalloc(sizeof (struct MouseStateInfo
), KM_SLEEP
);
201 WR(qp
)->q_ptr
= qp
->q_ptr
;
203 /* initialize state */
204 STATEP
->format
= VUID_NATIVE
;
209 if (VUID_OPEN(qp
) != 0) {
212 mutex_enter(&vuidmice_lock
);
214 mutex_exit(&vuidmice_lock
);
215 kmem_free(qp
->q_ptr
, sizeof (struct MouseStateInfo
));
226 vuidmice_close(queue_t
*const qp
, const int flag
, const cred_t
*const crp
)
231 flushq(qp
, FLUSHALL
);
232 flushq(OTHERQ(qp
), FLUSHALL
);
237 mutex_enter(&vuidmice_lock
);
239 mutex_exit(&vuidmice_lock
);
240 kmem_free(qp
->q_ptr
, sizeof (struct MouseStateInfo
));
247 * Put procedure for input from driver end of stream (read queue).
250 vuidmice_rput(queue_t
*const qp
, mblk_t
*mp
)
256 * Handle all the related high priority messages here, hence
257 * should spend the least amount of time here.
260 if (DB_TYPE(mp
) == M_DATA
) {
261 if ((int)STATEP
->format
== VUID_FIRM_EVENT
)
262 return (putq(qp
, mp
)); /* queue message & return */
263 } else if (DB_TYPE(mp
) == M_FLUSH
) {
264 if (*mp
->b_rptr
& FLUSHR
)
265 flushq(qp
, FLUSHALL
);
268 putnext(qp
, mp
); /* pass it on */
273 vuidmice_rsrv(queue_t
*const qp
)
279 while ((mp
= getq(qp
)) != NULL
) {
280 ASSERT(DB_TYPE(mp
) == M_DATA
);
283 return (putbq(qp
, mp
)); /* read side is blocked */
285 switch (DB_TYPE(mp
)) {
287 if ((int)STATEP
->format
== VUID_FIRM_EVENT
)
288 (void) VUID_QUEUE(qp
, mp
);
290 (void) putnext(qp
, mp
);
295 "vuidmice_rsrv: bad message type (0x%x)\n",
298 (void) putnext(qp
, mp
);
306 * Put procedure for write from user end of stream (write queue).
309 vuidmice_wput(queue_t
*const qp
, mblk_t
*mp
)
317 * Handle all the related high priority messages here, hence
318 * should spend the least amount of time here.
320 switch (DB_TYPE(mp
)) { /* handle hi pri messages here */
322 if (*mp
->b_rptr
& FLUSHW
)
323 flushq(qp
, FLUSHALL
);
324 putnext(qp
, mp
); /* pass it on */
328 struct iocblk
*iocbp
= (void *)mp
->b_rptr
;
330 switch (iocbp
->ioc_cmd
) {
334 * VUIDSFORMAT is known to the stream head and thus
335 * is guaranteed to be an I_STR ioctl.
337 if (iocbp
->ioc_count
== TRANSPARENT
) {
338 miocnak(qp
, mp
, 0, EINVAL
);
343 error
= miocpullup(mp
, sizeof (int));
345 miocnak(qp
, mp
, 0, error
);
350 *(int *)(void *)mp
->b_cont
->b_rptr
;
351 STATEP
->format
= (uchar_t
)format_type
;
353 iocbp
->ioc_count
= 0;
354 iocbp
->ioc_error
= 0;
355 mp
->b_datap
->db_type
= M_IOCACK
;
358 /* return buffer to pool ASAP */
369 /* return buffer to pool ASAP */
371 freemsg(mp
->b_cont
); /* over written below */
376 * VUIDGFORMAT is known to the stream head and thus
377 * is guaranteed to be an I_STR ioctl.
379 if (iocbp
->ioc_count
== TRANSPARENT
) {
380 miocnak(qp
, mp
, 0, EINVAL
);
384 mp
->b_cont
= allocb(sizeof (int), BPRI_MED
);
385 if (mp
->b_cont
== NULL
) {
386 miocnak(qp
, mp
, 0, EAGAIN
);
390 *(int *)(void *)mp
->b_cont
->b_rptr
=
392 mp
->b_cont
->b_wptr
+= sizeof (int);
394 iocbp
->ioc_count
= sizeof (int);
395 mp
->b_datap
->db_type
= M_IOCACK
;
402 miocnak(qp
, mp
, 0, ENOTTY
);
406 /* return buffer to pool ASAP */
408 freemsg(mp
->b_cont
); /* over written below */
413 * MSIOBUTTONS is known to streamio.c and this
414 * is assume to be non-I_STR & non-TRANSPARENT ioctl
417 if (iocbp
->ioc_count
== TRANSPARENT
) {
418 miocnak(qp
, mp
, 0, EINVAL
);
422 if (STATEP
->nbuttons
== 0) {
423 miocnak(qp
, mp
, 0, EINVAL
);
427 mp
->b_cont
= allocb(sizeof (int), BPRI_MED
);
428 if (mp
->b_cont
== NULL
) {
429 miocnak(qp
, mp
, 0, EAGAIN
);
433 *(int *)(void *)mp
->b_cont
->b_rptr
=
434 (int)STATEP
->nbuttons
;
435 mp
->b_cont
->b_wptr
+= sizeof (int);
437 iocbp
->ioc_count
= sizeof (int);
438 mp
->b_datap
->db_type
= M_IOCACK
;
443 * New IOCTL support. Since it's explicitly mentioned
444 * that you can't add more ioctls to stream head's
445 * hard coded list, we have to do the transparent
446 * ioctl processing which is not very exciting.
448 case VUIDGWHEELCOUNT
:
450 case VUIDGWHEELSTATE
:
451 case VUIDSWHEELSTATE
:
452 case MSIOSRESOLUTION
:
453 error
= vuidmice_handle_wheel_resolution_ioctl(qp
,
458 miocnak(qp
, mp
, 0, error
);
462 putnext(qp
, mp
); /* nothing to process here */
467 } /* End of case M_IOCTL */
470 vuidmice_miocdata(qp
, mp
);
474 putnext(qp
, mp
); /* pass it on */
481 VUID_PUTNEXT(queue_t
*const qp
, uchar_t event_id
, uchar_t event_pair_type
,
482 uchar_t event_pair
, int event_value
)
489 * Give this event 3 chances to allocate blocks,
490 * otherwise discard this mouse event. 3 Strikes and you're out.
492 while ((bp
= allocb((int)sizeof (Firm_event
), BPRI_HI
)) == NULL
) {
498 fep
= (void *)bp
->b_wptr
;
499 fep
->id
= vuid_id_addr(VKEY_FIRST
) | vuid_id_offset(event_id
);
501 fep
->pair_type
= event_pair_type
;
502 fep
->pair
= event_pair
;
503 fep
->value
= event_value
;
504 uniqtime32(&fep
->time
);
505 bp
->b_wptr
+= sizeof (Firm_event
);
507 if (canput(qp
->q_next
))
510 (void) putbq(qp
, bp
); /* read side is blocked */
516 * M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO,
517 * VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION.
520 vuidmice_miocdata(queue_t
*qp
, mblk_t
*mp
)
522 struct copyresp
*copyresp
;
523 struct iocblk
*iocbp
;
526 Mouse_iocstate_t
*Mouseioc
;
531 copyresp
= (void *)mp
->b_rptr
;
532 iocbp
= (void *)mp
->b_rptr
;
534 if (copyresp
->cp_rval
) {
539 switch (copyresp
->cp_cmd
) {
540 case VUIDGWHEELCOUNT
:
541 mp
->b_datap
->db_type
= M_IOCACK
;
542 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct iocblk
);
543 iocbp
->ioc_error
= 0;
544 iocbp
->ioc_count
= 0;
546 if (mp
->b_cont
!= NULL
) {
553 case VUIDGWHEELSTATE
:
554 ioctmp
= copyresp
->cp_private
;
555 Mouseioc
= (void *)ioctmp
->b_rptr
;
556 if (Mouseioc
->ioc_state
== GETSTRUCT
) {
557 if (mp
->b_cont
== NULL
) {
563 if (copyresp
->cp_cmd
== VUIDGWHEELSTATE
) {
564 err
= vuidmice_service_wheel_state(qp
, datap
,
567 err
= vuidmice_service_wheel_info(datap
);
573 if (copyresp
->cp_cmd
== VUIDGWHEELSTATE
) {
574 size
= sizeof (wheel_state
);
576 size
= sizeof (wheel_info
);
579 Mouseioc
->ioc_state
= GETRESULT
;
580 ASSERT(Mouseioc
->u_addr
!= NULL
);
581 mcopyout(mp
, ioctmp
, size
, Mouseioc
->u_addr
, NULL
);
582 } else if (Mouseioc
->ioc_state
== GETRESULT
) {
584 mp
->b_datap
->db_type
= M_IOCACK
;
585 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct iocblk
);
586 iocbp
->ioc_error
= 0;
587 iocbp
->ioc_count
= 0;
589 if (mp
->b_cont
!= NULL
) {
596 case VUIDSWHEELSTATE
:
597 case MSIOSRESOLUTION
:
598 ioctmp
= copyresp
->cp_private
;
599 Mouseioc
= (void *)ioctmp
->b_rptr
;
600 if (mp
->b_cont
== NULL
) {
607 if (copyresp
->cp_cmd
== VUIDSWHEELSTATE
) {
608 err
= vuidmice_service_wheel_state(qp
,
609 datap
, VUIDSWHEELSTATE
);
621 iocbp
->ioc_count
= 0;
622 iocbp
->ioc_error
= 0;
624 mp
->b_datap
->db_type
= M_IOCACK
;
635 mp
->b_datap
->db_type
= M_IOCNAK
;
640 if (copyresp
->cp_private
) {
641 freemsg(copyresp
->cp_private
);
642 copyresp
->cp_private
= NULL
;
644 iocbp
->ioc_count
= 0;
645 iocbp
->ioc_error
= err
;
652 * vuidmice_handle_wheel_resolution_ioctl
653 * Handle wheel mouse and MSIOSRESOLUTION ioctls.
655 * Here we also support non-transparent way of these ioctls
656 * just like usb mouse driver does, so the consms module is
657 * very simple to deal with these ioctls.
660 vuidmice_handle_wheel_resolution_ioctl(queue_t
*qp
, mblk_t
*mp
, int cmd
)
663 Mouse_iocstate_t
*Mouseioc
;
669 struct iocblk
*iocbp
= (void *)mp
->b_rptr
;
671 if (iocbp
->ioc_count
== TRANSPARENT
) {
672 if (mp
->b_cont
== NULL
)
674 useraddr
= *((caddr_t
*)(void *)mp
->b_cont
->b_rptr
);
676 case VUIDGWHEELCOUNT
:
678 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
680 *((int *)(void *)datap
->b_wptr
) =
681 STATEP
->vuid_mouse_mode
;
682 mcopyout(mp
, NULL
, size
, NULL
, datap
);
687 size
= sizeof (wheel_info
);
690 case VUIDSWHEELSTATE
:
691 case VUIDGWHEELSTATE
:
692 size
= sizeof (wheel_state
);
695 case MSIOSRESOLUTION
:
696 size
= sizeof (Ms_screen_resolution
);
700 if ((ioctmp
= allocb(sizeof (Mouse_iocstate_t
),
703 Mouseioc
= (void *)ioctmp
->b_rptr
;
704 Mouseioc
->ioc_state
= GETSTRUCT
;
705 Mouseioc
->u_addr
= useraddr
;
706 ioctmp
->b_wptr
= ioctmp
->b_rptr
+ sizeof (Mouse_iocstate_t
);
707 mcopyin(mp
, ioctmp
, size
, NULL
);
713 case VUIDGWHEELCOUNT
:
718 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
) {
722 *((int *)(void *)datap
->b_wptr
) =
723 STATEP
->vuid_mouse_mode
;
724 datap
->b_wptr
+= sizeof (int);
729 if (mp
->b_cont
== NULL
||
730 iocbp
->ioc_count
!= sizeof (wheel_info
)) {
735 err
= vuidmice_service_wheel_info(datap
);
738 case VUIDSWHEELSTATE
:
739 case VUIDGWHEELSTATE
:
740 if (mp
->b_cont
== NULL
||
741 iocbp
->ioc_count
!= sizeof (wheel_state
)) {
746 err
= vuidmice_service_wheel_state(qp
, datap
, cmd
);
749 case MSIOSRESOLUTION
:
751 * Now we just make Xserver and
752 * the virtual mouse happy. Of course,
753 * the screen resolution value may
754 * be used later for absolute PS/2 mouse.
761 mp
->b_datap
->db_type
= M_IOCACK
;
763 iocbp
->ioc_error
= 0;
772 vuidmice_service_wheel_info(register mblk_t
*datap
)
777 wi
= (void *)datap
->b_rptr
;
778 if (wi
->vers
!= VUID_WHEEL_INFO_VERS
) {
783 if (wi
->id
> (VUIDMICE_NUM_WHEELS
- 1)) {
787 wi
->format
= (wi
->id
== VUIDMICE_VERTICAL_WHEEL_ID
) ?
788 VUID_WHEEL_FORMAT_VERTICAL
: VUID_WHEEL_FORMAT_HORIZONTAL
;
795 vuidmice_service_wheel_state(register queue_t
*qp
,
796 register mblk_t
*datap
,
802 ws
= (void *)datap
->b_rptr
;
803 if (ws
->vers
!= VUID_WHEEL_STATE_VERS
) {
808 if (ws
->id
> (VUIDMICE_NUM_WHEELS
- 1)) {
814 case VUIDGWHEELSTATE
:
816 (STATEP
->wheel_state_bf
>> ws
->id
) & 1;
819 case VUIDSWHEELSTATE
:
820 STATEP
->wheel_state_bf
= (ws
->stateflags
<< ws
->id
) |
821 (STATEP
->wheel_state_bf
& ~(1 << ws
->id
));