1 /* $OpenBSD: wsmouse.c,v 1.34 2016/08/18 21:12:35 bru Exp $ */ 2 /* $NetBSD: wsmouse.c,v 1.35 2005/02/27 00:27:52 perry Exp $ */ 3 4 /* 5 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou 18 * for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1992, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This software was developed by the Computer Systems Engineering group 39 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 40 * contributed to Berkeley. 41 * 42 * All advertising materials mentioning features or use of this software 43 * must display the following acknowledgement: 44 * This product includes software developed by the University of 45 * California, Lawrence Berkeley Laboratory. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)ms.c 8.1 (Berkeley) 6/11/93 72 */ 73 74 /* 75 * Copyright (c) 2015, 2016 Ulf Brosziewski 76 * 77 * Permission to use, copy, modify, and distribute this software for any 78 * purpose with or without fee is hereby granted, provided that the above 79 * copyright notice and this permission notice appear in all copies. 80 * 81 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 82 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 83 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 84 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 85 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 86 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 87 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 88 */ 89 90 /* 91 * Mouse driver. 92 */ 93 94 #include <sys/param.h> 95 #include <sys/conf.h> 96 #include <sys/ioctl.h> 97 #include <sys/fcntl.h> 98 #include <sys/kernel.h> 99 #include <sys/proc.h> 100 #include <sys/syslog.h> 101 #include <sys/systm.h> 102 #include <sys/tty.h> 103 #include <sys/signalvar.h> 104 #include <sys/device.h> 105 #include <sys/vnode.h> 106 #include <sys/poll.h> 107 #include <sys/malloc.h> 108 109 #include <dev/wscons/wscons_features.h> 110 #include <dev/wscons/wsconsio.h> 111 #include <dev/wscons/wsmousevar.h> 112 #include <dev/wscons/wsmouseinput.h> 113 #include <dev/wscons/wseventvar.h> 114 #include <dev/rndvar.h> 115 116 #include "wsmux.h" 117 #include "wsdisplay.h" 118 #include "wskbd.h" 119 120 #include <dev/wscons/wsmuxvar.h> 121 122 #if defined(WSMUX_DEBUG) && NWSMUX > 0 123 #define DPRINTF(x) if (wsmuxdebug) printf x 124 #define DPRINTFN(n,x) if (wsmuxdebug > (n)) printf x 125 extern int wsmuxdebug; 126 #else 127 #define DPRINTF(x) 128 #define DPRINTFN(n,x) 129 #endif 130 131 struct wsmouse_softc { 132 struct wsevsrc sc_base; 133 134 const struct wsmouse_accessops *sc_accessops; 135 void *sc_accesscookie; 136 137 struct wsmouseinput input; 138 139 int sc_refcnt; 140 u_char sc_dying; /* device is being detached */ 141 }; 142 143 int wsmouse_match(struct device *, void *, void *); 144 void wsmouse_attach(struct device *, struct device *, void *); 145 int wsmouse_detach(struct device *, int); 146 int wsmouse_activate(struct device *, int); 147 148 int wsmouse_do_ioctl(struct wsmouse_softc *, u_long, caddr_t, 149 int, struct proc *); 150 151 #if NWSMUX > 0 152 int wsmouse_mux_open(struct wsevsrc *, struct wseventvar *); 153 int wsmouse_mux_close(struct wsevsrc *); 154 #endif 155 156 int wsmousedoioctl(struct device *, u_long, caddr_t, int, 157 struct proc *); 158 int wsmousedoopen(struct wsmouse_softc *, struct wseventvar *); 159 160 struct cfdriver wsmouse_cd = { 161 NULL, "wsmouse", DV_TTY 162 }; 163 164 struct cfattach wsmouse_ca = { 165 sizeof (struct wsmouse_softc), wsmouse_match, wsmouse_attach, 166 wsmouse_detach, wsmouse_activate 167 }; 168 169 #if NWSMUX > 0 170 struct wssrcops wsmouse_srcops = { 171 WSMUX_MOUSE, 172 wsmouse_mux_open, wsmouse_mux_close, wsmousedoioctl, NULL, NULL 173 }; 174 #endif 175 176 /* 177 * Print function (for parent devices). 178 */ 179 int 180 wsmousedevprint(void *aux, const char *pnp) 181 { 182 183 if (pnp) 184 printf("wsmouse at %s", pnp); 185 return (UNCONF); 186 } 187 188 int 189 wsmouse_match(struct device *parent, void *match, void *aux) 190 { 191 return (1); 192 } 193 194 void 195 wsmouse_attach(struct device *parent, struct device *self, void *aux) 196 { 197 struct wsmouse_softc *sc = (struct wsmouse_softc *)self; 198 struct wsmousedev_attach_args *ap = aux; 199 #if NWSMUX > 0 200 int mux, error; 201 #endif 202 203 sc->sc_accessops = ap->accessops; 204 sc->sc_accesscookie = ap->accesscookie; 205 206 wsmouse_input_init(&sc->input, &sc->sc_base.me_evp); 207 208 #if NWSMUX > 0 209 sc->sc_base.me_ops = &wsmouse_srcops; 210 mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux; 211 if (mux >= 0) { 212 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 213 if (error) 214 printf(" attach error=%d", error); 215 else 216 printf(" mux %d", mux); 217 } 218 #else 219 #if 0 /* not worth keeping, especially since the default value is not -1... */ 220 if (sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux >= 0) 221 printf(" (mux ignored)"); 222 #endif 223 #endif /* NWSMUX > 0 */ 224 225 printf("\n"); 226 } 227 228 int 229 wsmouse_activate(struct device *self, int act) 230 { 231 struct wsmouse_softc *sc = (struct wsmouse_softc *)self; 232 233 if (act == DVACT_DEACTIVATE) 234 sc->sc_dying = 1; 235 return (0); 236 } 237 238 /* 239 * Detach a mouse. To keep track of users of the softc we keep 240 * a reference count that's incremented while inside, e.g., read. 241 * If the mouse is active and the reference count is > 0 (0 is the 242 * normal state) we post an event and then wait for the process 243 * that had the reference to wake us up again. Then we blow away the 244 * vnode and return (which will deallocate the softc). 245 */ 246 int 247 wsmouse_detach(struct device *self, int flags) 248 { 249 struct wsmouse_softc *sc = (struct wsmouse_softc *)self; 250 struct wseventvar *evar; 251 int maj, mn; 252 int s; 253 254 #if NWSMUX > 0 255 /* Tell parent mux we're leaving. */ 256 if (sc->sc_base.me_parent != NULL) { 257 DPRINTF(("wsmouse_detach:\n")); 258 wsmux_detach_sc(&sc->sc_base); 259 } 260 #endif 261 262 /* If we're open ... */ 263 evar = sc->sc_base.me_evp; 264 if (evar != NULL && evar->io != NULL) { 265 s = spltty(); 266 if (--sc->sc_refcnt >= 0) { 267 /* Wake everyone by generating a dummy event. */ 268 if (++evar->put >= WSEVENT_QSIZE) 269 evar->put = 0; 270 WSEVENT_WAKEUP(evar); 271 /* Wait for processes to go away. */ 272 if (tsleep(sc, PZERO, "wsmdet", hz * 60)) 273 printf("wsmouse_detach: %s didn't detach\n", 274 sc->sc_base.me_dv.dv_xname); 275 } 276 splx(s); 277 } 278 279 /* locate the major number */ 280 for (maj = 0; maj < nchrdev; maj++) 281 if (cdevsw[maj].d_open == wsmouseopen) 282 break; 283 284 /* Nuke the vnodes for any open instances (calls close). */ 285 mn = self->dv_unit; 286 vdevgone(maj, mn, mn, VCHR); 287 288 wsmouse_input_cleanup(&sc->input); 289 290 return (0); 291 } 292 293 int 294 wsmouseopen(dev_t dev, int flags, int mode, struct proc *p) 295 { 296 struct wsmouse_softc *sc; 297 struct wseventvar *evar; 298 int error, unit; 299 300 unit = minor(dev); 301 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */ 302 (sc = wsmouse_cd.cd_devs[unit]) == NULL) 303 return (ENXIO); 304 305 #if NWSMUX > 0 306 DPRINTF(("wsmouseopen: %s mux=%p p=%p\n", sc->sc_base.me_dv.dv_xname, 307 sc->sc_base.me_parent, p)); 308 #endif 309 310 if (sc->sc_dying) 311 return (EIO); 312 313 if ((flags & (FREAD | FWRITE)) == FWRITE) 314 return (0); /* always allow open for write 315 so ioctl() is possible. */ 316 317 #if NWSMUX > 0 318 if (sc->sc_base.me_parent != NULL) { 319 /* Grab the mouse out of the greedy hands of the mux. */ 320 DPRINTF(("wsmouseopen: detach\n")); 321 wsmux_detach_sc(&sc->sc_base); 322 } 323 #endif 324 325 if (sc->sc_base.me_evp != NULL) 326 return (EBUSY); 327 328 evar = &sc->sc_base.me_evar; 329 wsevent_init(evar); 330 evar->io = p->p_p; 331 332 error = wsmousedoopen(sc, evar); 333 if (error) { 334 DPRINTF(("wsmouseopen: %s open failed\n", 335 sc->sc_base.me_dv.dv_xname)); 336 sc->sc_base.me_evp = NULL; 337 wsevent_fini(evar); 338 } 339 return (error); 340 } 341 342 int 343 wsmouseclose(dev_t dev, int flags, int mode, struct proc *p) 344 { 345 struct wsmouse_softc *sc = 346 (struct wsmouse_softc *)wsmouse_cd.cd_devs[minor(dev)]; 347 struct wseventvar *evar = sc->sc_base.me_evp; 348 349 if ((flags & (FREAD | FWRITE)) == FWRITE) 350 return (0); /* see wsmouseopen() */ 351 352 if (evar == NULL) 353 /* not open for read */ 354 return (0); 355 sc->sc_base.me_evp = NULL; 356 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 357 wsevent_fini(evar); 358 359 #if NWSMUX > 0 360 if (sc->sc_base.me_parent == NULL) { 361 int mux, error; 362 363 DPRINTF(("wsmouseclose: attach\n")); 364 mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux; 365 if (mux >= 0) { 366 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 367 if (error) 368 printf("%s: can't attach mux (error=%d)\n", 369 sc->sc_base.me_dv.dv_xname, error); 370 } 371 } 372 #endif 373 374 return (0); 375 } 376 377 int 378 wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp) 379 { 380 sc->sc_base.me_evp = evp; 381 382 wsmouse_input_reset(&sc->input); 383 384 /* enable the device, and punt if that's not possible */ 385 return (*sc->sc_accessops->enable)(sc->sc_accesscookie); 386 } 387 388 int 389 wsmouseread(dev_t dev, struct uio *uio, int flags) 390 { 391 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)]; 392 int error; 393 394 if (sc->sc_dying) 395 return (EIO); 396 397 #ifdef DIAGNOSTIC 398 if (sc->sc_base.me_evp == NULL) { 399 printf("wsmouseread: evp == NULL\n"); 400 return (EINVAL); 401 } 402 #endif 403 404 sc->sc_refcnt++; 405 error = wsevent_read(sc->sc_base.me_evp, uio, flags); 406 if (--sc->sc_refcnt < 0) { 407 wakeup(sc); 408 error = EIO; 409 } 410 return (error); 411 } 412 413 int 414 wsmouseioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 415 { 416 return (wsmousedoioctl(wsmouse_cd.cd_devs[minor(dev)], 417 cmd, data, flag, p)); 418 } 419 420 /* A wrapper around the ioctl() workhorse to make reference counting easy. */ 421 int 422 wsmousedoioctl(struct device *dv, u_long cmd, caddr_t data, int flag, 423 struct proc *p) 424 { 425 struct wsmouse_softc *sc = (struct wsmouse_softc *)dv; 426 int error; 427 428 sc->sc_refcnt++; 429 error = wsmouse_do_ioctl(sc, cmd, data, flag, p); 430 if (--sc->sc_refcnt < 0) 431 wakeup(sc); 432 return (error); 433 } 434 435 int 436 wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, caddr_t data, int flag, 437 struct proc *p) 438 { 439 int error; 440 441 if (sc->sc_dying) 442 return (EIO); 443 444 /* 445 * Try the generic ioctls that the wsmouse interface supports. 446 */ 447 448 switch (cmd) { 449 case FIOASYNC: 450 case FIOSETOWN: 451 case TIOCSPGRP: 452 if ((flag & FWRITE) == 0) 453 return (EACCES); 454 } 455 456 switch (cmd) { 457 case FIONBIO: /* we will remove this someday (soon???) */ 458 return (0); 459 460 case FIOASYNC: 461 if (sc->sc_base.me_evp == NULL) 462 return (EINVAL); 463 sc->sc_base.me_evp->async = *(int *)data != 0; 464 return (0); 465 466 case FIOSETOWN: 467 if (sc->sc_base.me_evp == NULL) 468 return (EINVAL); 469 if (-*(int *)data != sc->sc_base.me_evp->io->ps_pgid 470 && *(int *)data != sc->sc_base.me_evp->io->ps_pid) 471 return (EPERM); 472 return (0); 473 474 case TIOCSPGRP: 475 if (sc->sc_base.me_evp == NULL) 476 return (EINVAL); 477 if (*(int *)data != sc->sc_base.me_evp->io->ps_pgid) 478 return (EPERM); 479 return (0); 480 } 481 482 /* 483 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1 484 * if it didn't recognize the request. 485 */ 486 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 487 data, flag, p); 488 return (error != -1 ? error : ENOTTY); 489 } 490 491 int 492 wsmousepoll(dev_t dev, int events, struct proc *p) 493 { 494 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)]; 495 496 if (sc->sc_base.me_evp == NULL) 497 return (POLLERR); 498 return (wsevent_poll(sc->sc_base.me_evp, events, p)); 499 } 500 501 int 502 wsmousekqfilter(dev_t dev, struct knote *kn) 503 { 504 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)]; 505 506 if (sc->sc_base.me_evp == NULL) 507 return (ENXIO); 508 return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); 509 } 510 511 #if NWSMUX > 0 512 int 513 wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp) 514 { 515 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 516 517 if (sc->sc_base.me_evp != NULL) 518 return (EBUSY); 519 520 return wsmousedoopen(sc, evp); 521 } 522 523 int 524 wsmouse_mux_close(struct wsevsrc *me) 525 { 526 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 527 528 sc->sc_base.me_evp = NULL; 529 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 530 531 return (0); 532 } 533 534 int 535 wsmouse_add_mux(int unit, struct wsmux_softc *muxsc) 536 { 537 struct wsmouse_softc *sc; 538 539 if (unit < 0 || unit >= wsmouse_cd.cd_ndevs || 540 (sc = wsmouse_cd.cd_devs[unit]) == NULL) 541 return (ENXIO); 542 543 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 544 return (EBUSY); 545 546 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 547 } 548 #endif /* NWSMUX > 0 */ 549 550 void 551 wsmouse_buttons(struct device *sc, u_int buttons) 552 { 553 struct btn_state *btn = 554 &((struct wsmouse_softc *) sc)->input.btn; 555 556 if (btn->sync) 557 /* Restore the old state. */ 558 btn->buttons ^= btn->sync; 559 560 btn->sync = btn->buttons ^ buttons; 561 btn->buttons = buttons; 562 } 563 564 void 565 wsmouse_motion(struct device *sc, int dx, int dy, int dz, int dw) 566 { 567 struct motion_state *motion = 568 &((struct wsmouse_softc *) sc)->input.motion; 569 570 motion->dx = dx; 571 motion->dy = dy; 572 motion->dz = dz; 573 motion->dw = dw; 574 if (dx || dy || dz || dw) 575 motion->sync |= SYNC_DELTAS; 576 } 577 578 /* 579 * Handle absolute coordinates. 580 * 581 * x_delta/y_delta are used by touchpad code. The values are only 582 * valid if the SYNC-flags are set, and will be cleared by update- or 583 * conversion-functions if a touch shouldn't trigger pointer motion. 584 */ 585 void 586 wsmouse_position(struct device *sc, int x, int y) 587 { 588 struct motion_state *motion = 589 &((struct wsmouse_softc *) sc)->input.motion; 590 int delta; 591 592 delta = x - motion->x; 593 if (delta) { 594 motion->x = x; 595 motion->sync |= SYNC_X; 596 motion->x_delta = delta; 597 } 598 delta = y - motion->y; 599 if (delta) { 600 motion->y = y; 601 motion->sync |= SYNC_Y; 602 motion->y_delta = delta; 603 } 604 } 605 606 static __inline int 607 normalized_pressure(struct wsmouseinput *input, int pressure) 608 { 609 int limit = imax(input->touch.min_pressure, 1); 610 611 if (pressure >= limit) 612 return pressure; 613 else 614 return (pressure < 0 ? limit : 0); 615 } 616 617 void 618 wsmouse_touch(struct device *sc, int pressure, int contacts) 619 { 620 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 621 struct touch_state *touch = &input->touch; 622 623 pressure = normalized_pressure(input, pressure); 624 contacts = (pressure ? imax(contacts, 1) : 0); 625 626 if (pressure == 0 || pressure != touch->pressure) { 627 /* 628 * pressure == 0: Drivers may report possibly arbitrary 629 * coordinates in this case; touch_update will correct them. 630 */ 631 touch->pressure = pressure; 632 touch->sync |= SYNC_PRESSURE; 633 } 634 if (contacts != touch->contacts) { 635 touch->contacts = contacts; 636 touch->sync |= SYNC_CONTACTS; 637 } 638 } 639 640 void 641 wsmouse_mtstate(struct device *sc, int slot, int x, int y, int pressure) 642 { 643 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 644 struct mt_state *mt = &input->mt; 645 struct mt_slot *mts; 646 u_int bit; 647 int initial; 648 649 if (slot < 0 || slot >= mt->num_slots) 650 return; 651 652 bit = (1 << slot); 653 mt->frame |= bit; 654 655 /* Is this a new touch? */ 656 initial = ((mt->touches & bit) == (mt->sync[MTS_TOUCH] & bit)); 657 658 mts = &mt->slots[slot]; 659 if (x != mts->x || initial) { 660 mts->x = x; 661 mt->sync[MTS_X] |= bit; 662 } 663 if (y != mts->y || initial) { 664 mts->y = y; 665 mt->sync[MTS_Y] |= bit; 666 } 667 pressure = normalized_pressure(input, pressure); 668 if (pressure != mts->pressure || initial) { 669 mts->pressure = pressure; 670 mt->sync[MTS_PRESSURE] |= bit; 671 672 if (pressure) { 673 if ((mt->touches & bit) == 0) { 674 mt->num_touches++; 675 mt->touches |= bit; 676 mt->sync[MTS_TOUCH] |= bit; 677 } 678 } else if (mt->touches & bit) { 679 mt->num_touches--; 680 mt->touches ^= bit; 681 mt->sync[MTS_TOUCH] |= bit; 682 } 683 } 684 } 685 686 void 687 wsmouse_set(struct device *sc, enum wsmouseval type, int value, int aux) 688 { 689 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 690 struct mt_slot *mts; 691 692 if (WSMOUSE_IS_MT_CODE(type)) { 693 if (aux < 0 || aux >= input->mt.num_slots) 694 return; 695 mts = &input->mt.slots[aux]; 696 } 697 698 switch (type) { 699 case WSMOUSE_REL_X: 700 value += input->motion.x; /* fall through */ 701 case WSMOUSE_ABS_X: 702 wsmouse_position(sc, value, input->motion.y); 703 return; 704 case WSMOUSE_REL_Y: 705 value += input->motion.y; 706 case WSMOUSE_ABS_Y: 707 wsmouse_position(sc, input->motion.x, value); 708 return; 709 case WSMOUSE_PRESSURE: 710 wsmouse_touch(sc, value, input->touch.contacts); 711 return; 712 case WSMOUSE_CONTACTS: 713 /* Contact counts can be overridden by wsmouse_touch. */ 714 if (value != input->touch.contacts) { 715 input->touch.contacts = value; 716 input->touch.sync |= SYNC_CONTACTS; 717 } 718 return; 719 case WSMOUSE_TOUCH_WIDTH: 720 if (value != input->touch.width) { 721 input->touch.width = value; 722 input->touch.sync |= SYNC_TOUCH_WIDTH; 723 } 724 return; 725 case WSMOUSE_MT_REL_X: 726 value += mts->x; /* fall through */ 727 case WSMOUSE_MT_ABS_X: 728 wsmouse_mtstate(sc, aux, value, mts->y, mts->pressure); 729 return; 730 case WSMOUSE_MT_REL_Y: 731 value += mts->y; 732 case WSMOUSE_MT_ABS_Y: 733 wsmouse_mtstate(sc, aux, mts->x, value, mts->pressure); 734 return; 735 case WSMOUSE_MT_PRESSURE: 736 wsmouse_mtstate(sc, aux, mts->x, mts->y, value); 737 return; 738 } 739 } 740 741 /* Make touch and motion state consistent. */ 742 void 743 wsmouse_touch_update(struct wsmouseinput *input) 744 { 745 struct motion_state *motion = &input->motion; 746 struct touch_state *touch = &input->touch; 747 748 if (touch->pressure == 0) { 749 /* Restore valid coordinates. */ 750 if (motion->sync & SYNC_X) 751 motion->x -= motion->x_delta; 752 if (motion->sync & SYNC_Y) 753 motion->y -= motion->y_delta; 754 /* Don't generate motion/position events. */ 755 motion->sync &= ~SYNC_POSITION; 756 } 757 if (touch->sync & SYNC_CONTACTS) 758 /* Suppress pointer motion. */ 759 motion->x_delta = motion->y_delta = 0; 760 761 if ((touch->sync & SYNC_PRESSURE) && touch->min_pressure) { 762 if (touch->pressure >= input->params.pressure_hi) 763 touch->min_pressure = input->params.pressure_lo; 764 else if (touch->pressure < input->params.pressure_lo) 765 touch->min_pressure = input->params.pressure_hi; 766 } 767 } 768 769 /* Normalize multitouch state. */ 770 void 771 wsmouse_mt_update(struct wsmouseinput *input) 772 { 773 int i; 774 775 /* 776 * The same as above: There may be arbitrary coordinates if 777 * (pressure == 0). Clear the sync flags for touches that have 778 * been released. 779 */ 780 if (input->mt.sync[MTS_TOUCH] & ~input->mt.touches) { 781 for (i = MTS_X; i < MTS_SIZE; i++) 782 input->mt.sync[i] &= input->mt.touches; 783 } 784 } 785 786 /* 787 * Select the pointer-controlling MT slot. 788 * 789 * Pointer-control is assigned to slots with non-zero motion deltas if 790 * at least one such slot exists. This function doesn't impose any 791 * restrictions on the way drivers use wsmouse_mtstate(), it covers 792 * partial, unordered, and "delta-filtered" input. 793 * 794 * The "cycle" is the set of slots with X/Y updates in previous sync 795 * operations; it will be cleared and rebuilt whenever a slot that is 796 * being updated is already a member. If a cycle ends that doesn't 797 * contain the pointer-controlling slot, a new slot will be selected. 798 */ 799 void 800 wsmouse_ptr_ctrl(struct mt_state *mt) 801 { 802 u_int updates; 803 int select, slot; 804 805 mt->prev_ptr = mt->ptr; 806 807 if (mt->num_touches <= 1) { 808 mt->ptr = mt->touches; 809 mt->ptr_cycle = mt->ptr; 810 return; 811 } 812 813 /* 814 * If there is no pointer-controlling slot or it is inactive, 815 * select a new one. 816 */ 817 select = ((mt->ptr & mt->touches) == 0); 818 819 /* Remove slots without X/Y deltas from the cycle. */ 820 updates = (mt->sync[MTS_X] | mt->sync[MTS_Y]) & ~mt->sync[MTS_TOUCH]; 821 mt->ptr_cycle &= ~(mt->frame ^ updates); 822 823 if (mt->ptr_cycle & updates) { 824 select |= ((mt->ptr_cycle & mt->ptr) == 0); 825 mt->ptr_cycle = updates; 826 } else { 827 mt->ptr_cycle |= updates; 828 } 829 if (select) { 830 slot = (mt->ptr_cycle 831 ? ffs(mt->ptr_cycle) - 1 : ffs(mt->touches) - 1); 832 mt->ptr = (1 << slot); 833 } 834 } 835 836 /* Derive touch and motion state from MT state. */ 837 void 838 wsmouse_mt_convert(struct device *sc) 839 { 840 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 841 struct mt_state *mt = &input->mt; 842 struct mt_slot *mts; 843 int slot, pressure; 844 845 wsmouse_ptr_ctrl(mt); 846 847 if (mt->ptr) { 848 slot = ffs(mt->ptr) - 1; 849 mts = &mt->slots[slot]; 850 wsmouse_position(sc, mts->x, mts->y); 851 if (mt->ptr != mt->prev_ptr) 852 /* Suppress pointer motion. */ 853 input->motion.x_delta = input->motion.y_delta = 0; 854 pressure = mts->pressure; 855 } else { 856 pressure = 0; 857 } 858 859 wsmouse_touch(sc, pressure, mt->num_touches); 860 } 861 862 void 863 wsmouse_evq_put(struct evq_access *evq, int ev_type, int ev_value) 864 { 865 struct wscons_event *ev; 866 int space; 867 868 space = evq->evar->get - evq->put; 869 if (space != 1 && space != 1 - WSEVENT_QSIZE) { 870 ev = &evq->evar->q[evq->put++]; 871 evq->put %= WSEVENT_QSIZE; 872 ev->type = ev_type; 873 ev->value = ev_value; 874 memcpy(&ev->time, &evq->ts, sizeof(struct timespec)); 875 evq->result |= EVQ_RESULT_SUCCESS; 876 } else { 877 evq->result = EVQ_RESULT_OVERFLOW; 878 } 879 } 880 881 882 void 883 wsmouse_btn_sync(struct wsmouseinput *input, struct evq_access *evq) 884 { 885 struct btn_state *btn = &input->btn; 886 int button, ev_type; 887 u_int bit, sync; 888 889 for (sync = btn->sync; sync; sync ^= bit) { 890 button = ffs(sync) - 1; 891 bit = (1 << button); 892 ev_type = (btn->buttons & bit) ? BTN_DOWN_EV : BTN_UP_EV; 893 wsmouse_evq_put(evq, ev_type, button); 894 } 895 } 896 897 /* 898 * Scale with a [*.12] fixed-point factor and a remainder: 899 */ 900 static __inline int 901 scale(int val, int factor, int *rmdr) 902 { 903 val = val * factor + *rmdr; 904 if (val >= 0) { 905 *rmdr = val & 0xfff; 906 return (val >> 12); 907 } else { 908 *rmdr = -(-val & 0xfff); 909 return -(-val >> 12); 910 } 911 } 912 913 void 914 wsmouse_motion_sync(struct wsmouseinput *input, struct evq_access *evq) 915 { 916 struct motion_state *motion = &input->motion; 917 struct wsmouseparams *params = &input->params; 918 struct axis_filter *fltr; 919 int x, y, dx, dy; 920 921 if (motion->sync & SYNC_DELTAS) { 922 dx = params->x_inv ? -motion->dx : motion->dx; 923 dy = params->y_inv ? -motion->dy : motion->dy; 924 if (input->flags & SCALE_DELTAS) { 925 fltr = &input->fltr.h; 926 dx = scale(dx, fltr->scale, &fltr->rmdr); 927 fltr = &input->fltr.v; 928 dy = scale(dy, fltr->scale, &fltr->rmdr); 929 } 930 if (dx) 931 wsmouse_evq_put(evq, DELTA_X_EV(input->flags), dx); 932 if (dy) 933 wsmouse_evq_put(evq, DELTA_Y_EV(input->flags), dy); 934 if (motion->dz) 935 wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz); 936 if (motion->dw) 937 wsmouse_evq_put(evq, DELTA_W_EV, motion->dw); 938 } 939 if (motion->sync & SYNC_POSITION) { 940 if (motion->sync & SYNC_X) { 941 x = (params->x_inv 942 ? params->x_inv - motion->x : motion->x); 943 wsmouse_evq_put(evq, ABS_X_EV(input->flags), x); 944 } 945 if (motion->sync & SYNC_Y) { 946 y = (params->y_inv 947 ? params->y_inv - motion->y : motion->y); 948 wsmouse_evq_put(evq, ABS_Y_EV(input->flags), y); 949 } 950 if (motion->x_delta == 0 && motion->y_delta == 0 951 && (input->flags & TPAD_NATIVE_MODE)) 952 /* Suppress pointer motion. */ 953 wsmouse_evq_put(evq, WSCONS_EVENT_TOUCH_RESET, 0); 954 } 955 } 956 957 void 958 wsmouse_touch_sync(struct wsmouseinput *input, struct evq_access *evq) 959 { 960 struct touch_state *touch = &input->touch; 961 962 if (touch->sync & SYNC_PRESSURE) 963 wsmouse_evq_put(evq, ABS_Z_EV, touch->pressure); 964 if (touch->sync & SYNC_CONTACTS) 965 wsmouse_evq_put(evq, ABS_W_EV, touch->contacts); 966 if ((touch->sync & SYNC_TOUCH_WIDTH) 967 && (input->flags & TPAD_NATIVE_MODE)) 968 wsmouse_evq_put(evq, WSCONS_EVENT_TOUCH_WIDTH, touch->width); 969 } 970 971 /* 972 * Convert absolute touchpad input (compatibility mode). 973 */ 974 void 975 wsmouse_compat_convert(struct device *sc, struct evq_access *evq) 976 { 977 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 978 struct wsmouseparams *params = &input->params; 979 int dx, dy, dz, dw; 980 981 dx = (input->motion.sync & SYNC_X) ? input->motion.x_delta : 0; 982 dy = (input->motion.sync & SYNC_Y) ? input->motion.y_delta : 0; 983 dz = (input->motion.sync & SYNC_DELTAS) ? input->motion.dz : 0; 984 dw = (input->motion.sync & SYNC_DELTAS) ? input->motion.dw : 0; 985 986 if ((params->dx_max && abs(dx) > params->dx_max) 987 || (params->dy_max && abs(dy) > params->dy_max)) { 988 989 dx = dy = 0; 990 } 991 992 wsmouse_motion(sc, dx, dy, dz, dw); 993 994 input->motion.sync &= ~SYNC_POSITION; 995 input->touch.sync = 0; 996 } 997 998 static __inline void 999 clear_sync_flags(struct wsmouseinput *input) 1000 { 1001 int i; 1002 1003 input->btn.sync = 0; 1004 input->motion.sync = 0; 1005 input->touch.sync = 0; 1006 if (input->mt.frame) { 1007 input->mt.frame = 0; 1008 for (i = 0; i < MTS_SIZE; i++) 1009 input->mt.sync[i] = 0; 1010 } 1011 } 1012 1013 void 1014 wsmouse_input_sync(struct device *sc) 1015 { 1016 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 1017 struct evq_access evq; 1018 1019 evq.evar = *input->evar; 1020 if (evq.evar == NULL) 1021 return; 1022 evq.put = evq.evar->put; 1023 evq.result = EVQ_RESULT_NONE; 1024 getnanotime(&evq.ts); 1025 1026 add_mouse_randomness(input->btn.buttons 1027 ^ input->motion.dx ^ input->motion.dy 1028 ^ input->motion.x ^ input->motion.y 1029 ^ input->motion.dz ^ input->motion.dw); 1030 1031 if (input->mt.frame) { 1032 wsmouse_mt_update(input); 1033 wsmouse_mt_convert(sc); 1034 } 1035 if (input->touch.sync) 1036 wsmouse_touch_update(input); 1037 1038 if (input->flags & TPAD_COMPAT_MODE) 1039 wsmouse_compat_convert(sc, &evq); 1040 1041 if (input->flags & RESYNC) { 1042 input->flags &= ~RESYNC; 1043 input->motion.sync &= SYNC_POSITION; 1044 input->motion.x_delta = input->motion.y_delta = 0; 1045 } 1046 1047 if (input->btn.sync) 1048 wsmouse_btn_sync(input, &evq); 1049 if (input->motion.sync) 1050 wsmouse_motion_sync(input, &evq); 1051 if (input->touch.sync) 1052 wsmouse_touch_sync(input, &evq); 1053 /* No MT events are generated yet. */ 1054 1055 if (evq.result == EVQ_RESULT_SUCCESS) { 1056 wsmouse_evq_put(&evq, WSCONS_EVENT_SYNC, 0); 1057 if (evq.result == EVQ_RESULT_SUCCESS) { 1058 evq.evar->put = evq.put; 1059 WSEVENT_WAKEUP(evq.evar); 1060 } 1061 } 1062 1063 if (evq.result != EVQ_RESULT_OVERFLOW) 1064 clear_sync_flags(input); 1065 else 1066 input->flags |= RESYNC; 1067 } 1068 1069 int 1070 wsmouse_id_to_slot(struct device *sc, int id) 1071 { 1072 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 1073 struct mt_state *mt = &input->mt; 1074 int slot; 1075 1076 if (mt->num_slots == 0) 1077 return (-1); 1078 1079 FOREACHBIT(mt->touches, slot) { 1080 if (mt->slots[slot].id == id) 1081 return slot; 1082 } 1083 slot = ffs(~(mt->touches | mt->frame)) - 1; 1084 if (slot >= 0 && slot < mt->num_slots) { 1085 mt->frame |= 1 << slot; 1086 mt->slots[slot].id = id; 1087 return (slot); 1088 } else { 1089 return (-1); 1090 } 1091 } 1092 1093 /* 1094 * Find a minimum-weight matching for an m-by-n matrix. 1095 * 1096 * m must be greater than or equal to n. The size of the buffer must be 1097 * at least 4m + 3n. 1098 * 1099 * On return, the first m elements of the buffer contain the row-to- 1100 * column mappings, i.e., buffer[i] is the column index for row i, or -1 1101 * if there is no assignment for that row (which may happen if n < m). 1102 * 1103 * Wrong results because of overflows will not occur with input values 1104 * in the range of 0 to INT_MAX / 2 inclusive. 1105 * 1106 * The function applies the Dinic-Kronrod algorithm. It is not modern or 1107 * popular, but it seems to be a good choice for small matrices at least. 1108 * The original form of the algorithm is modified as follows: There is no 1109 * initial search for row minima, the initial assignments are in a 1110 * "virtual" column with the index -1 and zero values. This permits inputs 1111 * with n < m, and it simplifies the reassignments. 1112 */ 1113 void 1114 wsmouse_matching(int *matrix, int m, int n, int *buffer) 1115 { 1116 int i, j, k, d, e, row, col, delta; 1117 int *p; 1118 int *r2c = buffer; /* row-to-column assignments */ 1119 int *red = r2c + m; /* reduced values of the assignments */ 1120 int *alt = red + m; /* alternative assignments */ 1121 int *mc = alt + m; /* row-wise minimal elements of cs */ 1122 int *cs = mc + m; /* the column set */ 1123 int *c2r = cs + n; /* column-to-row assignments in cs */ 1124 int *cd = c2r + n; /* column deltas (reduction) */ 1125 1126 for (p = r2c; p < red; *p++ = -1) {} 1127 for (; p < alt; *p++ = 0) {} 1128 for (col = 0; col < n; col++) { 1129 delta = INT_MAX; 1130 for (i = 0, p = matrix + col; i < m; i++, p += n) { 1131 d = *p - red[i]; 1132 if (d < delta || (d == delta && r2c[i] < 0)) { 1133 delta = d; 1134 row = i; 1135 } 1136 } 1137 cd[col] = delta; 1138 if (r2c[row] < 0) { 1139 r2c[row] = col; 1140 continue; 1141 } 1142 for (p = alt; p < mc; *p++ = -1) {} 1143 for (; p < cs; *p++ = col) {} 1144 for (k = 0; (j = r2c[row]) >= 0;) { 1145 cs[k++] = j; 1146 c2r[j] = row; 1147 alt[row] = mc[row]; 1148 delta = INT_MAX; 1149 for (i = 0, p = matrix; i < m; i++, p += n) 1150 if (alt[i] < 0) { 1151 d = p[mc[i]] - cd[mc[i]]; 1152 e = p[j] - cd[j]; 1153 if (e < d) { 1154 d = e; 1155 mc[i] = j; 1156 } 1157 d -= red[i]; 1158 if (d < delta || (d == delta 1159 && r2c[i] < 0)) { 1160 delta = d; 1161 row = i; 1162 } 1163 } 1164 cd[col] += delta; 1165 for (i = 0; i < k; i++) { 1166 cd[cs[i]] += delta; 1167 red[c2r[cs[i]]] -= delta; 1168 } 1169 } 1170 for (j = mc[row]; (r2c[row] = j) != col;) { 1171 row = c2r[j]; 1172 j = alt[row]; 1173 } 1174 } 1175 } 1176 1177 void 1178 wsmouse_mtframe(struct device *sc, struct mtpoint *pt, int size) 1179 { 1180 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->input; 1181 struct mt_state *mt = &input->mt; 1182 int i, j, m, n, dx, dy, slot, maxdist; 1183 int *p, *r2c, *c2r; 1184 u_int touches; 1185 1186 if (mt->num_slots == 0 || mt->matrix == NULL) 1187 return; 1188 1189 size = imax(0, imin(size, mt->num_slots)); 1190 p = mt->matrix; 1191 touches = mt->touches; 1192 if (mt->num_touches >= size) { 1193 FOREACHBIT(touches, slot) 1194 for (i = 0; i < size; i++) { 1195 dx = pt[i].x - mt->slots[slot].x; 1196 dy = pt[i].y - mt->slots[slot].y; 1197 *p++ = dx * dx + dy * dy; 1198 } 1199 m = mt->num_touches; 1200 n = size; 1201 } else { 1202 for (i = 0; i < size; i++) 1203 FOREACHBIT(touches, slot) { 1204 dx = pt[i].x - mt->slots[slot].x; 1205 dy = pt[i].y - mt->slots[slot].y; 1206 *p++ = dx * dx + dy * dy; 1207 } 1208 m = size; 1209 n = mt->num_touches; 1210 } 1211 wsmouse_matching(mt->matrix, m, n, p); 1212 1213 r2c = p; 1214 c2r = p + m; 1215 maxdist = input->params.tracking_maxdist; 1216 maxdist = (maxdist ? maxdist * maxdist : INT_MAX); 1217 for (i = 0, p = mt->matrix; i < m; i++, p += n) 1218 if ((j = r2c[i]) >= 0) { 1219 if (p[j] <= maxdist) 1220 c2r[j] = i; 1221 else 1222 c2r[j] = r2c[i] = -1; 1223 } 1224 1225 p = (n == size ? c2r : r2c); 1226 for (i = 0; i < size; i++) 1227 if (*p++ < 0) { 1228 slot = ffs(~(mt->touches | mt->frame)) - 1; 1229 if (slot < 0 || slot >= mt->num_slots) 1230 break; 1231 wsmouse_mtstate(sc, slot, 1232 pt[i].x, pt[i].y, pt[i].pressure); 1233 pt[i].slot = slot; 1234 } 1235 1236 p = (n == size ? r2c : c2r); 1237 FOREACHBIT(touches, slot) 1238 if ((i = *p++) >= 0) { 1239 wsmouse_mtstate(sc, slot, 1240 pt[i].x, pt[i].y, pt[i].pressure); 1241 pt[i].slot = slot; 1242 } else { 1243 wsmouse_mtstate(sc, slot, 0, 0, 0); 1244 } 1245 } 1246 1247 static __inline void 1248 free_mt_slots(struct wsmouseinput *input) 1249 { 1250 int n, size; 1251 1252 if ((n = input->mt.num_slots)) { 1253 size = n * sizeof(struct mt_slot); 1254 if (input->flags & MT_TRACKING) 1255 size += MATRIX_SIZE(n); 1256 input->mt.num_slots = 0; 1257 free(input->mt.slots, M_DEVBUF, size); 1258 input->mt.slots = NULL; 1259 input->mt.matrix = NULL; 1260 } 1261 } 1262 1263 /* Allocate the MT slots and, if necessary, the buffers for MT tracking. */ 1264 int 1265 wsmouse_mt_init(struct device *sc, int num_slots, int tracking) 1266 { 1267 struct wsmouseinput *input = 1268 &((struct wsmouse_softc *) sc)->input; 1269 int n, size; 1270 1271 if (num_slots == input->mt.num_slots 1272 && (!tracking == ((input->flags & MT_TRACKING) == 0))) 1273 return (0); 1274 1275 free_mt_slots(input); 1276 1277 if (tracking) 1278 input->flags |= MT_TRACKING; 1279 else 1280 input->flags &= ~MT_TRACKING; 1281 n = imin(imax(num_slots, 0), WSMOUSE_MT_SLOTS_MAX); 1282 if (n) { 1283 size = n * sizeof(struct mt_slot); 1284 if (input->flags & MT_TRACKING) 1285 size += MATRIX_SIZE(n); 1286 input->mt.slots = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); 1287 if (input->mt.slots != NULL) { 1288 if (input->flags & MT_TRACKING) 1289 input->mt.matrix = (int *) 1290 (input->mt.slots + n); 1291 input->mt.num_slots = n; 1292 return (0); 1293 } 1294 } 1295 return (-1); 1296 } 1297 1298 void 1299 wsmouse_init_scaling(struct wsmouseinput *input) 1300 { 1301 struct wsmouseparams *params = &input->params; 1302 int m, n; 1303 1304 if (params->dx_mul || params->dx_div 1305 || params->dy_mul || params->dy_div) { 1306 /* Scale factors have a [*.12] fixed point format. */ 1307 m = (params->dx_mul ? abs(params->dx_mul) : 1); 1308 n = (params->dx_div ? abs(params->dx_div) : 1); 1309 input->fltr.h.scale = (m << 12) / n; 1310 input->fltr.h.rmdr = 0; 1311 m = (params->dy_mul ? abs(params->dy_mul) : 1); 1312 n = (params->dy_div ? abs(params->dy_div): 1); 1313 input->fltr.v.scale = (m << 12) / n; 1314 input->fltr.v.rmdr = 0; 1315 input->flags |= SCALE_DELTAS; 1316 } else { 1317 input->flags &= ~SCALE_DELTAS; 1318 } 1319 } 1320 1321 void 1322 wsmouse_set_param(struct device *sc, size_t param, int value) 1323 { 1324 struct wsmouseinput *input = 1325 &((struct wsmouse_softc *) sc)->input; 1326 struct wsmouseparams *params = &input->params; 1327 int *p; 1328 1329 if (param > WSMPARAM_LASTFIELD) { 1330 printf("wsmouse_set_param: invalid parameter type\n"); 1331 return; 1332 } 1333 1334 p = (int *) (((void *) params) + param); 1335 *p = value; 1336 1337 if (IS_WSMFLTR_PARAM(param)) { 1338 wsmouse_init_scaling(input); 1339 } else if (param == WSMPARAM_SWAPXY) { 1340 if (value) 1341 input->flags |= SWAPXY; 1342 else 1343 input->flags &= ~SWAPXY; 1344 } else if (param == WSMPARAM_PRESSURE_LO) { 1345 params->pressure_hi = 1346 imax(params->pressure_lo, params->pressure_hi); 1347 input->touch.min_pressure = params->pressure_hi; 1348 } else if (param == WSMPARAM_PRESSURE_HI 1349 && params->pressure_lo == 0) { 1350 params->pressure_lo = params->pressure_hi; 1351 input->touch.min_pressure = params->pressure_hi; 1352 } 1353 } 1354 1355 int 1356 wsmouse_set_mode(struct device *sc, int mode) 1357 { 1358 struct wsmouseinput *input = 1359 &((struct wsmouse_softc *) sc)->input; 1360 1361 if (mode == WSMOUSE_COMPAT) { 1362 input->flags &= ~TPAD_NATIVE_MODE; 1363 input->flags |= TPAD_COMPAT_MODE; 1364 return (0); 1365 } else if (mode == WSMOUSE_NATIVE) { 1366 input->flags &= ~TPAD_COMPAT_MODE; 1367 input->flags |= TPAD_NATIVE_MODE; 1368 return (0); 1369 } 1370 return (-1); 1371 } 1372 1373 void 1374 wsmouse_input_reset(struct wsmouseinput *input) 1375 { 1376 int num_slots, *matrix; 1377 struct mt_slot *slots; 1378 1379 memset(&input->btn, 0, sizeof(struct btn_state)); 1380 memset(&input->motion, 0, sizeof(struct motion_state)); 1381 memset(&input->touch, 0, sizeof(struct touch_state)); 1382 input->touch.min_pressure = input->params.pressure_hi; 1383 if ((num_slots = input->mt.num_slots)) { 1384 slots = input->mt.slots; 1385 matrix = input->mt.matrix; 1386 memset(&input->mt, 0, sizeof(struct mt_state)); 1387 memset(slots, 0, num_slots * sizeof(struct mt_slot)); 1388 input->mt.num_slots = num_slots; 1389 input->mt.slots = slots; 1390 input->mt.matrix = matrix; 1391 } 1392 } 1393 1394 void 1395 wsmouse_input_init(struct wsmouseinput *input, struct wseventvar **evar) 1396 { 1397 input->evar = evar; 1398 } 1399 1400 void 1401 wsmouse_input_cleanup(struct wsmouseinput *input) 1402 { 1403 free_mt_slots(input); 1404 } 1405