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