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
*, dev_t
*, int, int, cred_t
*);
52 static int vuidmice_close(queue_t
*, int, cred_t
*);
53 static int vuidmice_rput(queue_t
*, mblk_t
*);
54 static int vuidmice_rsrv(queue_t
*);
55 static int vuidmice_wput(queue_t
*, mblk_t
*);
56 static void vuidmice_miocdata(queue_t
*, mblk_t
*);
57 static int vuidmice_handle_wheel_resolution_ioctl(queue_t
*, mblk_t
*, int);
59 static int vuidmice_service_wheel_info(mblk_t
*);
60 static int vuidmice_service_wheel_state(queue_t
*, mblk_t
*, uint_t
);
62 void VUID_QUEUE(queue_t
*const, mblk_t
*);
63 int VUID_OPEN(queue_t
*const);
64 void VUID_CLOSE(queue_t
*const);
66 static kmutex_t vuidmice_lock
;
68 static struct module_info vuidmice_iinfo
= {
77 static struct qinit vuidmice_rinit
= {
87 static struct module_info vuidmice_oinfo
= {
96 static struct qinit vuidmice_winit
= {
106 struct streamtab vuidmice_info
= {
114 * This is the loadable module wrapper.
118 * D_MTQPAIR effectively makes the module single threaded.
119 * There can be only one thread active in the module at any time.
120 * It may be a read or write thread.
122 #define VUIDMICE_CONF_FLAG (D_MP | D_MTQPAIR)
124 static struct fmodsw fsw
= {
130 static struct modlstrmod modlstrmod
= {
132 "mouse events to vuid events",
137 * Module linkage information for the kernel.
139 static struct modlinkage modlinkage
= {
145 static int module_open
= 0; /* allow only one open of this module */
152 mutex_init(&vuidmice_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
153 if ((rc
= mod_install(&modlinkage
)) != 0) {
154 mutex_destroy(&vuidmice_lock
);
164 if ((rc
= mod_remove(&modlinkage
)) == 0)
165 mutex_destroy(&vuidmice_lock
);
170 _info(struct modinfo
*modinfop
)
172 return (mod_info(&modlinkage
, modinfop
));
178 vuidmice_open(queue_t
*qp
, dev_t
*devp
, int oflag
, int sflag
, cred_t
*crp
)
180 if (qp
->q_ptr
!= NULL
)
181 return (0); /* reopen */
183 mutex_enter(&vuidmice_lock
);
185 /* Allow only 1 open of this module */
187 mutex_exit(&vuidmice_lock
);
192 mutex_exit(&vuidmice_lock
);
195 * Both the read and write queues share the same state structures.
197 qp
->q_ptr
= kmem_zalloc(sizeof (struct MouseStateInfo
), KM_SLEEP
);
198 WR(qp
)->q_ptr
= qp
->q_ptr
;
200 /* initialize state */
201 STATEP
->format
= VUID_NATIVE
;
206 if (VUID_OPEN(qp
) != 0) {
209 mutex_enter(&vuidmice_lock
);
211 mutex_exit(&vuidmice_lock
);
212 kmem_free(qp
->q_ptr
, sizeof (struct MouseStateInfo
));
223 vuidmice_close(queue_t
*qp
, int flag
, cred_t
*crp
)
228 flushq(qp
, FLUSHALL
);
229 flushq(OTHERQ(qp
), FLUSHALL
);
234 mutex_enter(&vuidmice_lock
);
236 mutex_exit(&vuidmice_lock
);
237 kmem_free(qp
->q_ptr
, sizeof (struct MouseStateInfo
));
244 * Put procedure for input from driver end of stream (read queue).
247 vuidmice_rput(queue_t
*const qp
, mblk_t
*mp
)
253 * Handle all the related high priority messages here, hence
254 * should spend the least amount of time here.
257 if (DB_TYPE(mp
) == M_DATA
) {
258 if ((int)STATEP
->format
== VUID_FIRM_EVENT
)
259 return (putq(qp
, mp
)); /* queue message & return */
260 } else if (DB_TYPE(mp
) == M_FLUSH
) {
261 if (*mp
->b_rptr
& FLUSHR
)
262 flushq(qp
, FLUSHALL
);
265 putnext(qp
, mp
); /* pass it on */
270 vuidmice_rsrv(queue_t
*const qp
)
276 while ((mp
= getq(qp
)) != NULL
) {
277 ASSERT(DB_TYPE(mp
) == M_DATA
);
280 return (putbq(qp
, mp
)); /* read side is blocked */
282 switch (DB_TYPE(mp
)) {
284 if ((int)STATEP
->format
== VUID_FIRM_EVENT
)
285 (void) VUID_QUEUE(qp
, mp
);
287 (void) putnext(qp
, mp
);
292 "vuidmice_rsrv: bad message type (0x%x)\n",
295 (void) putnext(qp
, mp
);
303 * Put procedure for write from user end of stream (write queue).
306 vuidmice_wput(queue_t
*const qp
, mblk_t
*mp
)
314 * Handle all the related high priority messages here, hence
315 * should spend the least amount of time here.
317 switch (DB_TYPE(mp
)) { /* handle hi pri messages here */
319 if (*mp
->b_rptr
& FLUSHW
)
320 flushq(qp
, FLUSHALL
);
321 putnext(qp
, mp
); /* pass it on */
325 struct iocblk
*iocbp
= (void *)mp
->b_rptr
;
327 switch (iocbp
->ioc_cmd
) {
331 * VUIDSFORMAT is known to the stream head and thus
332 * is guaranteed to be an I_STR ioctl.
334 if (iocbp
->ioc_count
== TRANSPARENT
) {
335 miocnak(qp
, mp
, 0, EINVAL
);
340 error
= miocpullup(mp
, sizeof (int));
342 miocnak(qp
, mp
, 0, error
);
347 *(int *)(void *)mp
->b_cont
->b_rptr
;
348 STATEP
->format
= (uchar_t
)format_type
;
350 iocbp
->ioc_count
= 0;
351 iocbp
->ioc_error
= 0;
352 mp
->b_datap
->db_type
= M_IOCACK
;
355 /* return buffer to pool ASAP */
366 /* return buffer to pool ASAP */
368 freemsg(mp
->b_cont
); /* over written below */
373 * VUIDGFORMAT is known to the stream head and thus
374 * is guaranteed to be an I_STR ioctl.
376 if (iocbp
->ioc_count
== TRANSPARENT
) {
377 miocnak(qp
, mp
, 0, EINVAL
);
381 mp
->b_cont
= allocb(sizeof (int), BPRI_MED
);
382 if (mp
->b_cont
== NULL
) {
383 miocnak(qp
, mp
, 0, EAGAIN
);
387 *(int *)(void *)mp
->b_cont
->b_rptr
=
389 mp
->b_cont
->b_wptr
+= sizeof (int);
391 iocbp
->ioc_count
= sizeof (int);
392 mp
->b_datap
->db_type
= M_IOCACK
;
399 miocnak(qp
, mp
, 0, ENOTTY
);
403 /* return buffer to pool ASAP */
405 freemsg(mp
->b_cont
); /* over written below */
410 * MSIOBUTTONS is known to streamio.c and this
411 * is assume to be non-I_STR & non-TRANSPARENT ioctl
414 if (iocbp
->ioc_count
== TRANSPARENT
) {
415 miocnak(qp
, mp
, 0, EINVAL
);
419 if (STATEP
->nbuttons
== 0) {
420 miocnak(qp
, mp
, 0, EINVAL
);
424 mp
->b_cont
= allocb(sizeof (int), BPRI_MED
);
425 if (mp
->b_cont
== NULL
) {
426 miocnak(qp
, mp
, 0, EAGAIN
);
430 *(int *)(void *)mp
->b_cont
->b_rptr
=
431 (int)STATEP
->nbuttons
;
432 mp
->b_cont
->b_wptr
+= sizeof (int);
434 iocbp
->ioc_count
= sizeof (int);
435 mp
->b_datap
->db_type
= M_IOCACK
;
440 * New IOCTL support. Since it's explicitly mentioned
441 * that you can't add more ioctls to stream head's
442 * hard coded list, we have to do the transparent
443 * ioctl processing which is not very exciting.
445 case VUIDGWHEELCOUNT
:
447 case VUIDGWHEELSTATE
:
448 case VUIDSWHEELSTATE
:
449 case MSIOSRESOLUTION
:
450 error
= vuidmice_handle_wheel_resolution_ioctl(qp
,
455 miocnak(qp
, mp
, 0, error
);
459 putnext(qp
, mp
); /* nothing to process here */
464 } /* End of case M_IOCTL */
467 vuidmice_miocdata(qp
, mp
);
471 putnext(qp
, mp
); /* pass it on */
478 VUID_PUTNEXT(queue_t
*const qp
, uchar_t event_id
, uchar_t event_pair_type
,
479 uchar_t event_pair
, int event_value
)
486 * Give this event 3 chances to allocate blocks,
487 * otherwise discard this mouse event. 3 Strikes and you're out.
489 while ((bp
= allocb((int)sizeof (Firm_event
), BPRI_HI
)) == NULL
) {
495 fep
= (void *)bp
->b_wptr
;
496 fep
->id
= vuid_id_addr(VKEY_FIRST
) | vuid_id_offset(event_id
);
498 fep
->pair_type
= event_pair_type
;
499 fep
->pair
= event_pair
;
500 fep
->value
= event_value
;
501 uniqtime32(&fep
->time
);
502 bp
->b_wptr
+= sizeof (Firm_event
);
504 if (canput(qp
->q_next
))
507 (void) putbq(qp
, bp
); /* read side is blocked */
513 * M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO,
514 * VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION.
517 vuidmice_miocdata(queue_t
*qp
, mblk_t
*mp
)
519 struct copyresp
*copyresp
;
520 struct iocblk
*iocbp
;
523 Mouse_iocstate_t
*Mouseioc
;
528 copyresp
= (void *)mp
->b_rptr
;
529 iocbp
= (void *)mp
->b_rptr
;
531 if (copyresp
->cp_rval
) {
536 switch (copyresp
->cp_cmd
) {
537 case VUIDGWHEELCOUNT
:
538 mp
->b_datap
->db_type
= M_IOCACK
;
539 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct iocblk
);
540 iocbp
->ioc_error
= 0;
541 iocbp
->ioc_count
= 0;
543 if (mp
->b_cont
!= NULL
) {
550 case VUIDGWHEELSTATE
:
551 ioctmp
= copyresp
->cp_private
;
552 Mouseioc
= (void *)ioctmp
->b_rptr
;
553 if (Mouseioc
->ioc_state
== GETSTRUCT
) {
554 if (mp
->b_cont
== NULL
) {
560 if (copyresp
->cp_cmd
== VUIDGWHEELSTATE
) {
561 err
= vuidmice_service_wheel_state(qp
, datap
,
564 err
= vuidmice_service_wheel_info(datap
);
570 if (copyresp
->cp_cmd
== VUIDGWHEELSTATE
) {
571 size
= sizeof (wheel_state
);
573 size
= sizeof (wheel_info
);
576 Mouseioc
->ioc_state
= GETRESULT
;
577 ASSERT(Mouseioc
->u_addr
!= NULL
);
578 mcopyout(mp
, ioctmp
, size
, Mouseioc
->u_addr
, NULL
);
579 } else if (Mouseioc
->ioc_state
== GETRESULT
) {
581 mp
->b_datap
->db_type
= M_IOCACK
;
582 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct iocblk
);
583 iocbp
->ioc_error
= 0;
584 iocbp
->ioc_count
= 0;
586 if (mp
->b_cont
!= NULL
) {
593 case VUIDSWHEELSTATE
:
594 case MSIOSRESOLUTION
:
595 ioctmp
= copyresp
->cp_private
;
596 Mouseioc
= (void *)ioctmp
->b_rptr
;
597 if (mp
->b_cont
== NULL
) {
604 if (copyresp
->cp_cmd
== VUIDSWHEELSTATE
) {
605 err
= vuidmice_service_wheel_state(qp
,
606 datap
, VUIDSWHEELSTATE
);
618 iocbp
->ioc_count
= 0;
619 iocbp
->ioc_error
= 0;
621 mp
->b_datap
->db_type
= M_IOCACK
;
632 mp
->b_datap
->db_type
= M_IOCNAK
;
637 if (copyresp
->cp_private
) {
638 freemsg(copyresp
->cp_private
);
639 copyresp
->cp_private
= NULL
;
641 iocbp
->ioc_count
= 0;
642 iocbp
->ioc_error
= err
;
649 * vuidmice_handle_wheel_resolution_ioctl
650 * Handle wheel mouse and MSIOSRESOLUTION ioctls.
652 * Here we also support non-transparent way of these ioctls
653 * just like usb mouse driver does, so the consms module is
654 * very simple to deal with these ioctls.
657 vuidmice_handle_wheel_resolution_ioctl(queue_t
*qp
, mblk_t
*mp
, int cmd
)
660 Mouse_iocstate_t
*Mouseioc
;
666 struct iocblk
*iocbp
= (void *)mp
->b_rptr
;
668 if (iocbp
->ioc_count
== TRANSPARENT
) {
669 if (mp
->b_cont
== NULL
)
671 useraddr
= *((caddr_t
*)(void *)mp
->b_cont
->b_rptr
);
673 case VUIDGWHEELCOUNT
:
675 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
677 *((int *)(void *)datap
->b_wptr
) =
678 STATEP
->vuid_mouse_mode
;
679 mcopyout(mp
, NULL
, size
, NULL
, datap
);
684 size
= sizeof (wheel_info
);
687 case VUIDSWHEELSTATE
:
688 case VUIDGWHEELSTATE
:
689 size
= sizeof (wheel_state
);
692 case MSIOSRESOLUTION
:
693 size
= sizeof (Ms_screen_resolution
);
697 if ((ioctmp
= allocb(sizeof (Mouse_iocstate_t
),
700 Mouseioc
= (void *)ioctmp
->b_rptr
;
701 Mouseioc
->ioc_state
= GETSTRUCT
;
702 Mouseioc
->u_addr
= useraddr
;
703 ioctmp
->b_wptr
= ioctmp
->b_rptr
+ sizeof (Mouse_iocstate_t
);
704 mcopyin(mp
, ioctmp
, size
, NULL
);
710 case VUIDGWHEELCOUNT
:
715 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
) {
719 *((int *)(void *)datap
->b_wptr
) =
720 STATEP
->vuid_mouse_mode
;
721 datap
->b_wptr
+= sizeof (int);
726 if (mp
->b_cont
== NULL
||
727 iocbp
->ioc_count
!= sizeof (wheel_info
)) {
732 err
= vuidmice_service_wheel_info(datap
);
735 case VUIDSWHEELSTATE
:
736 case VUIDGWHEELSTATE
:
737 if (mp
->b_cont
== NULL
||
738 iocbp
->ioc_count
!= sizeof (wheel_state
)) {
743 err
= vuidmice_service_wheel_state(qp
, datap
, cmd
);
746 case MSIOSRESOLUTION
:
748 * Now we just make Xserver and
749 * the virtual mouse happy. Of course,
750 * the screen resolution value may
751 * be used later for absolute PS/2 mouse.
758 mp
->b_datap
->db_type
= M_IOCACK
;
760 iocbp
->ioc_error
= 0;
769 vuidmice_service_wheel_info(register mblk_t
*datap
)
774 wi
= (void *)datap
->b_rptr
;
775 if (wi
->vers
!= VUID_WHEEL_INFO_VERS
) {
780 if (wi
->id
> (VUIDMICE_NUM_WHEELS
- 1)) {
784 wi
->format
= (wi
->id
== VUIDMICE_VERTICAL_WHEEL_ID
) ?
785 VUID_WHEEL_FORMAT_VERTICAL
: VUID_WHEEL_FORMAT_HORIZONTAL
;
792 vuidmice_service_wheel_state(register queue_t
*qp
,
793 register mblk_t
*datap
,
799 ws
= (void *)datap
->b_rptr
;
800 if (ws
->vers
!= VUID_WHEEL_STATE_VERS
) {
805 if (ws
->id
> (VUIDMICE_NUM_WHEELS
- 1)) {
811 case VUIDGWHEELSTATE
:
813 (STATEP
->wheel_state_bf
>> ws
->id
) & 1;
816 case VUIDSWHEELSTATE
:
817 STATEP
->wheel_state_bf
= (ws
->stateflags
<< ws
->id
) |
818 (STATEP
->wheel_state_bf
& ~(1 << ws
->id
));