1 /* $NetBSD: wsmouse.c,v 1.72 2022/07/17 11:44:30 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.72 2022/07/17 11:44:30 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 /* 376 * Discard input if not open. 377 */ 378 evar = sc->sc_base.me_evp; 379 if (evar == NULL) 380 return; 381 382 #ifdef DIAGNOSTIC 383 if (evar->q == NULL) { 384 printf("wsmouse_input: evar->q=NULL\n"); 385 return; 386 } 387 #endif 388 389 #if NWSMUX > 0 390 DPRINTFN(5,("wsmouse_input: %s mux=%p, evar=%p\n", 391 device_xname(sc->sc_base.me_dv), 392 sc->sc_base.me_parent, evar)); 393 #endif 394 395 sc->sc_mb = btns; 396 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X)) 397 sc->sc_dx += x; 398 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y)) 399 sc->sc_dy += y; 400 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z)) 401 sc->sc_dz += z; 402 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W)) 403 sc->sc_dw += w; 404 405 /* 406 * We have at least one event (mouse button, delta-X, or 407 * delta-Y; possibly all three, and possibly three separate 408 * button events). Deliver these events until we are out 409 * of changes or out of room. As events get delivered, 410 * mark them `unchanged'. 411 */ 412 ub = sc->sc_ub; 413 nevents = 0; 414 415 if (flags & WSMOUSE_INPUT_ABSOLUTE_X) { 416 if (sc->sc_x != x) { 417 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_X; 418 events[nevents].value = x; 419 nevents++; 420 } 421 } else { 422 if (sc->sc_dx) { 423 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_X; 424 events[nevents].value = sc->sc_dx; 425 nevents++; 426 } 427 } 428 if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) { 429 if (sc->sc_y != y) { 430 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y; 431 events[nevents].value = y; 432 nevents++; 433 } 434 } else { 435 if (sc->sc_dy) { 436 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Y; 437 events[nevents].value = sc->sc_dy; 438 nevents++; 439 } 440 } 441 if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) { 442 if (sc->sc_z != z) { 443 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z; 444 events[nevents].value = z; 445 nevents++; 446 } 447 } else { 448 if (sc->sc_dz) { 449 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Z; 450 events[nevents].value = sc->sc_dz; 451 nevents++; 452 } 453 } 454 if (flags & WSMOUSE_INPUT_ABSOLUTE_W) { 455 if (sc->sc_w != w) { 456 events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_W; 457 events[nevents].value = w; 458 nevents++; 459 } 460 } else { 461 if (sc->sc_dw) { 462 events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_W; 463 events[nevents].value = sc->sc_dw; 464 nevents++; 465 } 466 } 467 468 mb = sc->sc_mb; 469 while ((d = mb ^ ub) != 0) { 470 int btnno; 471 472 /* 473 * Cancel button repeating if button status changed. 474 */ 475 if (sc->sc_repeat_button != -1) { 476 KASSERT(sc->sc_repeat_button >= 0); 477 KASSERT(sc->sc_repeat.wr_buttons & 478 (1 << sc->sc_repeat_button)); 479 ub &= ~(1 << sc->sc_repeat_button); 480 sc->sc_repeat_button = -1; 481 callout_stop(&sc->sc_repeat_callout); 482 } 483 484 /* 485 * Mouse button change. Find the first change and drop 486 * it into the event queue. 487 */ 488 btnno = ffs(d) - 1; 489 KASSERT(btnno >= 0); 490 491 if (nevents >= __arraycount(events)) { 492 aprint_error_dev(sc->sc_base.me_dv, 493 "Event queue full (button status mb=0x%x" 494 " ub=0x%x)\n", mb, ub); 495 break; 496 } 497 498 events[nevents].type = 499 (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP; 500 events[nevents].value = btnno; 501 nevents++; 502 503 ub ^= (1 << btnno); 504 505 /* 506 * Program button repeating if configured for this button. 507 */ 508 if ((mb & d) && (sc->sc_repeat.wr_buttons & (1 << btnno)) && 509 sc->sc_repeat.wr_delay_first > 0) { 510 sc->sc_repeat_button = btnno; 511 sc->sc_repeat_delay = sc->sc_repeat.wr_delay_first; 512 callout_schedule(&sc->sc_repeat_callout, 513 mstohz(sc->sc_repeat_delay)); 514 } 515 } 516 517 if (nevents == 0 || wsevent_inject(evar, events, nevents) == 0) { 518 /* All events were correctly injected into the queue. 519 * Synchronize the mouse's status with what the user 520 * has received. */ 521 sc->sc_x = x; sc->sc_dx = 0; 522 sc->sc_y = y; sc->sc_dy = 0; 523 sc->sc_z = z; sc->sc_dz = 0; 524 sc->sc_w = w; sc->sc_dw = 0; 525 sc->sc_ub = ub; 526 #if NWSMUX > 0 527 DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n", 528 device_xname(sc->sc_base.me_dv), evar)); 529 #endif 530 } 531 } 532 533 void 534 wsmouse_precision_scroll(device_t wsmousedev, int x, int y) 535 { 536 struct wsmouse_softc *sc = device_private(wsmousedev); 537 struct wseventvar *evar; 538 struct wscons_event events[2]; 539 int nevents = 0; 540 541 evar = sc->sc_base.me_evp; 542 if (evar == NULL) 543 return; 544 545 if (sc->sc_reverse_scroll) { 546 x = -x; 547 y = -y; 548 } 549 550 x = (x * 4096) / sc->sc_horiz_scroll_dist; 551 y = (y * 4096) / sc->sc_vert_scroll_dist; 552 553 if (x != 0) { 554 events[nevents].type = WSCONS_EVENT_HSCROLL; 555 events[nevents].value = x; 556 nevents++; 557 } 558 559 if (y != 0) { 560 events[nevents].type = WSCONS_EVENT_VSCROLL; 561 events[nevents].value = y; 562 nevents++; 563 } 564 565 (void)wsevent_inject(evar, events, nevents); 566 } 567 568 static void 569 wsmouse_repeat(void *v) 570 { 571 int oldspl; 572 unsigned int newdelay; 573 struct wsmouse_softc *sc; 574 struct wscons_event events[2]; 575 576 oldspl = spltty(); 577 sc = (struct wsmouse_softc *)v; 578 579 if (sc->sc_repeat_button == -1) { 580 /* Race condition: a "button up" event came in when 581 * this function was already called but did not do 582 * spltty() yet. */ 583 splx(oldspl); 584 return; 585 } 586 KASSERT(sc->sc_repeat_button >= 0); 587 588 KASSERT(sc->sc_repeat.wr_buttons & (1 << sc->sc_repeat_button)); 589 590 newdelay = sc->sc_repeat_delay; 591 592 events[0].type = WSCONS_EVENT_MOUSE_UP; 593 events[0].value = sc->sc_repeat_button; 594 events[1].type = WSCONS_EVENT_MOUSE_DOWN; 595 events[1].value = sc->sc_repeat_button; 596 597 if (wsevent_inject(sc->sc_base.me_evp, events, 2) == 0) { 598 sc->sc_ub = 1 << sc->sc_repeat_button; 599 600 if (newdelay - sc->sc_repeat.wr_delay_decrement < 601 sc->sc_repeat.wr_delay_minimum) 602 newdelay = sc->sc_repeat.wr_delay_minimum; 603 else if (newdelay > sc->sc_repeat.wr_delay_minimum) 604 newdelay -= sc->sc_repeat.wr_delay_decrement; 605 KASSERT(newdelay >= sc->sc_repeat.wr_delay_minimum); 606 KASSERT(newdelay <= sc->sc_repeat.wr_delay_first); 607 } 608 609 /* 610 * Reprogram the repeating event. 611 */ 612 sc->sc_repeat_delay = newdelay; 613 callout_schedule(&sc->sc_repeat_callout, mstohz(newdelay)); 614 615 splx(oldspl); 616 } 617 618 static int 619 wsmouse_set_params(struct wsmouse_softc *sc, 620 struct wsmouse_param *buf, size_t nparams) 621 { 622 size_t i = 0; 623 624 for (i = 0; i < nparams; ++i) { 625 switch (buf[i].key) { 626 case WSMOUSECFG_REVERSE_SCROLLING: 627 sc->sc_reverse_scroll = (buf[i].value != 0); 628 break; 629 case WSMOUSECFG_HORIZSCROLLDIST: 630 sc->sc_horiz_scroll_dist = buf[i].value; 631 break; 632 case WSMOUSECFG_VERTSCROLLDIST: 633 sc->sc_vert_scroll_dist = buf[i].value; 634 break; 635 } 636 } 637 return 0; 638 } 639 640 static int 641 wsmouse_get_params(struct wsmouse_softc *sc, 642 struct wsmouse_param *buf, size_t nparams) 643 { 644 size_t i = 0; 645 646 for (i = 0; i < nparams; ++i) { 647 switch (buf[i].key) { 648 case WSMOUSECFG_REVERSE_SCROLLING: 649 buf[i].value = sc->sc_reverse_scroll; 650 break; 651 case WSMOUSECFG_HORIZSCROLLDIST: 652 buf[i].value = sc->sc_horiz_scroll_dist; 653 break; 654 case WSMOUSECFG_VERTSCROLLDIST: 655 buf[i].value = sc->sc_vert_scroll_dist; 656 break; 657 } 658 } 659 return 0; 660 } 661 662 static int 663 wsmouse_handle_params(struct wsmouse_softc *sc, struct wsmouse_parameters *upl, 664 bool set) 665 { 666 size_t len; 667 struct wsmouse_param *buf; 668 int error = 0; 669 670 if (upl->params == NULL || upl->nparams > WSMOUSECFG_MAX) 671 return EINVAL; 672 if (upl->nparams == 0) 673 return 0; 674 675 len = upl->nparams * sizeof(struct wsmouse_param); 676 677 buf = kmem_alloc(len, KM_SLEEP); 678 if (buf == NULL) 679 return ENOMEM; 680 if ((error = copyin(upl->params, buf, len)) != 0) 681 goto error; 682 683 if (set) { 684 error = wsmouse_set_params(sc, buf, upl->nparams); 685 if (error != 0) 686 goto error; 687 } else { 688 error = wsmouse_get_params(sc, buf, upl->nparams); 689 if (error != 0) 690 goto error; 691 if ((error = copyout(buf, upl->params, len)) != 0) 692 goto error; 693 } 694 695 error: 696 kmem_free(buf, len); 697 return error; 698 } 699 700 int 701 wsmouseopen(dev_t dev, int flags, int mode, struct lwp *l) 702 { 703 struct wsmouse_softc *sc; 704 struct wseventvar *evar; 705 int error; 706 707 sc = device_lookup_private(&wsmouse_cd, minor(dev)); 708 if (sc == NULL) 709 return ENXIO; 710 711 #if NWSMUX > 0 712 DPRINTF(("wsmouseopen: %s mux=%p p=%p\n", device_xname(sc->sc_base.me_dv), 713 sc->sc_base.me_parent, l)); 714 #endif 715 716 if (sc->sc_dying) 717 return (EIO); 718 719 if ((flags & (FREAD | FWRITE)) == FWRITE) 720 return (0); /* always allow open for write 721 so ioctl() is possible. */ 722 723 if (sc->sc_base.me_evp != NULL) 724 return (EBUSY); 725 726 evar = &sc->sc_base.me_evar; 727 wsevent_init(evar, l->l_proc); 728 sc->sc_base.me_evp = evar; 729 730 error = wsmousedoopen(sc, evar); 731 if (error) { 732 DPRINTF(("wsmouseopen: %s open failed\n", 733 device_xname(sc->sc_base.me_dv))); 734 sc->sc_base.me_evp = NULL; 735 wsevent_fini(evar); 736 } 737 return (error); 738 } 739 740 int 741 wsmouseclose(dev_t dev, int flags, int mode, 742 struct lwp *l) 743 { 744 struct wsmouse_softc *sc = 745 device_lookup_private(&wsmouse_cd, minor(dev)); 746 struct wseventvar *evar = sc->sc_base.me_evp; 747 748 if (evar == NULL) 749 /* not open for read */ 750 return (0); 751 sc->sc_base.me_evp = NULL; 752 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 753 wsevent_fini(evar); 754 755 return (0); 756 } 757 758 int 759 wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp) 760 { 761 sc->sc_base.me_evp = evp; 762 sc->sc_x = INVALID_X; 763 sc->sc_y = INVALID_Y; 764 sc->sc_z = INVALID_Z; 765 sc->sc_w = INVALID_W; 766 767 /* Stop button repeating when messing with the device. */ 768 if (sc->sc_repeat_button != -1) { 769 KASSERT(sc->sc_repeat_button >= 0); 770 sc->sc_repeat_button = -1; 771 callout_stop(&sc->sc_repeat_callout); 772 } 773 774 /* enable the device, and punt if that's not possible */ 775 return (*sc->sc_accessops->enable)(sc->sc_accesscookie); 776 } 777 778 int 779 wsmouseread(dev_t dev, struct uio *uio, int flags) 780 { 781 struct wsmouse_softc *sc = 782 device_lookup_private(&wsmouse_cd, minor(dev)); 783 int error; 784 785 if (sc->sc_dying) 786 return (EIO); 787 788 #ifdef DIAGNOSTIC 789 if (sc->sc_base.me_evp == NULL) { 790 printf("wsmouseread: evp == NULL\n"); 791 return (EINVAL); 792 } 793 #endif 794 795 sc->sc_refcnt++; 796 error = wsevent_read(sc->sc_base.me_evp, uio, flags); 797 if (--sc->sc_refcnt < 0) { 798 wakeup(sc); 799 error = EIO; 800 } 801 return (error); 802 } 803 804 int 805 wsmouseioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 806 { 807 return (wsmousedoioctl(device_lookup(&wsmouse_cd, minor(dev)), 808 cmd, data, flag, l)); 809 } 810 811 /* A wrapper around the ioctl() workhorse to make reference counting easy. */ 812 int 813 wsmousedoioctl(device_t dv, u_long cmd, void *data, int flag, 814 struct lwp *l) 815 { 816 struct wsmouse_softc *sc = device_private(dv); 817 int error; 818 819 sc->sc_refcnt++; 820 error = wsmouse_do_ioctl(sc, cmd, data, flag, l); 821 if (--sc->sc_refcnt < 0) 822 wakeup(sc); 823 return (error); 824 } 825 826 int 827 wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, void *data, 828 int flag, struct lwp *l) 829 { 830 int error; 831 struct wsmouse_repeat *wr; 832 833 if (sc->sc_dying) 834 return (EIO); 835 836 /* 837 * Try the generic ioctls that the wsmouse interface supports. 838 */ 839 switch (cmd) { 840 case FIONBIO: /* we will remove this someday (soon???) */ 841 return (0); 842 843 case FIOASYNC: 844 if (sc->sc_base.me_evp == NULL) 845 return (EINVAL); 846 sc->sc_base.me_evp->async = *(int *)data != 0; 847 return (0); 848 849 case FIOSETOWN: 850 if (sc->sc_base.me_evp == NULL) 851 return (EINVAL); 852 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid 853 && *(int *)data != sc->sc_base.me_evp->io->p_pid) 854 return (EPERM); 855 return (0); 856 857 case TIOCSPGRP: 858 if (sc->sc_base.me_evp == NULL) 859 return (EINVAL); 860 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid) 861 return (EPERM); 862 return (0); 863 } 864 865 /* 866 * Try the wsmouse specific ioctls. 867 */ 868 switch (cmd) { 869 case WSMOUSEIO_GETREPEAT: 870 wr = (struct wsmouse_repeat *)data; 871 memcpy(wr, &sc->sc_repeat, sizeof(sc->sc_repeat)); 872 return 0; 873 874 case WSMOUSEIO_SETREPEAT: 875 if ((flag & FWRITE) == 0) 876 return EACCES; 877 878 /* Validate input data. */ 879 wr = (struct wsmouse_repeat *)data; 880 if (wr->wr_delay_first != 0 && 881 (wr->wr_delay_first < wr->wr_delay_decrement || 882 wr->wr_delay_first < wr->wr_delay_minimum || 883 wr->wr_delay_first < wr->wr_delay_minimum + 884 wr->wr_delay_decrement)) 885 return EINVAL; 886 887 /* Stop current repeating and set new data. */ 888 sc->sc_repeat_button = -1; 889 callout_stop(&sc->sc_repeat_callout); 890 memcpy(&sc->sc_repeat, wr, sizeof(sc->sc_repeat)); 891 892 return 0; 893 894 case WSMOUSEIO_SETVERSION: 895 return wsevent_setversion(sc->sc_base.me_evp, *(int *)data); 896 897 case WSMOUSEIO_GETPARAMS: 898 return wsmouse_handle_params(sc, 899 (struct wsmouse_parameters *)data, false); 900 901 case WSMOUSEIO_SETPARAMS: 902 if ((flag & FWRITE) == 0) 903 return EACCES; 904 return wsmouse_handle_params(sc, 905 (struct wsmouse_parameters *)data, true); 906 } 907 908 /* 909 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1 910 * if it didn't recognize the request. 911 */ 912 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 913 data, flag, l); 914 return (error); /* may be EPASSTHROUGH */ 915 } 916 917 int 918 wsmousepoll(dev_t dev, int events, struct lwp *l) 919 { 920 struct wsmouse_softc *sc = 921 device_lookup_private(&wsmouse_cd, minor(dev)); 922 923 if (sc->sc_base.me_evp == NULL) 924 return (POLLERR); 925 return (wsevent_poll(sc->sc_base.me_evp, events, l)); 926 } 927 928 int 929 wsmousekqfilter(dev_t dev, struct knote *kn) 930 { 931 struct wsmouse_softc *sc = 932 device_lookup_private(&wsmouse_cd, minor(dev)); 933 934 if (sc->sc_base.me_evp == NULL) 935 return (1); 936 return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); 937 } 938 939 #if NWSMUX > 0 940 int 941 wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp) 942 { 943 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 944 945 if (sc->sc_base.me_evp != NULL) 946 return (EBUSY); 947 948 return wsmousedoopen(sc, evp); 949 } 950 951 int 952 wsmouse_mux_close(struct wsevsrc *me) 953 { 954 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 955 956 sc->sc_base.me_evp = NULL; 957 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 958 959 return (0); 960 } 961 962 int 963 wsmouse_add_mux(int unit, struct wsmux_softc *muxsc) 964 { 965 struct wsmouse_softc *sc; 966 967 sc = device_lookup_private(&wsmouse_cd, unit); 968 if (sc == NULL) 969 return ENXIO; 970 971 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 972 return (EBUSY); 973 974 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 975 } 976 #endif /* NWSMUX > 0 */ 977