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