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