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