1 /* $NetBSD: wsmouse.c,v 1.73 2023/07/30 10:45:11 riastradh 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.73 2023/07/30 10:45:11 riastradh 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 128 #include <dev/wscons/wsconsio.h> 129 #include <dev/wscons/wsmousevar.h> 130 #include <dev/wscons/wseventvar.h> 131 #include <dev/wscons/wsmuxvar.h> 132 133 #include "ioconf.h" 134 135 #if defined(WSMUX_DEBUG) && NWSMUX > 0 136 #define DPRINTF(x) if (wsmuxdebug) printf x 137 #define DPRINTFN(n,x) if (wsmuxdebug > (n)) printf x 138 extern int wsmuxdebug; 139 #else 140 #define DPRINTF(x) 141 #define DPRINTFN(n,x) 142 #endif 143 144 #define INVALID_X INT_MAX 145 #define INVALID_Y INT_MAX 146 #define INVALID_Z INT_MAX 147 #define INVALID_W INT_MAX 148 149 struct wsmouse_softc { 150 struct wsevsrc sc_base; 151 152 const struct wsmouse_accessops *sc_accessops; 153 void *sc_accesscookie; 154 155 u_int sc_mb; /* mouse button state */ 156 u_int sc_ub; /* user button state */ 157 int sc_dx; /* delta-x */ 158 int sc_dy; /* delta-y */ 159 int sc_dz; /* delta-z */ 160 int sc_dw; /* delta-w */ 161 int sc_x; /* absolute-x */ 162 int sc_y; /* absolute-y */ 163 int sc_z; /* absolute-z */ 164 int sc_w; /* absolute-w */ 165 166 int sc_refcnt; 167 u_char sc_dying; /* device is being detached */ 168 169 struct wsmouse_repeat sc_repeat; 170 int sc_repeat_button; 171 callout_t sc_repeat_callout; 172 unsigned int sc_repeat_delay; 173 174 int sc_reverse_scroll; 175 int sc_horiz_scroll_dist; 176 int sc_vert_scroll_dist; 177 }; 178 179 static int wsmouse_match(device_t, cfdata_t, void *); 180 static void wsmouse_attach(device_t, device_t, void *); 181 static int wsmouse_detach(device_t, int); 182 static int wsmouse_activate(device_t, enum devact); 183 184 static int wsmouse_set_params(struct wsmouse_softc *, 185 struct wsmouse_param *, size_t); 186 static int wsmouse_get_params(struct wsmouse_softc *, 187 struct wsmouse_param *, size_t); 188 static int wsmouse_handle_params(struct wsmouse_softc *, 189 struct wsmouse_parameters *, bool); 190 191 static int wsmouse_do_ioctl(struct wsmouse_softc *, u_long, void *, 192 int, struct lwp *); 193 194 #if NWSMUX > 0 195 static int wsmouse_mux_open(struct wsevsrc *, struct wseventvar *); 196 static int wsmouse_mux_close(struct wsevsrc *); 197 #endif 198 199 static int wsmousedoioctl(device_t, u_long, void *, int, struct lwp *); 200 201 static int wsmousedoopen(struct wsmouse_softc *, struct wseventvar *); 202 203 CFATTACH_DECL_NEW(wsmouse, sizeof (struct wsmouse_softc), 204 wsmouse_match, wsmouse_attach, wsmouse_detach, wsmouse_activate); 205 206 static void wsmouse_repeat(void *v); 207 208 dev_type_open(wsmouseopen); 209 dev_type_close(wsmouseclose); 210 dev_type_read(wsmouseread); 211 dev_type_ioctl(wsmouseioctl); 212 dev_type_poll(wsmousepoll); 213 dev_type_kqfilter(wsmousekqfilter); 214 215 const struct cdevsw wsmouse_cdevsw = { 216 .d_open = wsmouseopen, 217 .d_close = wsmouseclose, 218 .d_read = wsmouseread, 219 .d_write = nowrite, 220 .d_ioctl = wsmouseioctl, 221 .d_stop = nostop, 222 .d_tty = notty, 223 .d_poll = wsmousepoll, 224 .d_mmap = nommap, 225 .d_kqfilter = wsmousekqfilter, 226 .d_discard = nodiscard, 227 .d_flag = D_OTHER 228 }; 229 230 #if NWSMUX > 0 231 struct wssrcops wsmouse_srcops = { 232 WSMUX_MOUSE, 233 wsmouse_mux_open, wsmouse_mux_close, wsmousedoioctl, NULL, NULL 234 }; 235 #endif 236 237 /* 238 * Print function (for parent devices). 239 */ 240 int 241 wsmousedevprint(void *aux, const char *pnp) 242 { 243 244 if (pnp) 245 aprint_normal("wsmouse at %s", pnp); 246 return (UNCONF); 247 } 248 249 int 250 wsmouse_match(device_t parent, cfdata_t match, void *aux) 251 { 252 return (1); 253 } 254 255 void 256 wsmouse_attach(device_t parent, device_t self, void *aux) 257 { 258 struct wsmouse_softc *sc = device_private(self); 259 struct wsmousedev_attach_args *ap = aux; 260 #if NWSMUX > 0 261 int mux, error; 262 #endif 263 264 sc->sc_base.me_dv = self; 265 sc->sc_accessops = ap->accessops; 266 sc->sc_accesscookie = ap->accesscookie; 267 268 /* Initialize button repeating. */ 269 memset(&sc->sc_repeat, 0, sizeof(sc->sc_repeat)); 270 sc->sc_repeat_button = -1; 271 sc->sc_repeat_delay = 0; 272 sc->sc_reverse_scroll = 0; 273 sc->sc_horiz_scroll_dist = WSMOUSE_DEFAULT_SCROLL_DIST; 274 sc->sc_vert_scroll_dist = WSMOUSE_DEFAULT_SCROLL_DIST; 275 callout_init(&sc->sc_repeat_callout, 0); 276 callout_setfunc(&sc->sc_repeat_callout, wsmouse_repeat, sc); 277 278 #if NWSMUX > 0 279 sc->sc_base.me_ops = &wsmouse_srcops; 280 mux = device_cfdata(self)->wsmousedevcf_mux; 281 if (mux >= 0) { 282 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 283 if (error) 284 aprint_error(" attach error=%d", error); 285 else 286 aprint_normal(" mux %d", mux); 287 } 288 #else 289 if (device_cfdata(self)->wsmousedevcf_mux >= 0) 290 aprint_normal(" (mux ignored)"); 291 #endif 292 293 aprint_naive("\n"); 294 aprint_normal("\n"); 295 296 if (!pmf_device_register(self, NULL, NULL)) 297 aprint_error_dev(self, "couldn't establish power handler\n"); 298 } 299 300 int 301 wsmouse_activate(device_t self, enum devact act) 302 { 303 struct wsmouse_softc *sc = device_private(self); 304 305 if (act == DVACT_DEACTIVATE) 306 sc->sc_dying = 1; 307 return (0); 308 } 309 310 /* 311 * Detach a mouse. To keep track of users of the softc we keep 312 * a reference count that's incremented while inside, e.g., read. 313 * If the mouse is active and the reference count is > 0 (0 is the 314 * normal state) we post an event and then wait for the process 315 * that had the reference to wake us up again. Then we blow away the 316 * vnode and return (which will deallocate the softc). 317 */ 318 int 319 wsmouse_detach(device_t self, int flags) 320 { 321 struct wsmouse_softc *sc = device_private(self); 322 struct wseventvar *evar; 323 int maj, mn; 324 int s; 325 326 #if NWSMUX > 0 327 /* Tell parent mux we're leaving. */ 328 if (sc->sc_base.me_parent != NULL) { 329 DPRINTF(("wsmouse_detach:\n")); 330 wsmux_detach_sc(&sc->sc_base); 331 } 332 #endif 333 334 /* If we're open ... */ 335 evar = sc->sc_base.me_evp; 336 if (evar != NULL && evar->io != NULL) { 337 s = spltty(); 338 if (--sc->sc_refcnt >= 0) { 339 struct wscons_event event; 340 341 /* Wake everyone by generating a dummy event. */ 342 event.type = 0; 343 event.value = 0; 344 if (wsevent_inject(evar, &event, 1) != 0) 345 wsevent_wakeup(evar); 346 347 /* Wait for processes to go away. */ 348 if (tsleep(sc, PZERO, "wsmdet", hz * 60)) 349 printf("wsmouse_detach: %s didn't detach\n", 350 device_xname(self)); 351 } 352 splx(s); 353 } 354 355 /* locate the major number */ 356 maj = cdevsw_lookup_major(&wsmouse_cdevsw); 357 358 /* Nuke the vnodes for any open instances (calls close). */ 359 mn = device_unit(self); 360 vdevgone(maj, mn, mn, VCHR); 361 362 return (0); 363 } 364 365 void 366 wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */, 367 int x, int y, int z, int w, u_int flags) 368 { 369 struct wsmouse_softc *sc = device_private(wsmousedev); 370 struct wseventvar *evar; 371 int mb, ub, d, nevents; 372 /* one for each dimension (4) + a bit for each button */ 373 struct wscons_event events[4 + sizeof(d) * 8]; 374 375 KERNEL_LOCK(1, NULL); 376 377 /* 378 * Discard input if not open. 379 */ 380 evar = sc->sc_base.me_evp; 381 if (evar == NULL) 382 goto out; 383 384 #ifdef DIAGNOSTIC 385 if (evar->q == NULL) { 386 printf("wsmouse_input: evar->q=NULL\n"); 387 goto out; 388 } 389 #endif 390 391 #if NWSMUX > 0 392 DPRINTFN(5,("wsmouse_input: %s mux=%p, evar=%p\n", 393 device_xname(sc->sc_base.me_dv), 394 sc->sc_base.me_parent, evar)); 395 #endif 396 397 sc->sc_mb = btns; 398 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X)) 399 sc->sc_dx += x; 400 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y)) 401 sc->sc_dy += y; 402 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z)) 403 sc->sc_dz += z; 404 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W)) 405 sc->sc_dw += w; 406 407 /* 408 * We have at least one event (mouse button, delta-X, or 409 * delta-Y; possibly all three, and possibly three separate 410 * button events). Deliver these events until we are out 411 * of changes or out of room. As events get delivered, 412 * mark them `unchanged'. 413 */ 414 ub = sc->sc_ub; 415 nevents = 0; 416 417 if (flags & WSMOUSE_INPUT_ABSOLUTE_X) { 418 if (sc->sc_x != x) { 419 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_X; 420 events[nevents].value = x; 421 nevents++; 422 } 423 } else { 424 if (sc->sc_dx) { 425 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_X; 426 events[nevents].value = sc->sc_dx; 427 nevents++; 428 } 429 } 430 if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) { 431 if (sc->sc_y != y) { 432 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y; 433 events[nevents].value = y; 434 nevents++; 435 } 436 } else { 437 if (sc->sc_dy) { 438 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Y; 439 events[nevents].value = sc->sc_dy; 440 nevents++; 441 } 442 } 443 if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) { 444 if (sc->sc_z != z) { 445 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z; 446 events[nevents].value = z; 447 nevents++; 448 } 449 } else { 450 if (sc->sc_dz) { 451 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Z; 452 events[nevents].value = sc->sc_dz; 453 nevents++; 454 } 455 } 456 if (flags & WSMOUSE_INPUT_ABSOLUTE_W) { 457 if (sc->sc_w != w) { 458 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_W; 459 events[nevents].value = w; 460 nevents++; 461 } 462 } else { 463 if (sc->sc_dw) { 464 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_W; 465 events[nevents].value = sc->sc_dw; 466 nevents++; 467 } 468 } 469 470 mb = sc->sc_mb; 471 while ((d = mb ^ ub) != 0) { 472 int btnno; 473 474 /* 475 * Cancel button repeating if button status changed. 476 */ 477 if (sc->sc_repeat_button != -1) { 478 KASSERT(sc->sc_repeat_button >= 0); 479 KASSERT(sc->sc_repeat.wr_buttons & 480 (1 << sc->sc_repeat_button)); 481 ub &= ~(1 << sc->sc_repeat_button); 482 sc->sc_repeat_button = -1; 483 callout_stop(&sc->sc_repeat_callout); 484 } 485 486 /* 487 * Mouse button change. Find the first change and drop 488 * it into the event queue. 489 */ 490 btnno = ffs(d) - 1; 491 KASSERT(btnno >= 0); 492 493 if (nevents >= __arraycount(events)) { 494 aprint_error_dev(sc->sc_base.me_dv, 495 "Event queue full (button status mb=0x%x" 496 " ub=0x%x)\n", mb, ub); 497 break; 498 } 499 500 events[nevents].type = 501 (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP; 502 events[nevents].value = btnno; 503 nevents++; 504 505 ub ^= (1 << btnno); 506 507 /* 508 * Program button repeating if configured for this button. 509 */ 510 if ((mb & d) && (sc->sc_repeat.wr_buttons & (1 << btnno)) && 511 sc->sc_repeat.wr_delay_first > 0) { 512 sc->sc_repeat_button = btnno; 513 sc->sc_repeat_delay = sc->sc_repeat.wr_delay_first; 514 callout_schedule(&sc->sc_repeat_callout, 515 mstohz(sc->sc_repeat_delay)); 516 } 517 } 518 519 if (nevents == 0 || wsevent_inject(evar, events, nevents) == 0) { 520 /* All events were correctly injected into the queue. 521 * Synchronize the mouse's status with what the user 522 * has received. */ 523 sc->sc_x = x; sc->sc_dx = 0; 524 sc->sc_y = y; sc->sc_dy = 0; 525 sc->sc_z = z; sc->sc_dz = 0; 526 sc->sc_w = w; sc->sc_dw = 0; 527 sc->sc_ub = ub; 528 #if NWSMUX > 0 529 DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n", 530 device_xname(sc->sc_base.me_dv), evar)); 531 #endif 532 } 533 534 out: KERNEL_UNLOCK_ONE(NULL); 535 } 536 537 void 538 wsmouse_precision_scroll(device_t wsmousedev, int x, int y) 539 { 540 struct wsmouse_softc *sc = device_private(wsmousedev); 541 struct wseventvar *evar; 542 struct wscons_event events[2]; 543 int nevents = 0; 544 545 evar = sc->sc_base.me_evp; 546 if (evar == NULL) 547 return; 548 549 if (sc->sc_reverse_scroll) { 550 x = -x; 551 y = -y; 552 } 553 554 x = (x * 4096) / sc->sc_horiz_scroll_dist; 555 y = (y * 4096) / sc->sc_vert_scroll_dist; 556 557 if (x != 0) { 558 events[nevents].type = WSCONS_EVENT_HSCROLL; 559 events[nevents].value = x; 560 nevents++; 561 } 562 563 if (y != 0) { 564 events[nevents].type = WSCONS_EVENT_VSCROLL; 565 events[nevents].value = y; 566 nevents++; 567 } 568 569 (void)wsevent_inject(evar, events, nevents); 570 } 571 572 static void 573 wsmouse_repeat(void *v) 574 { 575 int oldspl; 576 unsigned int newdelay; 577 struct wsmouse_softc *sc; 578 struct wscons_event events[2]; 579 580 oldspl = spltty(); 581 sc = (struct wsmouse_softc *)v; 582 583 if (sc->sc_repeat_button == -1) { 584 /* Race condition: a "button up" event came in when 585 * this function was already called but did not do 586 * spltty() yet. */ 587 splx(oldspl); 588 return; 589 } 590 KASSERT(sc->sc_repeat_button >= 0); 591 592 KASSERT(sc->sc_repeat.wr_buttons & (1 << sc->sc_repeat_button)); 593 594 newdelay = sc->sc_repeat_delay; 595 596 events[0].type = WSCONS_EVENT_MOUSE_UP; 597 events[0].value = sc->sc_repeat_button; 598 events[1].type = WSCONS_EVENT_MOUSE_DOWN; 599 events[1].value = sc->sc_repeat_button; 600 601 if (wsevent_inject(sc->sc_base.me_evp, events, 2) == 0) { 602 sc->sc_ub = 1 << sc->sc_repeat_button; 603 604 if (newdelay - sc->sc_repeat.wr_delay_decrement < 605 sc->sc_repeat.wr_delay_minimum) 606 newdelay = sc->sc_repeat.wr_delay_minimum; 607 else if (newdelay > sc->sc_repeat.wr_delay_minimum) 608 newdelay -= sc->sc_repeat.wr_delay_decrement; 609 KASSERT(newdelay >= sc->sc_repeat.wr_delay_minimum); 610 KASSERT(newdelay <= sc->sc_repeat.wr_delay_first); 611 } 612 613 /* 614 * Reprogram the repeating event. 615 */ 616 sc->sc_repeat_delay = newdelay; 617 callout_schedule(&sc->sc_repeat_callout, mstohz(newdelay)); 618 619 splx(oldspl); 620 } 621 622 static int 623 wsmouse_set_params(struct wsmouse_softc *sc, 624 struct wsmouse_param *buf, size_t nparams) 625 { 626 size_t i = 0; 627 628 for (i = 0; i < nparams; ++i) { 629 switch (buf[i].key) { 630 case WSMOUSECFG_REVERSE_SCROLLING: 631 sc->sc_reverse_scroll = (buf[i].value != 0); 632 break; 633 case WSMOUSECFG_HORIZSCROLLDIST: 634 sc->sc_horiz_scroll_dist = buf[i].value; 635 break; 636 case WSMOUSECFG_VERTSCROLLDIST: 637 sc->sc_vert_scroll_dist = buf[i].value; 638 break; 639 } 640 } 641 return 0; 642 } 643 644 static int 645 wsmouse_get_params(struct wsmouse_softc *sc, 646 struct wsmouse_param *buf, size_t nparams) 647 { 648 size_t i = 0; 649 650 for (i = 0; i < nparams; ++i) { 651 switch (buf[i].key) { 652 case WSMOUSECFG_REVERSE_SCROLLING: 653 buf[i].value = sc->sc_reverse_scroll; 654 break; 655 case WSMOUSECFG_HORIZSCROLLDIST: 656 buf[i].value = sc->sc_horiz_scroll_dist; 657 break; 658 case WSMOUSECFG_VERTSCROLLDIST: 659 buf[i].value = sc->sc_vert_scroll_dist; 660 break; 661 } 662 } 663 return 0; 664 } 665 666 static int 667 wsmouse_handle_params(struct wsmouse_softc *sc, struct wsmouse_parameters *upl, 668 bool set) 669 { 670 size_t len; 671 struct wsmouse_param *buf; 672 int error = 0; 673 674 if (upl->params == NULL || upl->nparams > WSMOUSECFG_MAX) 675 return EINVAL; 676 if (upl->nparams == 0) 677 return 0; 678 679 len = upl->nparams * sizeof(struct wsmouse_param); 680 681 buf = kmem_alloc(len, KM_SLEEP); 682 if (buf == NULL) 683 return ENOMEM; 684 if ((error = copyin(upl->params, buf, len)) != 0) 685 goto error; 686 687 if (set) { 688 error = wsmouse_set_params(sc, buf, upl->nparams); 689 if (error != 0) 690 goto error; 691 } else { 692 error = wsmouse_get_params(sc, buf, upl->nparams); 693 if (error != 0) 694 goto error; 695 if ((error = copyout(buf, upl->params, len)) != 0) 696 goto error; 697 } 698 699 error: 700 kmem_free(buf, len); 701 return error; 702 } 703 704 int 705 wsmouseopen(dev_t dev, int flags, int mode, struct lwp *l) 706 { 707 struct wsmouse_softc *sc; 708 struct wseventvar *evar; 709 int error; 710 711 sc = device_lookup_private(&wsmouse_cd, minor(dev)); 712 if (sc == NULL) 713 return ENXIO; 714 715 #if NWSMUX > 0 716 DPRINTF(("wsmouseopen: %s mux=%p p=%p\n", device_xname(sc->sc_base.me_dv), 717 sc->sc_base.me_parent, l)); 718 #endif 719 720 if (sc->sc_dying) 721 return (EIO); 722 723 if ((flags & (FREAD | FWRITE)) == FWRITE) 724 return (0); /* always allow open for write 725 so ioctl() is possible. */ 726 727 if (sc->sc_base.me_evp != NULL) 728 return (EBUSY); 729 730 evar = &sc->sc_base.me_evar; 731 wsevent_init(evar, l->l_proc); 732 sc->sc_base.me_evp = evar; 733 734 error = wsmousedoopen(sc, evar); 735 if (error) { 736 DPRINTF(("wsmouseopen: %s open failed\n", 737 device_xname(sc->sc_base.me_dv))); 738 sc->sc_base.me_evp = NULL; 739 wsevent_fini(evar); 740 } 741 return (error); 742 } 743 744 int 745 wsmouseclose(dev_t dev, int flags, int mode, 746 struct lwp *l) 747 { 748 struct wsmouse_softc *sc = 749 device_lookup_private(&wsmouse_cd, minor(dev)); 750 struct wseventvar *evar = sc->sc_base.me_evp; 751 752 if (evar == NULL) 753 /* not open for read */ 754 return (0); 755 sc->sc_base.me_evp = NULL; 756 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 757 wsevent_fini(evar); 758 759 return (0); 760 } 761 762 int 763 wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp) 764 { 765 sc->sc_base.me_evp = evp; 766 sc->sc_x = INVALID_X; 767 sc->sc_y = INVALID_Y; 768 sc->sc_z = INVALID_Z; 769 sc->sc_w = INVALID_W; 770 771 /* Stop button repeating when messing with the device. */ 772 if (sc->sc_repeat_button != -1) { 773 KASSERT(sc->sc_repeat_button >= 0); 774 sc->sc_repeat_button = -1; 775 callout_stop(&sc->sc_repeat_callout); 776 } 777 778 /* enable the device, and punt if that's not possible */ 779 return (*sc->sc_accessops->enable)(sc->sc_accesscookie); 780 } 781 782 int 783 wsmouseread(dev_t dev, struct uio *uio, int flags) 784 { 785 struct wsmouse_softc *sc = 786 device_lookup_private(&wsmouse_cd, minor(dev)); 787 int error; 788 789 if (sc->sc_dying) 790 return (EIO); 791 792 #ifdef DIAGNOSTIC 793 if (sc->sc_base.me_evp == NULL) { 794 printf("wsmouseread: evp == NULL\n"); 795 return (EINVAL); 796 } 797 #endif 798 799 sc->sc_refcnt++; 800 error = wsevent_read(sc->sc_base.me_evp, uio, flags); 801 if (--sc->sc_refcnt < 0) { 802 wakeup(sc); 803 error = EIO; 804 } 805 return (error); 806 } 807 808 int 809 wsmouseioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 810 { 811 return (wsmousedoioctl(device_lookup(&wsmouse_cd, minor(dev)), 812 cmd, data, flag, l)); 813 } 814 815 /* A wrapper around the ioctl() workhorse to make reference counting easy. */ 816 int 817 wsmousedoioctl(device_t dv, u_long cmd, void *data, int flag, 818 struct lwp *l) 819 { 820 struct wsmouse_softc *sc = device_private(dv); 821 int error; 822 823 sc->sc_refcnt++; 824 error = wsmouse_do_ioctl(sc, cmd, data, flag, l); 825 if (--sc->sc_refcnt < 0) 826 wakeup(sc); 827 return (error); 828 } 829 830 int 831 wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, void *data, 832 int flag, struct lwp *l) 833 { 834 int error; 835 struct wsmouse_repeat *wr; 836 837 if (sc->sc_dying) 838 return (EIO); 839 840 /* 841 * Try the generic ioctls that the wsmouse interface supports. 842 */ 843 switch (cmd) { 844 case FIONBIO: /* we will remove this someday (soon???) */ 845 return (0); 846 847 case FIOASYNC: 848 if (sc->sc_base.me_evp == NULL) 849 return (EINVAL); 850 sc->sc_base.me_evp->async = *(int *)data != 0; 851 return (0); 852 853 case FIOSETOWN: 854 if (sc->sc_base.me_evp == NULL) 855 return (EINVAL); 856 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid 857 && *(int *)data != sc->sc_base.me_evp->io->p_pid) 858 return (EPERM); 859 return (0); 860 861 case TIOCSPGRP: 862 if (sc->sc_base.me_evp == NULL) 863 return (EINVAL); 864 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid) 865 return (EPERM); 866 return (0); 867 } 868 869 /* 870 * Try the wsmouse specific ioctls. 871 */ 872 switch (cmd) { 873 case WSMOUSEIO_GETREPEAT: 874 wr = (struct wsmouse_repeat *)data; 875 memcpy(wr, &sc->sc_repeat, sizeof(sc->sc_repeat)); 876 return 0; 877 878 case WSMOUSEIO_SETREPEAT: 879 if ((flag & FWRITE) == 0) 880 return EACCES; 881 882 /* Validate input data. */ 883 wr = (struct wsmouse_repeat *)data; 884 if (wr->wr_delay_first != 0 && 885 (wr->wr_delay_first < wr->wr_delay_decrement || 886 wr->wr_delay_first < wr->wr_delay_minimum || 887 wr->wr_delay_first < wr->wr_delay_minimum + 888 wr->wr_delay_decrement)) 889 return EINVAL; 890 891 /* Stop current repeating and set new data. */ 892 sc->sc_repeat_button = -1; 893 callout_stop(&sc->sc_repeat_callout); 894 memcpy(&sc->sc_repeat, wr, sizeof(sc->sc_repeat)); 895 896 return 0; 897 898 case WSMOUSEIO_SETVERSION: 899 return wsevent_setversion(sc->sc_base.me_evp, *(int *)data); 900 901 case WSMOUSEIO_GETPARAMS: 902 return wsmouse_handle_params(sc, 903 (struct wsmouse_parameters *)data, false); 904 905 case WSMOUSEIO_SETPARAMS: 906 if ((flag & FWRITE) == 0) 907 return EACCES; 908 return wsmouse_handle_params(sc, 909 (struct wsmouse_parameters *)data, true); 910 } 911 912 /* 913 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1 914 * if it didn't recognize the request. 915 */ 916 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 917 data, flag, l); 918 return (error); /* may be EPASSTHROUGH */ 919 } 920 921 int 922 wsmousepoll(dev_t dev, int events, struct lwp *l) 923 { 924 struct wsmouse_softc *sc = 925 device_lookup_private(&wsmouse_cd, minor(dev)); 926 927 if (sc->sc_base.me_evp == NULL) 928 return (POLLERR); 929 return (wsevent_poll(sc->sc_base.me_evp, events, l)); 930 } 931 932 int 933 wsmousekqfilter(dev_t dev, struct knote *kn) 934 { 935 struct wsmouse_softc *sc = 936 device_lookup_private(&wsmouse_cd, minor(dev)); 937 938 if (sc->sc_base.me_evp == NULL) 939 return (1); 940 return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); 941 } 942 943 #if NWSMUX > 0 944 int 945 wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp) 946 { 947 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 948 949 if (sc->sc_base.me_evp != NULL) 950 return (EBUSY); 951 952 return wsmousedoopen(sc, evp); 953 } 954 955 int 956 wsmouse_mux_close(struct wsevsrc *me) 957 { 958 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 959 960 sc->sc_base.me_evp = NULL; 961 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 962 963 return (0); 964 } 965 966 int 967 wsmouse_add_mux(int unit, struct wsmux_softc *muxsc) 968 { 969 struct wsmouse_softc *sc; 970 971 sc = device_lookup_private(&wsmouse_cd, unit); 972 if (sc == NULL) 973 return ENXIO; 974 975 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 976 return (EBUSY); 977 978 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 979 } 980 #endif /* NWSMUX > 0 */ 981