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"
35 #include "opt_evdev.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/event.h>
44 #include <sys/vnode.h>
45 #include <sys/kernel.h>
46 #include <sys/signalvar.h>
47 #include <sys/filio.h>
49 #include <machine/console.h>
50 #include <sys/mouse.h>
53 #include <dev/misc/evdev/input.h>
54 #include <dev/misc/evdev/evdev.h>
59 #ifndef SC_NO_SYSMOUSE
64 mouse_info_t buf[FIFO_SIZE];
70 struct sysmouse_state {
71 struct event_fifo *fifo;
72 int level; /* sysmouse protocol level */
73 mousestatus_t syncstatus;
74 mousestatus_t readstatus; /* Only needed for button status */
78 struct sigio *sm_sigio;
82 static d_open_t smopen;
83 static d_close_t smclose;
84 static d_read_t smread;
85 static d_ioctl_t smioctl;
86 static d_kqfilter_t smkqfilter;
88 static struct dev_ops sm_ops = {
89 { "sysmouse", 0, D_MPSAFE },
94 .d_kqfilter = smkqfilter,
98 static struct sysmouse_state mouse_state;
100 static int sysmouse_evtopkt(struct sysmouse_state *sc, mouse_info_t *info,
102 static void smqueue(struct sysmouse_state *sc, mouse_info_t *info);
103 static int pktlen(struct sysmouse_state *sc);
104 static void smfilter_detach(struct knote *);
105 static int smfilter(struct knote *, long);
106 static void smget(struct sysmouse_state *sc, mouse_info_t *info);
107 static void smpop(struct sysmouse_state *sc);
110 static struct evdev_dev *sysmouse_evdev;
113 smdev_evdev_init(void)
117 sysmouse_evdev = evdev_alloc();
118 evdev_set_name(sysmouse_evdev, "System mouse");
119 evdev_set_phys(sysmouse_evdev, "sysmouse");
120 evdev_set_id(sysmouse_evdev, BUS_VIRTUAL, 0, 0, 0);
121 evdev_support_prop(sysmouse_evdev, INPUT_PROP_POINTER);
122 evdev_support_event(sysmouse_evdev, EV_SYN);
123 evdev_support_event(sysmouse_evdev, EV_REL);
124 evdev_support_event(sysmouse_evdev, EV_KEY);
125 evdev_support_rel(sysmouse_evdev, REL_X);
126 evdev_support_rel(sysmouse_evdev, REL_Y);
127 evdev_support_rel(sysmouse_evdev, REL_WHEEL);
128 evdev_support_rel(sysmouse_evdev, REL_HWHEEL);
129 for (i = 0; i < 8; i++)
130 evdev_support_key(sysmouse_evdev, BTN_MOUSE + i);
131 if (evdev_register(sysmouse_evdev)) {
132 evdev_free(sysmouse_evdev);
133 sysmouse_evdev = NULL;
138 smdev_evdev_write(int x, int y, int z, int buttons)
141 if (sysmouse_evdev == NULL || !(evdev_rcpt_mask & EVDEV_RCPT_SYSMOUSE))
144 evdev_push_event(sysmouse_evdev, EV_REL, REL_X, x);
145 evdev_push_event(sysmouse_evdev, EV_REL, REL_Y, y);
146 switch (evdev_sysmouse_t_axis) {
147 case EVDEV_SYSMOUSE_T_AXIS_PSM:
151 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z);
155 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z / 2);
159 case EVDEV_SYSMOUSE_T_AXIS_UMS:
160 if (buttons & (1 << 6))
161 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, 1);
162 else if (buttons & (1 << 5))
163 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, -1);
164 buttons &= ~((1 << 5)|(1 << 6));
166 case EVDEV_SYSMOUSE_T_AXIS_NONE:
168 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z);
170 evdev_push_mouse_btn(sysmouse_evdev, buttons);
171 evdev_sync(sysmouse_evdev);
176 pktlen(struct sysmouse_state *sc)
185 smopen(struct dev_open_args *ap)
187 cdev_t dev = ap->a_head.a_dev;
188 struct sysmouse_state *sc = &mouse_state;
191 DPRINTF(5, ("smopen: dev:%d,%d\n",
192 major(dev), minor(dev)));
194 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
196 sc->fifo = kmalloc(sizeof(struct event_fifo),
197 M_SYSCONS, M_WAITOK | M_ZERO);
201 bzero(&sc->readstatus, sizeof(sc->readstatus));
202 bzero(&sc->syncstatus, sizeof(sc->syncstatus));
207 lockmgr(&sc->sm_lock, LK_RELEASE);
213 smclose(struct dev_close_args *ap)
215 struct sysmouse_state *sc = &mouse_state;
217 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
218 funsetown(&sc->sm_sigio);
222 kfree(sc->fifo, M_SYSCONS);
224 lockmgr(&sc->sm_lock, LK_RELEASE);
230 smread(struct dev_read_args *ap)
232 struct sysmouse_state *sc = &mouse_state;
233 mousestatus_t backupstatus;
236 struct uio *uio = ap->a_uio;
237 int error = 0, val, cnt = 0;
239 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
240 while (sc->fifo->fill <= 0) {
241 /* Buffer too small to fit a complete mouse packet */
242 if (uio->uio_resid < pktlen(sc)) {
246 if (ap->a_ioflag & IO_NDELAY) {
250 error = lksleep(sc, &sc->sm_lock, PCATCH, "smread", 0);
251 if (error == EINTR || error == ERESTART) {
257 /* Buffer too small to fit a complete mouse packet */
258 if (uio->uio_resid < pktlen(sc)) {
263 backupstatus = sc->readstatus;
264 val = sysmouse_evtopkt(sc, &info, buf);
266 error = uiomove(buf, val, uio);
268 sc->readstatus = backupstatus;
274 } while (sc->fifo->fill > 0);
277 lockmgr(&sc->sm_lock, LK_RELEASE);
278 if (cnt > 0 && error != EFAULT)
284 smioctl(struct dev_ioctl_args *ap)
286 struct sysmouse_state *sc = &mouse_state;
292 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
293 fsetown(*(int *)ap->a_data, &sc->sm_sigio);
294 lockmgr(&sc->sm_lock, LK_RELEASE);
297 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
298 *(int *)ap->a_data = fgetown(&sc->sm_sigio);
299 lockmgr(&sc->sm_lock, LK_RELEASE);
302 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
303 if (*(int *)ap->a_data) {
308 lockmgr(&sc->sm_lock, LK_RELEASE);
310 case MOUSE_GETHWINFO: /* get device information */
311 hw = (mousehw_t *)ap->a_data;
312 hw->buttons = 10; /* XXX unknown */
313 hw->iftype = MOUSE_IF_SYSMOUSE;
314 hw->type = MOUSE_MOUSE;
315 hw->model = MOUSE_MODEL_GENERIC;
319 case MOUSE_GETMODE: /* get protocol/mode */
320 mode = (mousemode_t *)ap->a_data;
321 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
322 mode->level = sc->level;
323 lockmgr(&sc->sm_lock, LK_RELEASE);
324 switch (mode->level) {
325 case 0: /* emulate MouseSystems protocol */
326 mode->protocol = MOUSE_PROTO_MSC;
327 mode->rate = -1; /* unknown */
328 mode->resolution = -1; /* unknown */
329 mode->accelfactor = 0; /* disabled */
330 mode->packetsize = MOUSE_MSC_PACKETSIZE;
331 mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
332 mode->syncmask[1] = MOUSE_MSC_SYNC;
335 case 1: /* sysmouse protocol */
336 mode->protocol = MOUSE_PROTO_SYSMOUSE;
338 mode->resolution = -1;
339 mode->accelfactor = 0;
340 mode->packetsize = MOUSE_SYS_PACKETSIZE;
341 mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
342 mode->syncmask[1] = MOUSE_SYS_SYNC;
347 case MOUSE_SETMODE: /* set protocol/mode */
348 mode = (mousemode_t *)ap->a_data;
349 if (mode->level == -1)
350 ; /* don't change the current setting */
351 else if ((mode->level < 0) || (mode->level > 1)) {
354 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
355 sc->level = mode->level;
356 lockmgr(&sc->sm_lock, LK_RELEASE);
360 case MOUSE_GETLEVEL: /* get operation level */
361 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
362 *(int *)ap->a_data = sc->level;
363 lockmgr(&sc->sm_lock, LK_RELEASE);
366 case MOUSE_SETLEVEL: /* set operation level */
367 if ((*(int *)ap->a_data < 0) || (*(int *)ap->a_data > 1)) {
370 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
371 sc->level = *(int *)ap->a_data;
372 lockmgr(&sc->sm_lock, LK_RELEASE);
375 case MOUSE_GETSTATUS: /* get accumulated mouse events */
376 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
377 *(mousestatus_t *)ap->a_data = sc->syncstatus;
378 sc->syncstatus.flags = 0;
379 sc->syncstatus.obutton = sc->syncstatus.button;
380 sc->syncstatus.dx = 0;
381 sc->syncstatus.dy = 0;
382 sc->syncstatus.dz = 0;
383 lockmgr(&sc->sm_lock, LK_RELEASE);
386 case MOUSE_READSTATE: /* read status from the device */
387 case MOUSE_READDATA: /* read data from the device */
394 static struct filterops smfiltops =
395 { FILTEROP_MPSAFE | FILTEROP_ISFD, NULL, smfilter_detach, smfilter };
398 smkqfilter(struct dev_kqfilter_args *ap)
400 struct sysmouse_state *sc = &mouse_state;
401 struct knote *kn = ap->a_kn;
406 switch (kn->kn_filter) {
408 kn->kn_fop = &smfiltops;
409 kn->kn_hook = (caddr_t)sc;
412 ap->a_result = EOPNOTSUPP;
416 klist = &sc->rkq.ki_note;
417 knote_insert(klist, kn);
423 smfilter_detach(struct knote *kn)
425 struct sysmouse_state *sc = &mouse_state;
428 klist = &sc->rkq.ki_note;
429 knote_remove(klist, kn);
433 smfilter(struct knote *kn, long hint)
435 struct sysmouse_state *sc = &mouse_state;
438 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
439 if (sc->fifo->fill > 0) {
443 lockmgr(&sc->sm_lock, LK_RELEASE);
449 smqueue(struct sysmouse_state *sc, mouse_info_t *info)
451 struct event_fifo *f = sc->fifo;
453 if (f->fill >= FIFO_SIZE) {
455 f->buf[f->start] = *info;
456 f->start = (f->start + 1) % FIFO_SIZE;
459 f->buf[(f->start + f->fill) % FIFO_SIZE] = *info;
466 smget(struct sysmouse_state *sc, mouse_info_t *info)
468 struct event_fifo *f = sc->fifo;
471 *info = f->buf[f->start];
475 smpop(struct sysmouse_state *sc)
477 struct event_fifo *f = sc->fifo;
481 f->start = (f->start + 1) % FIFO_SIZE;
486 sm_attach_mouse(void *unused)
488 struct sysmouse_state *sc = &mouse_state;
491 lockinit(&mouse_state.sm_lock, "sysmouse", 0, LK_CANRECURSE);
494 dev = make_dev(&sm_ops, 0, UID_ROOT, GID_WHEEL, 0600, "sysmouse");
500 SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_ANY, sm_attach_mouse, NULL);
503 sysmouse_updatestatus(mousestatus_t *status, mouse_info_t *info)
507 status->obutton = status->button;
509 switch (info->operation) {
511 status->button = info->u.data.buttons;
513 case MOUSE_MOTION_EVENT:
518 case MOUSE_BUTTON_EVENT:
520 if (info->u.event.value > 0)
521 status->button |= info->u.event.id;
523 status->button &= ~info->u.event.id;
532 status->flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0)
533 | (status->obutton ^ status->button);
536 smdev_evdev_write(x, y, z, status->button);
542 /* Requires buf to hold at least 8 bytes, returns number of bytes written */
544 sysmouse_evtopkt(struct sysmouse_state *sc, mouse_info_t *info, u_char *buf)
546 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
547 static int butmap[8] = {
548 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
549 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
550 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
552 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
559 sc->readstatus.dx = 0;
560 sc->readstatus.dy = 0;
561 sc->readstatus.dz = 0;
562 sc->readstatus.flags = 0;
563 if (sysmouse_updatestatus(&sc->readstatus, info) == 0)
566 /* We aren't using the sc->readstatus.dx/dy/dz values */
568 if (sc->readstatus.flags == 0)
571 x = (info->operation == MOUSE_BUTTON_EVENT ? 0 : info->u.data.x);
572 y = (info->operation == MOUSE_BUTTON_EVENT ? 0 : info->u.data.y);
573 z = (info->operation == MOUSE_BUTTON_EVENT ? 0 : info->u.data.z);
575 /* the first five bytes are compatible with MouseSystems' */
576 buf[0] = MOUSE_MSC_SYNC
577 | butmap[sc->readstatus.button & MOUSE_STDBUTTONS];
578 x = imax(imin(x, 255), -256);
581 y = -imax(imin(y, 255), -256);
584 if (sc->level >= 1) {
586 z = imax(imin(z, 127), -128);
587 buf[5] = (z >> 1) & 0x7f;
588 buf[6] = (z - (z >> 1)) & 0x7f;
590 buf[7] = (~sc->readstatus.button >> 3) & 0x7f;
600 sysmouse_event(mouse_info_t *info)
602 struct sysmouse_state *sc = &mouse_state;
605 lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
606 ret = sysmouse_updatestatus(&sc->syncstatus, info);
608 ret = sc->syncstatus.flags;
610 lockmgr(&sc->sm_lock, LK_RELEASE);
614 switch (info->operation) {
616 case MOUSE_MOTION_EVENT:
617 case MOUSE_BUTTON_EVENT:
620 pgsigio(sc->sm_sigio, SIGIO, 0);
621 lockmgr(&sc->sm_lock, LK_RELEASE);
623 KNOTE(&sc->rkq.ki_note, 0);
626 lockmgr(&sc->sm_lock, LK_RELEASE);
633 #endif /* !SC_NO_SYSMOUSE */