1 /* $NetBSD: wsmouse.c,v 1.66 2014/07/25 08:10:39 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.66 2014/07/25 08:10:39 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_discard = nodiscard, 217 .d_flag = D_OTHER 218 }; 219 220 #if NWSMUX > 0 221 struct wssrcops wsmouse_srcops = { 222 WSMUX_MOUSE, 223 wsmouse_mux_open, wsmouse_mux_close, wsmousedoioctl, NULL, NULL 224 }; 225 #endif 226 227 /* 228 * Print function (for parent devices). 229 */ 230 int 231 wsmousedevprint(void *aux, const char *pnp) 232 { 233 234 if (pnp) 235 aprint_normal("wsmouse at %s", pnp); 236 return (UNCONF); 237 } 238 239 int 240 wsmouse_match(device_t parent, cfdata_t match, void *aux) 241 { 242 return (1); 243 } 244 245 void 246 wsmouse_attach(device_t parent, device_t self, void *aux) 247 { 248 struct wsmouse_softc *sc = device_private(self); 249 struct wsmousedev_attach_args *ap = aux; 250 #if NWSMUX > 0 251 int mux, error; 252 #endif 253 254 sc->sc_base.me_dv = self; 255 sc->sc_accessops = ap->accessops; 256 sc->sc_accesscookie = ap->accesscookie; 257 258 /* Initialize button repeating. */ 259 memset(&sc->sc_repeat, 0, sizeof(sc->sc_repeat)); 260 sc->sc_repeat_button = -1; 261 sc->sc_repeat_delay = 0; 262 callout_init(&sc->sc_repeat_callout, 0); 263 callout_setfunc(&sc->sc_repeat_callout, wsmouse_repeat, sc); 264 265 #if NWSMUX > 0 266 sc->sc_base.me_ops = &wsmouse_srcops; 267 mux = device_cfdata(self)->wsmousedevcf_mux; 268 if (mux >= 0) { 269 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 270 if (error) 271 aprint_error(" attach error=%d", error); 272 else 273 aprint_normal(" mux %d", mux); 274 } 275 #else 276 if (device_cfdata(self)->wsmousedevcf_mux >= 0) 277 aprint_normal(" (mux ignored)"); 278 #endif 279 280 aprint_naive("\n"); 281 aprint_normal("\n"); 282 283 if (!pmf_device_register(self, NULL, NULL)) 284 aprint_error_dev(self, "couldn't establish power handler\n"); 285 } 286 287 int 288 wsmouse_activate(device_t self, enum devact act) 289 { 290 struct wsmouse_softc *sc = device_private(self); 291 292 if (act == DVACT_DEACTIVATE) 293 sc->sc_dying = 1; 294 return (0); 295 } 296 297 /* 298 * Detach a mouse. To keep track of users of the softc we keep 299 * a reference count that's incremented while inside, e.g., read. 300 * If the mouse is active and the reference count is > 0 (0 is the 301 * normal state) we post an event and then wait for the process 302 * that had the reference to wake us up again. Then we blow away the 303 * vnode and return (which will deallocate the softc). 304 */ 305 int 306 wsmouse_detach(device_t self, int flags) 307 { 308 struct wsmouse_softc *sc = device_private(self); 309 struct wseventvar *evar; 310 int maj, mn; 311 int s; 312 313 #if NWSMUX > 0 314 /* Tell parent mux we're leaving. */ 315 if (sc->sc_base.me_parent != NULL) { 316 DPRINTF(("wsmouse_detach:\n")); 317 wsmux_detach_sc(&sc->sc_base); 318 } 319 #endif 320 321 /* If we're open ... */ 322 evar = sc->sc_base.me_evp; 323 if (evar != NULL && evar->io != NULL) { 324 s = spltty(); 325 if (--sc->sc_refcnt >= 0) { 326 struct wscons_event event; 327 328 /* Wake everyone by generating a dummy event. */ 329 event.type = 0; 330 event.value = 0; 331 if (wsevent_inject(evar, &event, 1) != 0) 332 wsevent_wakeup(evar); 333 334 /* Wait for processes to go away. */ 335 if (tsleep(sc, PZERO, "wsmdet", hz * 60)) 336 printf("wsmouse_detach: %s didn't detach\n", 337 device_xname(self)); 338 } 339 splx(s); 340 } 341 342 /* locate the major number */ 343 maj = cdevsw_lookup_major(&wsmouse_cdevsw); 344 345 /* Nuke the vnodes for any open instances (calls close). */ 346 mn = device_unit(self); 347 vdevgone(maj, mn, mn, VCHR); 348 349 return (0); 350 } 351 352 void 353 wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */, 354 int x, int y, int z, int w, u_int flags) 355 { 356 struct wsmouse_softc *sc = device_private(wsmousedev); 357 struct wseventvar *evar; 358 int mb, ub, d, nevents; 359 /* one for each dimension (4) + a bit for each button */ 360 struct wscons_event events[4 + sizeof(d) * 8]; 361 362 /* 363 * Discard input if not open. 364 */ 365 evar = sc->sc_base.me_evp; 366 if (evar == NULL) 367 return; 368 369 #ifdef DIAGNOSTIC 370 if (evar->q == NULL) { 371 printf("wsmouse_input: evar->q=NULL\n"); 372 return; 373 } 374 #endif 375 376 #if NWSMUX > 0 377 DPRINTFN(5,("wsmouse_input: %s mux=%p, evar=%p\n", 378 device_xname(sc->sc_base.me_dv), 379 sc->sc_base.me_parent, evar)); 380 #endif 381 382 sc->sc_mb = btns; 383 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X)) 384 sc->sc_dx += x; 385 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y)) 386 sc->sc_dy += y; 387 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z)) 388 sc->sc_dz += z; 389 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W)) 390 sc->sc_dw += w; 391 392 /* 393 * We have at least one event (mouse button, delta-X, or 394 * delta-Y; possibly all three, and possibly three separate 395 * button events). Deliver these events until we are out 396 * of changes or out of room. As events get delivered, 397 * mark them `unchanged'. 398 */ 399 ub = sc->sc_ub; 400 nevents = 0; 401 402 if (flags & WSMOUSE_INPUT_ABSOLUTE_X) { 403 if (sc->sc_x != x) { 404 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_X; 405 events[nevents].value = x; 406 nevents++; 407 } 408 } else { 409 if (sc->sc_dx) { 410 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_X; 411 events[nevents].value = sc->sc_dx; 412 nevents++; 413 } 414 } 415 if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) { 416 if (sc->sc_y != y) { 417 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y; 418 events[nevents].value = y; 419 nevents++; 420 } 421 } else { 422 if (sc->sc_dy) { 423 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Y; 424 events[nevents].value = sc->sc_dy; 425 nevents++; 426 } 427 } 428 if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) { 429 if (sc->sc_z != z) { 430 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z; 431 events[nevents].value = z; 432 nevents++; 433 } 434 } else { 435 if (sc->sc_dz) { 436 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Z; 437 events[nevents].value = sc->sc_dz; 438 nevents++; 439 } 440 } 441 if (flags & WSMOUSE_INPUT_ABSOLUTE_W) { 442 if (sc->sc_w != w) { 443 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_W; 444 events[nevents].value = w; 445 nevents++; 446 } 447 } else { 448 if (sc->sc_dw) { 449 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_W; 450 events[nevents].value = sc->sc_dw; 451 nevents++; 452 } 453 } 454 455 mb = sc->sc_mb; 456 while ((d = mb ^ ub) != 0) { 457 int btnno; 458 459 /* 460 * Cancel button repeating if button status changed. 461 */ 462 if (sc->sc_repeat_button != -1) { 463 KASSERT(sc->sc_repeat_button >= 0); 464 KASSERT(sc->sc_repeat.wr_buttons & 465 (1 << sc->sc_repeat_button)); 466 ub &= ~(1 << sc->sc_repeat_button); 467 sc->sc_repeat_button = -1; 468 callout_stop(&sc->sc_repeat_callout); 469 } 470 471 /* 472 * Mouse button change. Find the first change and drop 473 * it into the event queue. 474 */ 475 btnno = ffs(d) - 1; 476 KASSERT(btnno >= 0); 477 478 if (nevents >= sizeof(events) / sizeof(events[0])) { 479 aprint_error_dev(sc->sc_base.me_dv, 480 "Event queue full (button status mb=0x%x" 481 " ub=0x%x)\n", mb, ub); 482 break; 483 } 484 485 events[nevents].type = 486 (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP; 487 events[nevents].value = btnno; 488 nevents++; 489 490 ub ^= (1 << btnno); 491 492 /* 493 * Program button repeating if configured for this button. 494 */ 495 if ((mb & d) && (sc->sc_repeat.wr_buttons & (1 << btnno)) && 496 sc->sc_repeat.wr_delay_first > 0) { 497 sc->sc_repeat_button = btnno; 498 sc->sc_repeat_delay = sc->sc_repeat.wr_delay_first; 499 callout_schedule(&sc->sc_repeat_callout, 500 mstohz(sc->sc_repeat_delay)); 501 } 502 } 503 504 if (nevents == 0 || wsevent_inject(evar, events, nevents) == 0) { 505 /* All events were correctly injected into the queue. 506 * Synchronize the mouse's status with what the user 507 * has received. */ 508 sc->sc_x = x; sc->sc_dx = 0; 509 sc->sc_y = y; sc->sc_dy = 0; 510 sc->sc_z = z; sc->sc_dz = 0; 511 sc->sc_w = w; sc->sc_dw = 0; 512 sc->sc_ub = ub; 513 #if NWSMUX > 0 514 DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n", 515 device_xname(sc->sc_base.me_dv), evar)); 516 #endif 517 } 518 } 519 520 static void 521 wsmouse_repeat(void *v) 522 { 523 int oldspl; 524 unsigned int newdelay; 525 struct wsmouse_softc *sc; 526 struct wscons_event events[2]; 527 528 oldspl = spltty(); 529 sc = (struct wsmouse_softc *)v; 530 531 if (sc->sc_repeat_button == -1) { 532 /* Race condition: a "button up" event came in when 533 * this function was already called but did not do 534 * spltty() yet. */ 535 splx(oldspl); 536 return; 537 } 538 KASSERT(sc->sc_repeat_button >= 0); 539 540 KASSERT(sc->sc_repeat.wr_buttons & (1 << sc->sc_repeat_button)); 541 542 newdelay = sc->sc_repeat_delay; 543 544 events[0].type = WSCONS_EVENT_MOUSE_UP; 545 events[0].value = sc->sc_repeat_button; 546 events[1].type = WSCONS_EVENT_MOUSE_DOWN; 547 events[1].value = sc->sc_repeat_button; 548 549 if (wsevent_inject(sc->sc_base.me_evp, events, 2) == 0) { 550 sc->sc_ub = 1 << sc->sc_repeat_button; 551 552 if (newdelay - sc->sc_repeat.wr_delay_decrement < 553 sc->sc_repeat.wr_delay_minimum) 554 newdelay = sc->sc_repeat.wr_delay_minimum; 555 else if (newdelay > sc->sc_repeat.wr_delay_minimum) 556 newdelay -= sc->sc_repeat.wr_delay_decrement; 557 KASSERT(newdelay >= sc->sc_repeat.wr_delay_minimum && 558 newdelay <= sc->sc_repeat.wr_delay_first); 559 } 560 561 /* 562 * Reprogram the repeating event. 563 */ 564 sc->sc_repeat_delay = newdelay; 565 callout_schedule(&sc->sc_repeat_callout, mstohz(newdelay)); 566 567 splx(oldspl); 568 } 569 570 int 571 wsmouseopen(dev_t dev, int flags, int mode, struct lwp *l) 572 { 573 struct wsmouse_softc *sc; 574 struct wseventvar *evar; 575 int error; 576 577 sc = device_lookup_private(&wsmouse_cd, minor(dev)); 578 if (sc == NULL) 579 return ENXIO; 580 581 #if NWSMUX > 0 582 DPRINTF(("wsmouseopen: %s mux=%p p=%p\n", device_xname(sc->sc_base.me_dv), 583 sc->sc_base.me_parent, l)); 584 #endif 585 586 if (sc->sc_dying) 587 return (EIO); 588 589 if ((flags & (FREAD | FWRITE)) == FWRITE) 590 return (0); /* always allow open for write 591 so ioctl() is possible. */ 592 593 if (sc->sc_base.me_evp != NULL) 594 return (EBUSY); 595 596 evar = &sc->sc_base.me_evar; 597 wsevent_init(evar, l->l_proc); 598 sc->sc_base.me_evp = evar; 599 600 error = wsmousedoopen(sc, evar); 601 if (error) { 602 DPRINTF(("wsmouseopen: %s open failed\n", 603 device_xname(sc->sc_base.me_dv))); 604 sc->sc_base.me_evp = NULL; 605 wsevent_fini(evar); 606 } 607 return (error); 608 } 609 610 int 611 wsmouseclose(dev_t dev, int flags, int mode, 612 struct lwp *l) 613 { 614 struct wsmouse_softc *sc = 615 device_lookup_private(&wsmouse_cd, minor(dev)); 616 struct wseventvar *evar = sc->sc_base.me_evp; 617 618 if (evar == NULL) 619 /* not open for read */ 620 return (0); 621 sc->sc_base.me_evp = NULL; 622 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 623 wsevent_fini(evar); 624 625 return (0); 626 } 627 628 int 629 wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp) 630 { 631 sc->sc_base.me_evp = evp; 632 sc->sc_x = INVALID_X; 633 sc->sc_y = INVALID_Y; 634 sc->sc_z = INVALID_Z; 635 sc->sc_w = INVALID_W; 636 637 /* Stop button repeating when messing with the device. */ 638 if (sc->sc_repeat_button != -1) { 639 KASSERT(sc->sc_repeat_button >= 0); 640 sc->sc_repeat_button = -1; 641 callout_stop(&sc->sc_repeat_callout); 642 } 643 644 /* enable the device, and punt if that's not possible */ 645 return (*sc->sc_accessops->enable)(sc->sc_accesscookie); 646 } 647 648 int 649 wsmouseread(dev_t dev, struct uio *uio, int flags) 650 { 651 struct wsmouse_softc *sc = 652 device_lookup_private(&wsmouse_cd, minor(dev)); 653 int error; 654 655 if (sc->sc_dying) 656 return (EIO); 657 658 #ifdef DIAGNOSTIC 659 if (sc->sc_base.me_evp == NULL) { 660 printf("wsmouseread: evp == NULL\n"); 661 return (EINVAL); 662 } 663 #endif 664 665 sc->sc_refcnt++; 666 error = wsevent_read(sc->sc_base.me_evp, uio, flags); 667 if (--sc->sc_refcnt < 0) { 668 wakeup(sc); 669 error = EIO; 670 } 671 return (error); 672 } 673 674 int 675 wsmouseioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 676 { 677 return (wsmousedoioctl(device_lookup(&wsmouse_cd, minor(dev)), 678 cmd, data, flag, l)); 679 } 680 681 /* A wrapper around the ioctl() workhorse to make reference counting easy. */ 682 int 683 wsmousedoioctl(device_t dv, u_long cmd, void *data, int flag, 684 struct lwp *l) 685 { 686 struct wsmouse_softc *sc = device_private(dv); 687 int error; 688 689 sc->sc_refcnt++; 690 error = wsmouse_do_ioctl(sc, cmd, data, flag, l); 691 if (--sc->sc_refcnt < 0) 692 wakeup(sc); 693 return (error); 694 } 695 696 int 697 wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, void *data, 698 int flag, struct lwp *l) 699 { 700 int error; 701 struct wsmouse_repeat *wr; 702 703 if (sc->sc_dying) 704 return (EIO); 705 706 /* 707 * Try the generic ioctls that the wsmouse interface supports. 708 */ 709 switch (cmd) { 710 case FIONBIO: /* we will remove this someday (soon???) */ 711 return (0); 712 713 case FIOASYNC: 714 if (sc->sc_base.me_evp == NULL) 715 return (EINVAL); 716 sc->sc_base.me_evp->async = *(int *)data != 0; 717 return (0); 718 719 case FIOSETOWN: 720 if (sc->sc_base.me_evp == NULL) 721 return (EINVAL); 722 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid 723 && *(int *)data != sc->sc_base.me_evp->io->p_pid) 724 return (EPERM); 725 return (0); 726 727 case TIOCSPGRP: 728 if (sc->sc_base.me_evp == NULL) 729 return (EINVAL); 730 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid) 731 return (EPERM); 732 return (0); 733 } 734 735 /* 736 * Try the wsmouse specific ioctls. 737 */ 738 switch (cmd) { 739 case WSMOUSEIO_GETREPEAT: 740 wr = (struct wsmouse_repeat *)data; 741 memcpy(wr, &sc->sc_repeat, sizeof(sc->sc_repeat)); 742 return 0; 743 744 case WSMOUSEIO_SETREPEAT: 745 if ((flag & FWRITE) == 0) 746 return EACCES; 747 748 /* Validate input data. */ 749 wr = (struct wsmouse_repeat *)data; 750 if (wr->wr_delay_first != 0 && 751 (wr->wr_delay_first < wr->wr_delay_decrement || 752 wr->wr_delay_first < wr->wr_delay_minimum || 753 wr->wr_delay_first < wr->wr_delay_minimum + 754 wr->wr_delay_decrement)) 755 return EINVAL; 756 757 /* Stop current repeating and set new data. */ 758 sc->sc_repeat_button = -1; 759 callout_stop(&sc->sc_repeat_callout); 760 memcpy(&sc->sc_repeat, wr, sizeof(sc->sc_repeat)); 761 762 return 0; 763 764 case WSMOUSEIO_SETVERSION: 765 return wsevent_setversion(sc->sc_base.me_evp, *(int *)data); 766 } 767 768 /* 769 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1 770 * if it didn't recognize the request. 771 */ 772 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 773 data, flag, l); 774 return (error); /* may be EPASSTHROUGH */ 775 } 776 777 int 778 wsmousepoll(dev_t dev, int events, struct lwp *l) 779 { 780 struct wsmouse_softc *sc = 781 device_lookup_private(&wsmouse_cd, minor(dev)); 782 783 if (sc->sc_base.me_evp == NULL) 784 return (POLLERR); 785 return (wsevent_poll(sc->sc_base.me_evp, events, l)); 786 } 787 788 int 789 wsmousekqfilter(dev_t dev, struct knote *kn) 790 { 791 struct wsmouse_softc *sc = 792 device_lookup_private(&wsmouse_cd, minor(dev)); 793 794 if (sc->sc_base.me_evp == NULL) 795 return (1); 796 return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); 797 } 798 799 #if NWSMUX > 0 800 int 801 wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp) 802 { 803 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 804 805 if (sc->sc_base.me_evp != NULL) 806 return (EBUSY); 807 808 return wsmousedoopen(sc, evp); 809 } 810 811 int 812 wsmouse_mux_close(struct wsevsrc *me) 813 { 814 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 815 816 sc->sc_base.me_evp = NULL; 817 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 818 819 return (0); 820 } 821 822 int 823 wsmouse_add_mux(int unit, struct wsmux_softc *muxsc) 824 { 825 struct wsmouse_softc *sc; 826 827 sc = device_lookup_private(&wsmouse_cd, unit); 828 if (sc == NULL) 829 return ENXIO; 830 831 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 832 return (EBUSY); 833 834 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 835 } 836 #endif /* NWSMUX > 0 */ 837