wsmouse.c revision 1.65 1 /* $NetBSD: wsmouse.c,v 1.65 2014/03/16 05:20:29 dholland Exp $ */
2
3 /*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by Christopher G. Demetriou
46 * for the NetBSD Project.
47 * 4. The name of the author may not be used to endorse or promote products
48 * derived from this software without specific prior written permission
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 */
61
62 /*
63 * Copyright (c) 1992, 1993
64 * The Regents of the University of California. All rights reserved.
65 *
66 * This software was developed by the Computer Systems Engineering group
67 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
68 * contributed to Berkeley.
69 *
70 * All advertising materials mentioning features or use of this software
71 * must display the following acknowledgement:
72 * This product includes software developed by the University of
73 * California, Lawrence Berkeley Laboratory.
74 *
75 * Redistribution and use in source and binary forms, with or without
76 * modification, are permitted provided that the following conditions
77 * are met:
78 * 1. Redistributions of source code must retain the above copyright
79 * notice, this list of conditions and the following disclaimer.
80 * 2. Redistributions in binary form must reproduce the above copyright
81 * notice, this list of conditions and the following disclaimer in the
82 * documentation and/or other materials provided with the distribution.
83 * 3. Neither the name of the University nor the names of its contributors
84 * may be used to endorse or promote products derived from this software
85 * without specific prior written permission.
86 *
87 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
88 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
91 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
92 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
93 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
94 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
95 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
96 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
97 * SUCH DAMAGE.
98 *
99 * @(#)ms.c 8.1 (Berkeley) 6/11/93
100 */
101
102 /*
103 * Mouse driver.
104 */
105
106 #include <sys/cdefs.h>
107 __KERNEL_RCSID(0, "$NetBSD: wsmouse.c,v 1.65 2014/03/16 05:20:29 dholland Exp $");
108
109 #include "wsmouse.h"
110 #include "wsdisplay.h"
111 #include "wsmux.h"
112
113 #include <sys/param.h>
114 #include <sys/conf.h>
115 #include <sys/ioctl.h>
116 #include <sys/poll.h>
117 #include <sys/fcntl.h>
118 #include <sys/kernel.h>
119 #include <sys/proc.h>
120 #include <sys/syslog.h>
121 #include <sys/systm.h>
122 #include <sys/tty.h>
123 #include <sys/signalvar.h>
124 #include <sys/device.h>
125 #include <sys/vnode.h>
126 #include <sys/callout.h>
127 #include <sys/malloc.h>
128
129 #include <dev/wscons/wsconsio.h>
130 #include <dev/wscons/wsmousevar.h>
131 #include <dev/wscons/wseventvar.h>
132 #include <dev/wscons/wsmuxvar.h>
133
134 #if defined(WSMUX_DEBUG) && NWSMUX > 0
135 #define DPRINTF(x) if (wsmuxdebug) printf x
136 #define DPRINTFN(n,x) if (wsmuxdebug > (n)) printf x
137 extern int wsmuxdebug;
138 #else
139 #define DPRINTF(x)
140 #define DPRINTFN(n,x)
141 #endif
142
143 #define INVALID_X INT_MAX
144 #define INVALID_Y INT_MAX
145 #define INVALID_Z INT_MAX
146 #define INVALID_W INT_MAX
147
148 struct wsmouse_softc {
149 struct wsevsrc sc_base;
150
151 const struct wsmouse_accessops *sc_accessops;
152 void *sc_accesscookie;
153
154 u_int sc_mb; /* mouse button state */
155 u_int sc_ub; /* user button state */
156 int sc_dx; /* delta-x */
157 int sc_dy; /* delta-y */
158 int sc_dz; /* delta-z */
159 int sc_dw; /* delta-w */
160 int sc_x; /* absolute-x */
161 int sc_y; /* absolute-y */
162 int sc_z; /* absolute-z */
163 int sc_w; /* absolute-w */
164
165 int sc_refcnt;
166 u_char sc_dying; /* device is being detached */
167
168 struct wsmouse_repeat sc_repeat;
169 int sc_repeat_button;
170 callout_t sc_repeat_callout;
171 unsigned int sc_repeat_delay;
172 };
173
174 static int wsmouse_match(device_t, cfdata_t, void *);
175 static void wsmouse_attach(device_t, device_t, void *);
176 static int wsmouse_detach(device_t, int);
177 static int wsmouse_activate(device_t, enum devact);
178
179 static int wsmouse_do_ioctl(struct wsmouse_softc *, u_long, void *,
180 int, struct lwp *);
181
182 #if NWSMUX > 0
183 static int wsmouse_mux_open(struct wsevsrc *, struct wseventvar *);
184 static int wsmouse_mux_close(struct wsevsrc *);
185 #endif
186
187 static int wsmousedoioctl(device_t, u_long, void *, int, struct lwp *);
188
189 static int wsmousedoopen(struct wsmouse_softc *, struct wseventvar *);
190
191 CFATTACH_DECL_NEW(wsmouse, sizeof (struct wsmouse_softc),
192 wsmouse_match, wsmouse_attach, wsmouse_detach, wsmouse_activate);
193
194 static void wsmouse_repeat(void *v);
195
196 extern struct cfdriver wsmouse_cd;
197
198 dev_type_open(wsmouseopen);
199 dev_type_close(wsmouseclose);
200 dev_type_read(wsmouseread);
201 dev_type_ioctl(wsmouseioctl);
202 dev_type_poll(wsmousepoll);
203 dev_type_kqfilter(wsmousekqfilter);
204
205 const struct cdevsw wsmouse_cdevsw = {
206 .d_open = wsmouseopen,
207 .d_close = wsmouseclose,
208 .d_read = wsmouseread,
209 .d_write = nowrite,
210 .d_ioctl = wsmouseioctl,
211 .d_stop = nostop,
212 .d_tty = notty,
213 .d_poll = wsmousepoll,
214 .d_mmap = nommap,
215 .d_kqfilter = wsmousekqfilter,
216 .d_flag = D_OTHER
217 };
218
219 #if NWSMUX > 0
220 struct wssrcops wsmouse_srcops = {
221 WSMUX_MOUSE,
222 wsmouse_mux_open, wsmouse_mux_close, wsmousedoioctl, NULL, NULL
223 };
224 #endif
225
226 /*
227 * Print function (for parent devices).
228 */
229 int
230 wsmousedevprint(void *aux, const char *pnp)
231 {
232
233 if (pnp)
234 aprint_normal("wsmouse at %s", pnp);
235 return (UNCONF);
236 }
237
238 int
239 wsmouse_match(device_t parent, cfdata_t match, void *aux)
240 {
241 return (1);
242 }
243
244 void
245 wsmouse_attach(device_t parent, device_t self, void *aux)
246 {
247 struct wsmouse_softc *sc = device_private(self);
248 struct wsmousedev_attach_args *ap = aux;
249 #if NWSMUX > 0
250 int mux, error;
251 #endif
252
253 sc->sc_base.me_dv = self;
254 sc->sc_accessops = ap->accessops;
255 sc->sc_accesscookie = ap->accesscookie;
256
257 /* Initialize button repeating. */
258 memset(&sc->sc_repeat, 0, sizeof(sc->sc_repeat));
259 sc->sc_repeat_button = -1;
260 sc->sc_repeat_delay = 0;
261 callout_init(&sc->sc_repeat_callout, 0);
262 callout_setfunc(&sc->sc_repeat_callout, wsmouse_repeat, sc);
263
264 #if NWSMUX > 0
265 sc->sc_base.me_ops = &wsmouse_srcops;
266 mux = device_cfdata(self)->wsmousedevcf_mux;
267 if (mux >= 0) {
268 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
269 if (error)
270 aprint_error(" attach error=%d", error);
271 else
272 aprint_normal(" mux %d", mux);
273 }
274 #else
275 if (device_cfdata(self)->wsmousedevcf_mux >= 0)
276 aprint_normal(" (mux ignored)");
277 #endif
278
279 aprint_naive("\n");
280 aprint_normal("\n");
281
282 if (!pmf_device_register(self, NULL, NULL))
283 aprint_error_dev(self, "couldn't establish power handler\n");
284 }
285
286 int
287 wsmouse_activate(device_t self, enum devact act)
288 {
289 struct wsmouse_softc *sc = device_private(self);
290
291 if (act == DVACT_DEACTIVATE)
292 sc->sc_dying = 1;
293 return (0);
294 }
295
296 /*
297 * Detach a mouse. To keep track of users of the softc we keep
298 * a reference count that's incremented while inside, e.g., read.
299 * If the mouse is active and the reference count is > 0 (0 is the
300 * normal state) we post an event and then wait for the process
301 * that had the reference to wake us up again. Then we blow away the
302 * vnode and return (which will deallocate the softc).
303 */
304 int
305 wsmouse_detach(device_t self, int flags)
306 {
307 struct wsmouse_softc *sc = device_private(self);
308 struct wseventvar *evar;
309 int maj, mn;
310 int s;
311
312 #if NWSMUX > 0
313 /* Tell parent mux we're leaving. */
314 if (sc->sc_base.me_parent != NULL) {
315 DPRINTF(("wsmouse_detach:\n"));
316 wsmux_detach_sc(&sc->sc_base);
317 }
318 #endif
319
320 /* If we're open ... */
321 evar = sc->sc_base.me_evp;
322 if (evar != NULL && evar->io != NULL) {
323 s = spltty();
324 if (--sc->sc_refcnt >= 0) {
325 struct wscons_event event;
326
327 /* Wake everyone by generating a dummy event. */
328 event.type = 0;
329 event.value = 0;
330 if (wsevent_inject(evar, &event, 1) != 0)
331 wsevent_wakeup(evar);
332
333 /* Wait for processes to go away. */
334 if (tsleep(sc, PZERO, "wsmdet", hz * 60))
335 printf("wsmouse_detach: %s didn't detach\n",
336 device_xname(self));
337 }
338 splx(s);
339 }
340
341 /* locate the major number */
342 maj = cdevsw_lookup_major(&wsmouse_cdevsw);
343
344 /* Nuke the vnodes for any open instances (calls close). */
345 mn = device_unit(self);
346 vdevgone(maj, mn, mn, VCHR);
347
348 return (0);
349 }
350
351 void
352 wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */,
353 int x, int y, int z, int w, u_int flags)
354 {
355 struct wsmouse_softc *sc = device_private(wsmousedev);
356 struct wseventvar *evar;
357 int mb, ub, d, nevents;
358 /* one for each dimension (4) + a bit for each button */
359 struct wscons_event events[4 + sizeof(d) * 8];
360
361 /*
362 * Discard input if not open.
363 */
364 evar = sc->sc_base.me_evp;
365 if (evar == NULL)
366 return;
367
368 #ifdef DIAGNOSTIC
369 if (evar->q == NULL) {
370 printf("wsmouse_input: evar->q=NULL\n");
371 return;
372 }
373 #endif
374
375 #if NWSMUX > 0
376 DPRINTFN(5,("wsmouse_input: %s mux=%p, evar=%p\n",
377 device_xname(sc->sc_base.me_dv),
378 sc->sc_base.me_parent, evar));
379 #endif
380
381 sc->sc_mb = btns;
382 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X))
383 sc->sc_dx += x;
384 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y))
385 sc->sc_dy += y;
386 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z))
387 sc->sc_dz += z;
388 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W))
389 sc->sc_dw += w;
390
391 /*
392 * We have at least one event (mouse button, delta-X, or
393 * delta-Y; possibly all three, and possibly three separate
394 * button events). Deliver these events until we are out
395 * of changes or out of room. As events get delivered,
396 * mark them `unchanged'.
397 */
398 ub = sc->sc_ub;
399 nevents = 0;
400
401 if (flags & WSMOUSE_INPUT_ABSOLUTE_X) {
402 if (sc->sc_x != x) {
403 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_X;
404 events[nevents].value = x;
405 nevents++;
406 }
407 } else {
408 if (sc->sc_dx) {
409 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_X;
410 events[nevents].value = sc->sc_dx;
411 nevents++;
412 }
413 }
414 if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) {
415 if (sc->sc_y != y) {
416 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y;
417 events[nevents].value = y;
418 nevents++;
419 }
420 } else {
421 if (sc->sc_dy) {
422 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Y;
423 events[nevents].value = sc->sc_dy;
424 nevents++;
425 }
426 }
427 if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) {
428 if (sc->sc_z != z) {
429 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z;
430 events[nevents].value = z;
431 nevents++;
432 }
433 } else {
434 if (sc->sc_dz) {
435 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Z;
436 events[nevents].value = sc->sc_dz;
437 nevents++;
438 }
439 }
440 if (flags & WSMOUSE_INPUT_ABSOLUTE_W) {
441 if (sc->sc_w != w) {
442 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_W;
443 events[nevents].value = w;
444 nevents++;
445 }
446 } else {
447 if (sc->sc_dw) {
448 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_W;
449 events[nevents].value = sc->sc_dw;
450 nevents++;
451 }
452 }
453
454 mb = sc->sc_mb;
455 while ((d = mb ^ ub) != 0) {
456 int btnno;
457
458 /*
459 * Cancel button repeating if button status changed.
460 */
461 if (sc->sc_repeat_button != -1) {
462 KASSERT(sc->sc_repeat_button >= 0);
463 KASSERT(sc->sc_repeat.wr_buttons &
464 (1 << sc->sc_repeat_button));
465 ub &= ~(1 << sc->sc_repeat_button);
466 sc->sc_repeat_button = -1;
467 callout_stop(&sc->sc_repeat_callout);
468 }
469
470 /*
471 * Mouse button change. Find the first change and drop
472 * it into the event queue.
473 */
474 btnno = ffs(d) - 1;
475 KASSERT(btnno >= 0);
476
477 if (nevents >= sizeof(events) / sizeof(events[0])) {
478 aprint_error_dev(sc->sc_base.me_dv,
479 "Event queue full (button status mb=0x%x"
480 " ub=0x%x)\n", mb, ub);
481 break;
482 }
483
484 events[nevents].type =
485 (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
486 events[nevents].value = btnno;
487 nevents++;
488
489 ub ^= (1 << btnno);
490
491 /*
492 * Program button repeating if configured for this button.
493 */
494 if ((mb & d) && (sc->sc_repeat.wr_buttons & (1 << btnno)) &&
495 sc->sc_repeat.wr_delay_first > 0) {
496 sc->sc_repeat_button = btnno;
497 sc->sc_repeat_delay = sc->sc_repeat.wr_delay_first;
498 callout_schedule(&sc->sc_repeat_callout,
499 mstohz(sc->sc_repeat_delay));
500 }
501 }
502
503 if (nevents == 0 || wsevent_inject(evar, events, nevents) == 0) {
504 /* All events were correctly injected into the queue.
505 * Synchronize the mouse's status with what the user
506 * has received. */
507 sc->sc_x = x; sc->sc_dx = 0;
508 sc->sc_y = y; sc->sc_dy = 0;
509 sc->sc_z = z; sc->sc_dz = 0;
510 sc->sc_w = w; sc->sc_dw = 0;
511 sc->sc_ub = ub;
512 #if NWSMUX > 0
513 DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n",
514 device_xname(sc->sc_base.me_dv), evar));
515 #endif
516 }
517 }
518
519 static void
520 wsmouse_repeat(void *v)
521 {
522 int oldspl;
523 unsigned int newdelay;
524 struct wsmouse_softc *sc;
525 struct wscons_event events[2];
526
527 oldspl = spltty();
528 sc = (struct wsmouse_softc *)v;
529
530 if (sc->sc_repeat_button == -1) {
531 /* Race condition: a "button up" event came in when
532 * this function was already called but did not do
533 * spltty() yet. */
534 splx(oldspl);
535 return;
536 }
537 KASSERT(sc->sc_repeat_button >= 0);
538
539 KASSERT(sc->sc_repeat.wr_buttons & (1 << sc->sc_repeat_button));
540
541 newdelay = sc->sc_repeat_delay;
542
543 events[0].type = WSCONS_EVENT_MOUSE_UP;
544 events[0].value = sc->sc_repeat_button;
545 events[1].type = WSCONS_EVENT_MOUSE_DOWN;
546 events[1].value = sc->sc_repeat_button;
547
548 if (wsevent_inject(sc->sc_base.me_evp, events, 2) == 0) {
549 sc->sc_ub = 1 << sc->sc_repeat_button;
550
551 if (newdelay - sc->sc_repeat.wr_delay_decrement <
552 sc->sc_repeat.wr_delay_minimum)
553 newdelay = sc->sc_repeat.wr_delay_minimum;
554 else if (newdelay > sc->sc_repeat.wr_delay_minimum)
555 newdelay -= sc->sc_repeat.wr_delay_decrement;
556 KASSERT(newdelay >= sc->sc_repeat.wr_delay_minimum &&
557 newdelay <= sc->sc_repeat.wr_delay_first);
558 }
559
560 /*
561 * Reprogram the repeating event.
562 */
563 sc->sc_repeat_delay = newdelay;
564 callout_schedule(&sc->sc_repeat_callout, mstohz(newdelay));
565
566 splx(oldspl);
567 }
568
569 int
570 wsmouseopen(dev_t dev, int flags, int mode, struct lwp *l)
571 {
572 struct wsmouse_softc *sc;
573 struct wseventvar *evar;
574 int error;
575
576 sc = device_lookup_private(&wsmouse_cd, minor(dev));
577 if (sc == NULL)
578 return ENXIO;
579
580 #if NWSMUX > 0
581 DPRINTF(("wsmouseopen: %s mux=%p p=%p\n", device_xname(sc->sc_base.me_dv),
582 sc->sc_base.me_parent, l));
583 #endif
584
585 if (sc->sc_dying)
586 return (EIO);
587
588 if ((flags & (FREAD | FWRITE)) == FWRITE)
589 return (0); /* always allow open for write
590 so ioctl() is possible. */
591
592 if (sc->sc_base.me_evp != NULL)
593 return (EBUSY);
594
595 evar = &sc->sc_base.me_evar;
596 wsevent_init(evar, l->l_proc);
597 sc->sc_base.me_evp = evar;
598
599 error = wsmousedoopen(sc, evar);
600 if (error) {
601 DPRINTF(("wsmouseopen: %s open failed\n",
602 device_xname(sc->sc_base.me_dv)));
603 sc->sc_base.me_evp = NULL;
604 wsevent_fini(evar);
605 }
606 return (error);
607 }
608
609 int
610 wsmouseclose(dev_t dev, int flags, int mode,
611 struct lwp *l)
612 {
613 struct wsmouse_softc *sc =
614 device_lookup_private(&wsmouse_cd, minor(dev));
615 struct wseventvar *evar = sc->sc_base.me_evp;
616
617 if (evar == NULL)
618 /* not open for read */
619 return (0);
620 sc->sc_base.me_evp = NULL;
621 (*sc->sc_accessops->disable)(sc->sc_accesscookie);
622 wsevent_fini(evar);
623
624 return (0);
625 }
626
627 int
628 wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp)
629 {
630 sc->sc_base.me_evp = evp;
631 sc->sc_x = INVALID_X;
632 sc->sc_y = INVALID_Y;
633 sc->sc_z = INVALID_Z;
634 sc->sc_w = INVALID_W;
635
636 /* Stop button repeating when messing with the device. */
637 if (sc->sc_repeat_button != -1) {
638 KASSERT(sc->sc_repeat_button >= 0);
639 sc->sc_repeat_button = -1;
640 callout_stop(&sc->sc_repeat_callout);
641 }
642
643 /* enable the device, and punt if that's not possible */
644 return (*sc->sc_accessops->enable)(sc->sc_accesscookie);
645 }
646
647 int
648 wsmouseread(dev_t dev, struct uio *uio, int flags)
649 {
650 struct wsmouse_softc *sc =
651 device_lookup_private(&wsmouse_cd, minor(dev));
652 int error;
653
654 if (sc->sc_dying)
655 return (EIO);
656
657 #ifdef DIAGNOSTIC
658 if (sc->sc_base.me_evp == NULL) {
659 printf("wsmouseread: evp == NULL\n");
660 return (EINVAL);
661 }
662 #endif
663
664 sc->sc_refcnt++;
665 error = wsevent_read(sc->sc_base.me_evp, uio, flags);
666 if (--sc->sc_refcnt < 0) {
667 wakeup(sc);
668 error = EIO;
669 }
670 return (error);
671 }
672
673 int
674 wsmouseioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
675 {
676 return (wsmousedoioctl(device_lookup(&wsmouse_cd, minor(dev)),
677 cmd, data, flag, l));
678 }
679
680 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
681 int
682 wsmousedoioctl(device_t dv, u_long cmd, void *data, int flag,
683 struct lwp *l)
684 {
685 struct wsmouse_softc *sc = device_private(dv);
686 int error;
687
688 sc->sc_refcnt++;
689 error = wsmouse_do_ioctl(sc, cmd, data, flag, l);
690 if (--sc->sc_refcnt < 0)
691 wakeup(sc);
692 return (error);
693 }
694
695 int
696 wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, void *data,
697 int flag, struct lwp *l)
698 {
699 int error;
700 struct wsmouse_repeat *wr;
701
702 if (sc->sc_dying)
703 return (EIO);
704
705 /*
706 * Try the generic ioctls that the wsmouse interface supports.
707 */
708 switch (cmd) {
709 case FIONBIO: /* we will remove this someday (soon???) */
710 return (0);
711
712 case FIOASYNC:
713 if (sc->sc_base.me_evp == NULL)
714 return (EINVAL);
715 sc->sc_base.me_evp->async = *(int *)data != 0;
716 return (0);
717
718 case FIOSETOWN:
719 if (sc->sc_base.me_evp == NULL)
720 return (EINVAL);
721 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid
722 && *(int *)data != sc->sc_base.me_evp->io->p_pid)
723 return (EPERM);
724 return (0);
725
726 case TIOCSPGRP:
727 if (sc->sc_base.me_evp == NULL)
728 return (EINVAL);
729 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid)
730 return (EPERM);
731 return (0);
732 }
733
734 /*
735 * Try the wsmouse specific ioctls.
736 */
737 switch (cmd) {
738 case WSMOUSEIO_GETREPEAT:
739 wr = (struct wsmouse_repeat *)data;
740 memcpy(wr, &sc->sc_repeat, sizeof(sc->sc_repeat));
741 return 0;
742
743 case WSMOUSEIO_SETREPEAT:
744 if ((flag & FWRITE) == 0)
745 return EACCES;
746
747 /* Validate input data. */
748 wr = (struct wsmouse_repeat *)data;
749 if (wr->wr_delay_first != 0 &&
750 (wr->wr_delay_first < wr->wr_delay_decrement ||
751 wr->wr_delay_first < wr->wr_delay_minimum ||
752 wr->wr_delay_first < wr->wr_delay_minimum +
753 wr->wr_delay_decrement))
754 return EINVAL;
755
756 /* Stop current repeating and set new data. */
757 sc->sc_repeat_button = -1;
758 callout_stop(&sc->sc_repeat_callout);
759 memcpy(&sc->sc_repeat, wr, sizeof(sc->sc_repeat));
760
761 return 0;
762
763 case WSMOUSEIO_SETVERSION:
764 return wsevent_setversion(sc->sc_base.me_evp, *(int *)data);
765 }
766
767 /*
768 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1
769 * if it didn't recognize the request.
770 */
771 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
772 data, flag, l);
773 return (error); /* may be EPASSTHROUGH */
774 }
775
776 int
777 wsmousepoll(dev_t dev, int events, struct lwp *l)
778 {
779 struct wsmouse_softc *sc =
780 device_lookup_private(&wsmouse_cd, minor(dev));
781
782 if (sc->sc_base.me_evp == NULL)
783 return (POLLERR);
784 return (wsevent_poll(sc->sc_base.me_evp, events, l));
785 }
786
787 int
788 wsmousekqfilter(dev_t dev, struct knote *kn)
789 {
790 struct wsmouse_softc *sc =
791 device_lookup_private(&wsmouse_cd, minor(dev));
792
793 if (sc->sc_base.me_evp == NULL)
794 return (1);
795 return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
796 }
797
798 #if NWSMUX > 0
799 int
800 wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp)
801 {
802 struct wsmouse_softc *sc = (struct wsmouse_softc *)me;
803
804 if (sc->sc_base.me_evp != NULL)
805 return (EBUSY);
806
807 return wsmousedoopen(sc, evp);
808 }
809
810 int
811 wsmouse_mux_close(struct wsevsrc *me)
812 {
813 struct wsmouse_softc *sc = (struct wsmouse_softc *)me;
814
815 sc->sc_base.me_evp = NULL;
816 (*sc->sc_accessops->disable)(sc->sc_accesscookie);
817
818 return (0);
819 }
820
821 int
822 wsmouse_add_mux(int unit, struct wsmux_softc *muxsc)
823 {
824 struct wsmouse_softc *sc;
825
826 sc = device_lookup_private(&wsmouse_cd, unit);
827 if (sc == NULL)
828 return ENXIO;
829
830 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
831 return (EBUSY);
832
833 return (wsmux_attach_sc(muxsc, &sc->sc_base));
834 }
835 #endif /* NWSMUX > 0 */
836