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