4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer as
12 * the first lines of this file unmodified.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * $FreeBSD: src/sys/dev/syscons/sysmouse.c,v 1.2.2.2 2001/07/16 05:21:24 yokota Exp $
31 /* MPSAFE NOTE: Take care with locking in sysmouse_event which is called
34 #include "opt_syscons.h"
36 #include <sys/param.h>
37 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/event.h>
43 #include <sys/vnode.h>
44 #include <sys/kernel.h>
45 #include <sys/thread2.h>
46 #include <sys/signalvar.h>
47 #include <sys/filio.h>
49 #include <machine/console.h>
50 #include <sys/mouse.h>
54 #ifndef SC_NO_SYSMOUSE
59 mouse_info_t buf
[FIFO_SIZE
];
65 struct sysmouse_state
{
66 struct event_fifo
*fifo
;
67 int level
; /* sysmouse protocol level */
68 mousestatus_t syncstatus
;
69 mousestatus_t readstatus
; /* Only needed for button status */
73 struct sigio
*sm_sigio
;
77 static d_open_t smopen
;
78 static d_close_t smclose
;
79 static d_read_t smread
;
80 static d_ioctl_t smioctl
;
81 static d_kqfilter_t smkqfilter
;
83 static struct dev_ops sm_ops
= {
84 { "sysmouse", 0, D_MPSAFE
},
89 .d_kqfilter
= smkqfilter
,
93 static struct sysmouse_state mouse_state
;
95 static int sysmouse_evtopkt(struct sysmouse_state
*sc
, mouse_info_t
*info
,
97 static void smqueue(struct sysmouse_state
*sc
, mouse_info_t
*info
);
98 static int pktlen(struct sysmouse_state
*sc
);
99 static void smfilter_detach(struct knote
*);
100 static int smfilter(struct knote
*, long);
101 static void smget(struct sysmouse_state
*sc
, mouse_info_t
*info
);
102 static void smpop(struct sysmouse_state
*sc
);
105 pktlen(struct sysmouse_state
*sc
)
114 smopen(struct dev_open_args
*ap
)
116 cdev_t dev
= ap
->a_head
.a_dev
;
117 struct sysmouse_state
*sc
= &mouse_state
;
120 DPRINTF(5, ("smopen: dev:%d,%d\n",
121 major(dev
), minor(dev
)));
123 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
125 sc
->fifo
= kmalloc(sizeof(struct event_fifo
),
126 M_SYSCONS
, M_WAITOK
| M_ZERO
);
130 bzero(&sc
->readstatus
, sizeof(sc
->readstatus
));
131 bzero(&sc
->syncstatus
, sizeof(sc
->syncstatus
));
136 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
142 smclose(struct dev_close_args
*ap
)
144 struct sysmouse_state
*sc
= &mouse_state
;
146 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
147 funsetown(&sc
->sm_sigio
);
151 kfree(sc
->fifo
, M_SYSCONS
);
153 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
159 smread(struct dev_read_args
*ap
)
161 struct sysmouse_state
*sc
= &mouse_state
;
162 mousestatus_t backupstatus
;
165 struct uio
*uio
= ap
->a_uio
;
166 int error
= 0, val
, cnt
= 0;
168 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
169 while (sc
->fifo
->fill
<= 0) {
170 /* Buffer too small to fit a complete mouse packet */
171 if (uio
->uio_resid
< pktlen(sc
)) {
175 if (ap
->a_ioflag
& IO_NDELAY
) {
179 error
= lksleep(sc
, &sc
->sm_lock
, PCATCH
, "smread", 0);
180 if (error
== EINTR
|| error
== ERESTART
) {
186 /* Buffer too small to fit a complete mouse packet */
187 if (uio
->uio_resid
< pktlen(sc
)) {
192 backupstatus
= sc
->readstatus
;
193 val
= sysmouse_evtopkt(sc
, &info
, buf
);
195 error
= uiomove(buf
, val
, uio
);
197 sc
->readstatus
= backupstatus
;
203 } while (sc
->fifo
->fill
> 0);
206 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
207 if (cnt
> 0 && error
!= EFAULT
)
213 smioctl(struct dev_ioctl_args
*ap
)
215 struct sysmouse_state
*sc
= &mouse_state
;
221 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
222 fsetown(*(int *)ap
->a_data
, &sc
->sm_sigio
);
223 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
226 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
227 *(int *)ap
->a_data
= fgetown(&sc
->sm_sigio
);
228 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
231 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
232 if (*(int *)ap
->a_data
) {
237 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
239 case MOUSE_GETHWINFO
: /* get device information */
240 hw
= (mousehw_t
*)ap
->a_data
;
241 hw
->buttons
= 10; /* XXX unknown */
242 hw
->iftype
= MOUSE_IF_SYSMOUSE
;
243 hw
->type
= MOUSE_MOUSE
;
244 hw
->model
= MOUSE_MODEL_GENERIC
;
248 case MOUSE_GETMODE
: /* get protocol/mode */
249 mode
= (mousemode_t
*)ap
->a_data
;
250 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
251 mode
->level
= sc
->level
;
252 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
253 switch (mode
->level
) {
254 case 0: /* emulate MouseSystems protocol */
255 mode
->protocol
= MOUSE_PROTO_MSC
;
256 mode
->rate
= -1; /* unknown */
257 mode
->resolution
= -1; /* unknown */
258 mode
->accelfactor
= 0; /* disabled */
259 mode
->packetsize
= MOUSE_MSC_PACKETSIZE
;
260 mode
->syncmask
[0] = MOUSE_MSC_SYNCMASK
;
261 mode
->syncmask
[1] = MOUSE_MSC_SYNC
;
264 case 1: /* sysmouse protocol */
265 mode
->protocol
= MOUSE_PROTO_SYSMOUSE
;
267 mode
->resolution
= -1;
268 mode
->accelfactor
= 0;
269 mode
->packetsize
= MOUSE_SYS_PACKETSIZE
;
270 mode
->syncmask
[0] = MOUSE_SYS_SYNCMASK
;
271 mode
->syncmask
[1] = MOUSE_SYS_SYNC
;
276 case MOUSE_SETMODE
: /* set protocol/mode */
277 mode
= (mousemode_t
*)ap
->a_data
;
278 if (mode
->level
== -1)
279 ; /* don't change the current setting */
280 else if ((mode
->level
< 0) || (mode
->level
> 1)) {
283 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
284 sc
->level
= mode
->level
;
285 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
289 case MOUSE_GETLEVEL
: /* get operation level */
290 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
291 *(int *)ap
->a_data
= sc
->level
;
292 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
295 case MOUSE_SETLEVEL
: /* set operation level */
296 if ((*(int *)ap
->a_data
< 0) || (*(int *)ap
->a_data
> 1)) {
299 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
300 sc
->level
= *(int *)ap
->a_data
;
301 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
304 case MOUSE_GETSTATUS
: /* get accumulated mouse events */
305 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
306 *(mousestatus_t
*)ap
->a_data
= sc
->syncstatus
;
307 sc
->syncstatus
.flags
= 0;
308 sc
->syncstatus
.obutton
= sc
->syncstatus
.button
;
309 sc
->syncstatus
.dx
= 0;
310 sc
->syncstatus
.dy
= 0;
311 sc
->syncstatus
.dz
= 0;
312 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
316 case MOUSE_GETVARS
: /* get internal mouse variables */
317 case MOUSE_SETVARS
: /* set internal mouse variables */
321 case MOUSE_READSTATE
: /* read status from the device */
322 case MOUSE_READDATA
: /* read data from the device */
329 static struct filterops smfiltops
=
330 { FILTEROP_MPSAFE
| FILTEROP_ISFD
, NULL
, smfilter_detach
, smfilter
};
333 smkqfilter(struct dev_kqfilter_args
*ap
)
335 struct sysmouse_state
*sc
= &mouse_state
;
336 struct knote
*kn
= ap
->a_kn
;
341 switch (kn
->kn_filter
) {
343 kn
->kn_fop
= &smfiltops
;
344 kn
->kn_hook
= (caddr_t
)sc
;
347 ap
->a_result
= EOPNOTSUPP
;
351 klist
= &sc
->rkq
.ki_note
;
352 knote_insert(klist
, kn
);
358 smfilter_detach(struct knote
*kn
)
360 struct sysmouse_state
*sc
= &mouse_state
;
363 klist
= &sc
->rkq
.ki_note
;
364 knote_remove(klist
, kn
);
368 smfilter(struct knote
*kn
, long hint
)
370 struct sysmouse_state
*sc
= &mouse_state
;
373 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
374 if (sc
->fifo
->fill
> 0) {
378 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
384 smqueue(struct sysmouse_state
*sc
, mouse_info_t
*info
)
386 struct event_fifo
*f
= sc
->fifo
;
388 if (f
->fill
>= FIFO_SIZE
) {
390 f
->buf
[f
->start
] = *info
;
391 f
->start
= (f
->start
+ 1) % FIFO_SIZE
;
394 f
->buf
[(f
->start
+ f
->fill
) % FIFO_SIZE
] = *info
;
401 smget(struct sysmouse_state
*sc
, mouse_info_t
*info
)
403 struct event_fifo
*f
= sc
->fifo
;
406 *info
= f
->buf
[f
->start
];
410 smpop(struct sysmouse_state
*sc
)
412 struct event_fifo
*f
= sc
->fifo
;
416 f
->start
= (f
->start
+ 1) % FIFO_SIZE
;
421 sm_attach_mouse(void *unused
)
423 struct sysmouse_state
*sc
= &mouse_state
;
426 lockinit(&mouse_state
.sm_lock
, "sysmouse", 0, LK_CANRECURSE
);
429 dev
= make_dev(&sm_ops
, 0, UID_ROOT
, GID_WHEEL
, 0600, "sysmouse");
432 SYSINIT(sysmouse
, SI_SUB_DRIVERS
, SI_ORDER_ANY
, sm_attach_mouse
, NULL
);
435 sysmouse_updatestatus(mousestatus_t
*status
, mouse_info_t
*info
)
439 status
->obutton
= status
->button
;
441 switch (info
->operation
) {
443 status
->button
= info
->u
.data
.buttons
;
445 case MOUSE_MOTION_EVENT
:
450 case MOUSE_BUTTON_EVENT
:
452 if (info
->u
.event
.value
> 0)
453 status
->button
|= info
->u
.event
.id
;
455 status
->button
&= ~info
->u
.event
.id
;
464 status
->flags
|= ((x
|| y
|| z
) ? MOUSE_POSCHANGED
: 0)
465 | (status
->obutton
^ status
->button
);
470 /* Requires buf to hold at least 8 bytes, returns number of bytes written */
472 sysmouse_evtopkt(struct sysmouse_state
*sc
, mouse_info_t
*info
, u_char
*buf
)
474 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
475 static int butmap
[8] = {
476 MOUSE_MSC_BUTTON1UP
| MOUSE_MSC_BUTTON2UP
| MOUSE_MSC_BUTTON3UP
,
477 MOUSE_MSC_BUTTON2UP
| MOUSE_MSC_BUTTON3UP
,
478 MOUSE_MSC_BUTTON1UP
| MOUSE_MSC_BUTTON3UP
,
480 MOUSE_MSC_BUTTON1UP
| MOUSE_MSC_BUTTON2UP
,
487 sc
->readstatus
.dx
= 0;
488 sc
->readstatus
.dy
= 0;
489 sc
->readstatus
.dz
= 0;
490 sc
->readstatus
.flags
= 0;
491 if (sysmouse_updatestatus(&sc
->readstatus
, info
) == 0)
494 /* We aren't using the sc->readstatus.dx/dy/dz values */
496 if (sc
->readstatus
.flags
== 0)
499 x
= (info
->operation
== MOUSE_BUTTON_EVENT
? 0 : info
->u
.data
.x
);
500 y
= (info
->operation
== MOUSE_BUTTON_EVENT
? 0 : info
->u
.data
.y
);
501 z
= (info
->operation
== MOUSE_BUTTON_EVENT
? 0 : info
->u
.data
.z
);
503 /* the first five bytes are compatible with MouseSystems' */
504 buf
[0] = MOUSE_MSC_SYNC
505 | butmap
[sc
->readstatus
.button
& MOUSE_STDBUTTONS
];
506 x
= imax(imin(x
, 255), -256);
509 y
= -imax(imin(y
, 255), -256);
512 if (sc
->level
>= 1) {
514 z
= imax(imin(z
, 127), -128);
515 buf
[5] = (z
>> 1) & 0x7f;
516 buf
[6] = (z
- (z
>> 1)) & 0x7f;
518 buf
[7] = (~sc
->readstatus
.button
>> 3) & 0x7f;
528 sysmouse_event(mouse_info_t
*info
)
530 struct sysmouse_state
*sc
= &mouse_state
;
533 lockmgr(&sc
->sm_lock
, LK_EXCLUSIVE
);
534 ret
= sysmouse_updatestatus(&sc
->syncstatus
, info
);
536 ret
= sc
->syncstatus
.flags
;
538 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
542 switch (info
->operation
) {
544 case MOUSE_MOTION_EVENT
:
545 case MOUSE_BUTTON_EVENT
:
548 pgsigio(sc
->sm_sigio
, SIGIO
, 0);
549 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
551 KNOTE(&sc
->rkq
.ki_note
, 0);
554 lockmgr(&sc
->sm_lock
, LK_RELEASE
);
561 #endif /* !SC_NO_SYSMOUSE */