LCOV - code coverage report
Current view: top level - dev/wscons - wsmouse.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 888 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 54 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $OpenBSD: wsmouse.c,v 1.45 2018/05/07 21:58:42 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/wseventvar.h>
     113             : #include <dev/wscons/wsmouseinput.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 sc_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           0 : wsmousedevprint(void *aux, const char *pnp)
     181             : {
     182             : 
     183           0 :         if (pnp)
     184           0 :                 printf("wsmouse at %s", pnp);
     185           0 :         return (UNCONF);
     186             : }
     187             : 
     188             : int
     189           0 : wsmouse_match(struct device *parent, void *match, void *aux)
     190             : {
     191           0 :         return (1);
     192             : }
     193             : 
     194             : void
     195           0 : wsmouse_attach(struct device *parent, struct device *self, void *aux)
     196             : {
     197           0 :         struct wsmouse_softc *sc = (struct wsmouse_softc *)self;
     198           0 :         struct wsmousedev_attach_args *ap = aux;
     199             : #if NWSMUX > 0
     200             :         int mux, error;
     201             : #endif
     202             : 
     203           0 :         sc->sc_accessops = ap->accessops;
     204           0 :         sc->sc_accesscookie = ap->accesscookie;
     205             : 
     206           0 :         sc->sc_input.evar = &sc->sc_base.me_evp;
     207             : 
     208             : #if NWSMUX > 0
     209           0 :         sc->sc_base.me_ops = &wsmouse_srcops;
     210           0 :         mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux;
     211           0 :         if (mux >= 0) {
     212           0 :                 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
     213           0 :                 if (error)
     214           0 :                         printf(" attach error=%d", error);
     215             :                 else
     216           0 :                         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           0 :         printf("\n");
     226           0 : }
     227             : 
     228             : int
     229           0 : wsmouse_activate(struct device *self, int act)
     230             : {
     231           0 :         struct wsmouse_softc *sc = (struct wsmouse_softc *)self;
     232             : 
     233           0 :         if (act == DVACT_DEACTIVATE)
     234           0 :                 sc->sc_dying = 1;
     235           0 :         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           0 : wsmouse_detach(struct device *self, int flags)
     248             : {
     249           0 :         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           0 :         if (sc->sc_base.me_parent != NULL) {
     257             :                 DPRINTF(("wsmouse_detach:\n"));
     258           0 :                 wsmux_detach_sc(&sc->sc_base);
     259           0 :         }
     260             : #endif
     261             : 
     262             :         /* If we're open ... */
     263           0 :         evar = sc->sc_base.me_evp;
     264           0 :         if (evar != NULL && evar->io != NULL) {
     265           0 :                 s = spltty();
     266           0 :                 if (--sc->sc_refcnt >= 0) {
     267             :                         /* Wake everyone by generating a dummy event. */
     268           0 :                         if (++evar->put >= WSEVENT_QSIZE)
     269           0 :                                 evar->put = 0;
     270           0 :                         WSEVENT_WAKEUP(evar);
     271             :                         /* Wait for processes to go away. */
     272           0 :                         if (tsleep(sc, PZERO, "wsmdet", hz * 60))
     273           0 :                                 printf("wsmouse_detach: %s didn't detach\n",
     274           0 :                                        sc->sc_base.me_dv.dv_xname);
     275             :                 }
     276           0 :                 splx(s);
     277           0 :         }
     278             : 
     279             :         /* locate the major number */
     280           0 :         for (maj = 0; maj < nchrdev; maj++)
     281           0 :                 if (cdevsw[maj].d_open == wsmouseopen)
     282             :                         break;
     283             : 
     284             :         /* Nuke the vnodes for any open instances (calls close). */
     285           0 :         mn = self->dv_unit;
     286           0 :         vdevgone(maj, mn, mn, VCHR);
     287             : 
     288           0 :         wsmouse_input_cleanup(&sc->sc_input);
     289             : 
     290           0 :         return (0);
     291             : }
     292             : 
     293             : int
     294           0 : 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           0 :         unit = minor(dev);
     301           0 :         if (unit >= wsmouse_cd.cd_ndevs ||   /* make sure it was attached */
     302           0 :             (sc = wsmouse_cd.cd_devs[unit]) == NULL)
     303           0 :                 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           0 :         if (sc->sc_dying)
     311           0 :                 return (EIO);
     312             : 
     313           0 :         if ((flags & (FREAD | FWRITE)) == FWRITE)
     314           0 :                 return (0);                     /* always allow open for write
     315             :                                                    so ioctl() is possible. */
     316             : 
     317             : #if NWSMUX > 0
     318           0 :         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           0 :                 wsmux_detach_sc(&sc->sc_base);
     322           0 :         }
     323             : #endif
     324             : 
     325           0 :         if (sc->sc_base.me_evp != NULL)
     326           0 :                 return (EBUSY);
     327             : 
     328           0 :         evar = &sc->sc_base.me_evar;
     329           0 :         wsevent_init(evar);
     330           0 :         evar->io = p->p_p;
     331             : 
     332           0 :         error = wsmousedoopen(sc, evar);
     333           0 :         if (error) {
     334             :                 DPRINTF(("wsmouseopen: %s open failed\n",
     335             :                          sc->sc_base.me_dv.dv_xname));
     336           0 :                 sc->sc_base.me_evp = NULL;
     337           0 :                 wsevent_fini(evar);
     338           0 :         }
     339           0 :         return (error);
     340           0 : }
     341             : 
     342             : int
     343           0 : wsmouseclose(dev_t dev, int flags, int mode, struct proc *p)
     344             : {
     345             :         struct wsmouse_softc *sc =
     346           0 :             (struct wsmouse_softc *)wsmouse_cd.cd_devs[minor(dev)];
     347           0 :         struct wseventvar *evar = sc->sc_base.me_evp;
     348             : 
     349           0 :         if ((flags & (FREAD | FWRITE)) == FWRITE)
     350           0 :                 return (0);                     /* see wsmouseopen() */
     351             : 
     352           0 :         if (evar == NULL)
     353             :                 /* not open for read */
     354           0 :                 return (0);
     355           0 :         sc->sc_base.me_evp = NULL;
     356           0 :         (*sc->sc_accessops->disable)(sc->sc_accesscookie);
     357           0 :         wsevent_fini(evar);
     358             : 
     359             : #if NWSMUX > 0
     360           0 :         if (sc->sc_base.me_parent == NULL) {
     361             :                 int mux, error;
     362             : 
     363             :                 DPRINTF(("wsmouseclose: attach\n"));
     364           0 :                 mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux;
     365           0 :                 if (mux >= 0) {
     366           0 :                         error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
     367           0 :                         if (error)
     368           0 :                                 printf("%s: can't attach mux (error=%d)\n",
     369           0 :                                     sc->sc_base.me_dv.dv_xname, error);
     370             :                 }
     371           0 :         }
     372             : #endif
     373             : 
     374           0 :         return (0);
     375           0 : }
     376             : 
     377             : int
     378           0 : wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp)
     379             : {
     380           0 :         sc->sc_base.me_evp = evp;
     381             : 
     382           0 :         wsmouse_input_reset(&sc->sc_input);
     383             : 
     384             :         /* enable the device, and punt if that's not possible */
     385           0 :         return (*sc->sc_accessops->enable)(sc->sc_accesscookie);
     386             : }
     387             : 
     388             : int
     389           0 : wsmouseread(dev_t dev, struct uio *uio, int flags)
     390             : {
     391           0 :         struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)];
     392             :         int error;
     393             : 
     394           0 :         if (sc->sc_dying)
     395           0 :                 return (EIO);
     396             : 
     397             : #ifdef DIAGNOSTIC
     398           0 :         if (sc->sc_base.me_evp == NULL) {
     399           0 :                 printf("wsmouseread: evp == NULL\n");
     400           0 :                 return (EINVAL);
     401             :         }
     402             : #endif
     403             : 
     404           0 :         sc->sc_refcnt++;
     405           0 :         error = wsevent_read(sc->sc_base.me_evp, uio, flags);
     406           0 :         if (--sc->sc_refcnt < 0) {
     407           0 :                 wakeup(sc);
     408             :                 error = EIO;
     409           0 :         }
     410           0 :         return (error);
     411           0 : }
     412             : 
     413             : int
     414           0 : wsmouseioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
     415             : {
     416           0 :         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           0 : wsmousedoioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
     423             :     struct proc *p)
     424             : {
     425           0 :         struct wsmouse_softc *sc = (struct wsmouse_softc *)dv;
     426             :         int error;
     427             : 
     428           0 :         sc->sc_refcnt++;
     429           0 :         error = wsmouse_do_ioctl(sc, cmd, data, flag, p);
     430           0 :         if (--sc->sc_refcnt < 0)
     431           0 :                 wakeup(sc);
     432           0 :         return (error);
     433             : }
     434             : 
     435             : int
     436           0 : wsmouse_param_ioctl(struct wsmouse_softc *sc,
     437             :     u_long cmd, struct wsmouse_param *params, u_int nparams)
     438             : {
     439             :         struct wsmouse_param *buf;
     440             :         int error, s, size;
     441             : 
     442           0 :         if (params == NULL || nparams > WSMOUSECFG_MAX)
     443           0 :                 return (EINVAL);
     444             : 
     445           0 :         size = nparams * sizeof(struct wsmouse_param);
     446           0 :         buf = malloc(size, M_DEVBUF, M_WAITOK);
     447           0 :         if (buf == NULL)
     448           0 :                 return (ENOMEM);
     449             : 
     450           0 :         if ((error = copyin(params, buf, size))) {
     451           0 :                 free(buf, M_DEVBUF, size);
     452           0 :                 return (error);
     453             :         }
     454             : 
     455           0 :         s = spltty();
     456           0 :         if (cmd == WSMOUSEIO_SETPARAMS) {
     457           0 :                 if (wsmouse_set_params((struct device *) sc, buf, nparams))
     458           0 :                         error = EINVAL;
     459             :         } else {
     460           0 :                 if (wsmouse_get_params((struct device *) sc, buf, nparams))
     461           0 :                         error = EINVAL;
     462             :                 else
     463           0 :                         error = copyout(buf, params, size);
     464             :         }
     465           0 :         splx(s);
     466           0 :         free(buf, M_DEVBUF, size);
     467           0 :         return (error);
     468           0 : }
     469             : 
     470             : int
     471           0 : wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, caddr_t data, int flag,
     472             :     struct proc *p)
     473             : {
     474             :         int error;
     475             : 
     476           0 :         if (sc->sc_dying)
     477           0 :                 return (EIO);
     478             : 
     479             :         /*
     480             :          * Try the generic ioctls that the wsmouse interface supports.
     481             :          */
     482             : 
     483           0 :         switch (cmd) {
     484             :         case FIOASYNC:
     485             :         case FIOSETOWN:
     486             :         case TIOCSPGRP:
     487           0 :                 if ((flag & FWRITE) == 0)
     488           0 :                         return (EACCES);
     489             :         }
     490             : 
     491           0 :         switch (cmd) {
     492             :         case FIONBIO:           /* we will remove this someday (soon???) */
     493           0 :                 return (0);
     494             : 
     495             :         case FIOASYNC:
     496           0 :                 if (sc->sc_base.me_evp == NULL)
     497           0 :                         return (EINVAL);
     498           0 :                 sc->sc_base.me_evp->async = *(int *)data != 0;
     499           0 :                 return (0);
     500             : 
     501             :         case FIOSETOWN:
     502           0 :                 if (sc->sc_base.me_evp == NULL)
     503           0 :                         return (EINVAL);
     504           0 :                 if (-*(int *)data != sc->sc_base.me_evp->io->ps_pgid
     505           0 :                     && *(int *)data != sc->sc_base.me_evp->io->ps_pid)
     506           0 :                         return (EPERM);
     507           0 :                 return (0);
     508             : 
     509             :         case TIOCSPGRP:
     510           0 :                 if (sc->sc_base.me_evp == NULL)
     511           0 :                         return (EINVAL);
     512           0 :                 if (*(int *)data != sc->sc_base.me_evp->io->ps_pgid)
     513           0 :                         return (EPERM);
     514           0 :                 return (0);
     515             :         case WSMOUSEIO_GETPARAMS:
     516             :         case WSMOUSEIO_SETPARAMS:
     517           0 :                 return (wsmouse_param_ioctl(sc, cmd,
     518           0 :                     ((struct wsmouse_parameters *) data)->params,
     519           0 :                     ((struct wsmouse_parameters *) data)->nparams));
     520             :         }
     521             : 
     522             :         /*
     523             :          * Try the mouse driver for WSMOUSEIO ioctls.  It returns -1
     524             :          * if it didn't recognize the request.
     525             :          */
     526           0 :         error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
     527             :             data, flag, p);
     528           0 :         return (error != -1 ? error : ENOTTY);
     529           0 : }
     530             : 
     531             : int
     532           0 : wsmousepoll(dev_t dev, int events, struct proc *p)
     533             : {
     534           0 :         struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)];
     535             : 
     536           0 :         if (sc->sc_base.me_evp == NULL)
     537           0 :                 return (POLLERR);
     538           0 :         return (wsevent_poll(sc->sc_base.me_evp, events, p));
     539           0 : }
     540             : 
     541             : int
     542           0 : wsmousekqfilter(dev_t dev, struct knote *kn)
     543             : {
     544           0 :         struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)];
     545             : 
     546           0 :         if (sc->sc_base.me_evp == NULL)
     547           0 :                 return (ENXIO);
     548           0 :         return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
     549           0 : }
     550             : 
     551             : #if NWSMUX > 0
     552             : int
     553           0 : wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp)
     554             : {
     555           0 :         struct wsmouse_softc *sc = (struct wsmouse_softc *)me;
     556             : 
     557           0 :         if (sc->sc_base.me_evp != NULL)
     558           0 :                 return (EBUSY);
     559             : 
     560           0 :         return wsmousedoopen(sc, evp);
     561           0 : }
     562             : 
     563             : int
     564           0 : wsmouse_mux_close(struct wsevsrc *me)
     565             : {
     566           0 :         struct wsmouse_softc *sc = (struct wsmouse_softc *)me;
     567             : 
     568           0 :         sc->sc_base.me_evp = NULL;
     569           0 :         (*sc->sc_accessops->disable)(sc->sc_accesscookie);
     570             : 
     571           0 :         return (0);
     572             : }
     573             : 
     574             : int
     575           0 : wsmouse_add_mux(int unit, struct wsmux_softc *muxsc)
     576             : {
     577             :         struct wsmouse_softc *sc;
     578             : 
     579           0 :         if (unit < 0 || unit >= wsmouse_cd.cd_ndevs ||
     580           0 :             (sc = wsmouse_cd.cd_devs[unit]) == NULL)
     581           0 :                 return (ENXIO);
     582             : 
     583           0 :         if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
     584           0 :                 return (EBUSY);
     585             : 
     586           0 :         return (wsmux_attach_sc(muxsc, &sc->sc_base));
     587           0 : }
     588             : #endif  /* NWSMUX > 0 */
     589             : 
     590             : void
     591           0 : wsmouse_buttons(struct device *sc, u_int buttons)
     592             : {
     593           0 :         struct btn_state *btn = &((struct wsmouse_softc *) sc)->sc_input.btn;
     594             : 
     595           0 :         if (btn->sync)
     596             :                 /* Restore the old state. */
     597           0 :                 btn->buttons ^= btn->sync;
     598             : 
     599           0 :         btn->sync = btn->buttons ^ buttons;
     600           0 :         btn->buttons = buttons;
     601           0 : }
     602             : 
     603             : void
     604           0 : wsmouse_motion(struct device *sc, int dx, int dy, int dz, int dw)
     605             : {
     606             :         struct motion_state *motion =
     607           0 :             &((struct wsmouse_softc *) sc)->sc_input.motion;
     608             : 
     609           0 :         motion->dx = dx;
     610           0 :         motion->dy = dy;
     611           0 :         motion->dz = dz;
     612           0 :         motion->dw = dw;
     613           0 :         if (dx || dy || dz || dw)
     614           0 :                 motion->sync |= SYNC_DELTAS;
     615           0 : }
     616             : 
     617             : static inline void
     618           0 : set_x(struct position *pos, int x, u_int *sync, u_int mask)
     619             : {
     620           0 :         if (*sync & mask) {
     621           0 :                 if (x == pos->x)
     622             :                         return;
     623           0 :                 pos->x -= pos->dx;
     624           0 :                 pos->acc_dx -= pos->dx;
     625           0 :         }
     626           0 :         if ((pos->dx = x - pos->x)) {
     627           0 :                 pos->x = x;
     628           0 :                 pos->acc_dx += pos->dx;
     629           0 :                 *sync |= mask;
     630           0 :         }
     631           0 : }
     632             : 
     633             : static inline void
     634           0 : set_y(struct position *pos, int y, u_int *sync, u_int mask)
     635             : {
     636           0 :         if (*sync & mask) {
     637           0 :                 if (y == pos->y)
     638             :                         return;
     639           0 :                 pos->y -= pos->dy;
     640           0 :                 pos->acc_dy -= pos->dy;
     641           0 :         }
     642           0 :         if ((pos->dy = y - pos->y)) {
     643           0 :                 pos->y = y;
     644           0 :                 pos->acc_dy += pos->dy;
     645           0 :                 *sync |= mask;
     646           0 :         }
     647           0 : }
     648             : 
     649             : static inline void
     650           0 : cleardeltas(struct position *pos)
     651             : {
     652           0 :         pos->dx = pos->acc_dx = 0;
     653           0 :         pos->dy = pos->acc_dy = 0;
     654           0 : }
     655             : 
     656             : void
     657           0 : wsmouse_position(struct device *sc, int x, int y)
     658             : {
     659             :         struct motion_state *motion =
     660           0 :             &((struct wsmouse_softc *) sc)->sc_input.motion;
     661             : 
     662           0 :         set_x(&motion->pos, x, &motion->sync, SYNC_X);
     663           0 :         set_y(&motion->pos, y, &motion->sync, SYNC_Y);
     664           0 : }
     665             : 
     666             : static inline int
     667           0 : normalized_pressure(struct wsmouseinput *input, int pressure)
     668             : {
     669           0 :         int limit = imax(input->touch.min_pressure, 1);
     670             : 
     671           0 :         if (pressure >= limit)
     672           0 :                 return pressure;
     673             :         else
     674           0 :                 return (pressure < 0 ? limit : 0);
     675           0 : }
     676             : 
     677             : void
     678           0 : wsmouse_touch(struct device *sc, int pressure, int contacts)
     679             : {
     680           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
     681           0 :         struct touch_state *touch = &input->touch;
     682             : 
     683           0 :         pressure = normalized_pressure(input, pressure);
     684           0 :         contacts = (pressure ? imax(contacts, 1) : 0);
     685             : 
     686           0 :         if (pressure == 0 || pressure != touch->pressure) {
     687             :                 /*
     688             :                  * pressure == 0: Drivers may report possibly arbitrary
     689             :                  * coordinates in this case; touch_update will correct them.
     690             :                  */
     691           0 :                 touch->pressure = pressure;
     692           0 :                 touch->sync |= SYNC_PRESSURE;
     693           0 :         }
     694           0 :         if (contacts != touch->contacts) {
     695           0 :                 touch->contacts = contacts;
     696           0 :                 touch->sync |= SYNC_CONTACTS;
     697           0 :         }
     698           0 : }
     699             : 
     700             : void
     701           0 : wsmouse_mtstate(struct device *sc, int slot, int x, int y, int pressure)
     702             : {
     703           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
     704           0 :         struct mt_state *mt = &input->mt;
     705             :         struct mt_slot *mts;
     706             :         u_int bit;
     707             :         int initial;
     708             : 
     709           0 :         if (slot < 0 || slot >= mt->num_slots)
     710           0 :                 return;
     711             : 
     712           0 :         bit = (1 << slot);
     713           0 :         mt->frame |= bit;
     714             : 
     715             :         /* Is this a new touch? */
     716           0 :         initial = ((mt->touches & bit) == (mt->sync[MTS_TOUCH] & bit));
     717             : 
     718           0 :         mts = &mt->slots[slot];
     719             : 
     720           0 :         if (initial) {
     721           0 :                 mts->pos.x = x;
     722           0 :                 mts->pos.y = y;
     723           0 :                 cleardeltas(&mts->pos);
     724           0 :                 mt->sync[MTS_X] |= bit;
     725           0 :                 mt->sync[MTS_Y] |= bit;
     726           0 :         } else {
     727           0 :                 set_x(&mts->pos, x, mt->sync + MTS_X, bit);
     728           0 :                 set_y(&mts->pos, y, mt->sync + MTS_Y, bit);
     729             :         }
     730             : 
     731           0 :         pressure = normalized_pressure(input, pressure);
     732           0 :         if (pressure != mts->pressure || initial) {
     733           0 :                 mts->pressure = pressure;
     734           0 :                 mt->sync[MTS_PRESSURE] |= bit;
     735             : 
     736           0 :                 if (pressure) {
     737           0 :                         if ((mt->touches & bit) == 0) {
     738           0 :                                 mt->num_touches++;
     739           0 :                                 mt->touches |= bit;
     740           0 :                                 mt->sync[MTS_TOUCH] |= bit;
     741           0 :                         }
     742           0 :                 } else if (mt->touches & bit) {
     743           0 :                         mt->num_touches--;
     744           0 :                         mt->touches ^= bit;
     745           0 :                         mt->sync[MTS_TOUCH] |= bit;
     746           0 :                         mt->ptr_mask &= mt->touches;
     747           0 :                 }
     748             :         }
     749           0 : }
     750             : 
     751             : void
     752           0 : wsmouse_set(struct device *sc, enum wsmouseval type, int value, int aux)
     753             : {
     754           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
     755             :         struct mt_slot *mts;
     756             : 
     757           0 :         if (WSMOUSE_IS_MT_CODE(type)) {
     758           0 :                 if (aux < 0 || aux >= input->mt.num_slots)
     759           0 :                         return;
     760           0 :                 mts = &input->mt.slots[aux];
     761           0 :         }
     762             : 
     763           0 :         switch (type) {
     764             :         case WSMOUSE_REL_X:
     765           0 :                 value += input->motion.pos.x; /* fall through */
     766             :         case WSMOUSE_ABS_X:
     767           0 :                 wsmouse_position(sc, value, input->motion.pos.y);
     768           0 :                 return;
     769             :         case WSMOUSE_REL_Y:
     770           0 :                 value += input->motion.pos.y;
     771             :         case WSMOUSE_ABS_Y:
     772           0 :                 wsmouse_position(sc, input->motion.pos.x, value);
     773           0 :                 return;
     774             :         case WSMOUSE_PRESSURE:
     775           0 :                 wsmouse_touch(sc, value, input->touch.contacts);
     776           0 :                 return;
     777             :         case WSMOUSE_CONTACTS:
     778             :                 /* Contact counts can be overridden by wsmouse_touch. */
     779           0 :                 if (value != input->touch.contacts) {
     780           0 :                         input->touch.contacts = value;
     781           0 :                         input->touch.sync |= SYNC_CONTACTS;
     782           0 :                 }
     783           0 :                 return;
     784             :         case WSMOUSE_TOUCH_WIDTH:
     785           0 :                 if (value != input->touch.width) {
     786           0 :                         input->touch.width = value;
     787           0 :                         input->touch.sync |= SYNC_TOUCH_WIDTH;
     788           0 :                 }
     789           0 :                 return;
     790             :         case WSMOUSE_MT_REL_X:
     791           0 :                 value += mts->pos.x; /* fall through */
     792             :         case WSMOUSE_MT_ABS_X:
     793           0 :                 wsmouse_mtstate(sc, aux, value, mts->pos.y, mts->pressure);
     794           0 :                 return;
     795             :         case WSMOUSE_MT_REL_Y:
     796           0 :                 value += mts->pos.y;
     797             :         case WSMOUSE_MT_ABS_Y:
     798           0 :                 wsmouse_mtstate(sc, aux, mts->pos.x, value, mts->pressure);
     799           0 :                 return;
     800             :         case WSMOUSE_MT_PRESSURE:
     801           0 :                 wsmouse_mtstate(sc, aux, mts->pos.x, mts->pos.y, value);
     802           0 :                 return;
     803             :         }
     804           0 : }
     805             : 
     806             : /* Make touch and motion state consistent. */
     807             : void
     808           0 : wsmouse_touch_update(struct wsmouseinput *input)
     809             : {
     810           0 :         struct motion_state *motion = &input->motion;
     811           0 :         struct touch_state *touch = &input->touch;
     812             : 
     813           0 :         if (touch->pressure == 0) {
     814             :                 /*
     815             :                  * There may be zero coordinates, or coordinates of
     816             :                  * touches with pressure values below min_pressure.
     817             :                  */
     818           0 :                 if (motion->sync & SYNC_POSITION) {
     819             :                         /* Restore valid coordinates. */
     820           0 :                         motion->pos.x -= motion->pos.dx;
     821           0 :                         motion->pos.y -= motion->pos.dy;
     822           0 :                         motion->sync &= ~SYNC_POSITION;
     823           0 :                 }
     824             : 
     825           0 :                 if (touch->prev_contacts == 0)
     826           0 :                         touch->sync &= ~SYNC_PRESSURE;
     827             : 
     828             :         }
     829             : 
     830           0 :         if (touch->sync & SYNC_CONTACTS)
     831             :                 /* Suppress pointer movement. */
     832           0 :                 cleardeltas(&motion->pos);
     833             : 
     834           0 :         if ((touch->sync & SYNC_PRESSURE) && touch->min_pressure) {
     835           0 :                 if (touch->pressure >= input->filter.pressure_hi)
     836           0 :                         touch->min_pressure = input->filter.pressure_lo;
     837           0 :                 else if (touch->pressure < input->filter.pressure_lo)
     838           0 :                         touch->min_pressure = input->filter.pressure_hi;
     839             :         }
     840           0 : }
     841             : 
     842             : /* Normalize multitouch state. */
     843             : void
     844           0 : wsmouse_mt_update(struct wsmouseinput *input)
     845             : {
     846             :         int i;
     847             : 
     848             :         /*
     849             :          * The same as above: There may be arbitrary coordinates if
     850             :          * (pressure == 0). Clear the sync flags for touches that have
     851             :          * been released.
     852             :          */
     853           0 :         if (input->mt.sync[MTS_TOUCH] & ~input->mt.touches) {
     854           0 :                 for (i = MTS_X; i < MTS_SIZE; i++)
     855           0 :                         input->mt.sync[i] &= input->mt.touches;
     856             :         }
     857           0 : }
     858             : 
     859             : /* Return TRUE if a coordinate update may be noise. */
     860             : int
     861           0 : wsmouse_hysteresis(struct wsmouseinput *input, struct position *pos)
     862             : {
     863             : 
     864           0 :         if (!(input->filter.h.hysteresis && input->filter.v.hysteresis))
     865           0 :                 return (0);
     866             : 
     867           0 :         if ((pos->dx > 0 && pos->dx > pos->acc_dx)
     868           0 :            || (pos->dx < 0 && pos->dx < pos->acc_dx))
     869           0 :                 pos->acc_dx = pos->dx;
     870             : 
     871           0 :         if ((pos->dy > 0 && pos->dy > pos->acc_dy)
     872           0 :            || (pos->dy < 0 && pos->dy < pos->acc_dy))
     873           0 :                 pos->acc_dy = pos->dy;
     874             : 
     875           0 :         return (abs(pos->acc_dx) < input->filter.h.hysteresis
     876           0 :             && abs(pos->acc_dy) < input->filter.v.hysteresis);
     877           0 : }
     878             : 
     879             : /*
     880             :  * Select the pointer-controlling MT slot.
     881             :  *
     882             :  * Pointer-control is assigned to slots with non-zero motion deltas if
     883             :  * at least one such slot exists. This function doesn't impose any
     884             :  * restrictions on the way drivers use wsmouse_mtstate(), it covers
     885             :  * partial, unordered, and "delta-filtered" input.
     886             :  *
     887             :  * The "cycle" is the set of slots with X/Y updates in previous sync
     888             :  * operations; it will be cleared and rebuilt whenever a slot that is
     889             :  * being updated is already a member. If a cycle ends that doesn't
     890             :  * contain the pointer-controlling slot, a new slot will be selected.
     891             :  */
     892             : void
     893           0 : wsmouse_ptr_ctrl(struct wsmouseinput *input)
     894             : {
     895           0 :         struct mt_state *mt = &input->mt;
     896             :         u_int updates;
     897             :         int select, slot;
     898             : 
     899           0 :         updates = (mt->sync[MTS_X] | mt->sync[MTS_Y]) & ~mt->sync[MTS_TOUCH];
     900           0 :         FOREACHBIT(updates, slot) {
     901             :                 /*
     902             :                  * Touches that just produce noise are no problem if the
     903             :                  * frequency of zero deltas is high enough, but there might
     904             :                  * be no guarantee for that.
     905             :                  */
     906           0 :                 if (wsmouse_hysteresis(input, &mt->slots[slot].pos))
     907           0 :                         updates ^= (1 << slot);
     908             :         }
     909             : 
     910           0 :         mt->prev_ptr = mt->ptr;
     911             : 
     912           0 :         if (mt->num_touches <= 1) {
     913           0 :                 mt->ptr = mt->touches;
     914           0 :                 mt->ptr_cycle = mt->ptr;
     915           0 :                 return;
     916             :         }
     917             : 
     918             :         /*
     919             :          * If there is no pointer-controlling slot, or if it should be
     920             :          * masked, select a new one.
     921             :          */
     922           0 :         select = ((mt->ptr & mt->touches & ~mt->ptr_mask) == 0);
     923             : 
     924             :         /* Remove slots without coordinate deltas from the cycle. */
     925           0 :         mt->ptr_cycle &= ~(mt->frame ^ updates);
     926             : 
     927           0 :         if (mt->ptr_cycle & updates) {
     928           0 :                 select |= ((mt->ptr_cycle & mt->ptr) == 0);
     929           0 :                 mt->ptr_cycle = updates;
     930           0 :         } else {
     931           0 :                 mt->ptr_cycle |= updates;
     932             :         }
     933           0 :         if (select) {
     934           0 :                 if (mt->ptr_cycle & ~mt->ptr_mask)
     935           0 :                         slot = ffs(mt->ptr_cycle & ~mt->ptr_mask) - 1;
     936           0 :                 else if (mt->touches & ~mt->ptr_mask)
     937           0 :                         slot = ffs(mt->touches & ~mt->ptr_mask) - 1;
     938             :                 else
     939           0 :                         slot = ffs(mt->touches) - 1;
     940           0 :                 mt->ptr = (1 << slot);
     941           0 :         }
     942           0 : }
     943             : 
     944             : /* Derive touch and motion state from MT state. */
     945             : void
     946           0 : wsmouse_mt_convert(struct device *sc)
     947             : {
     948           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
     949           0 :         struct mt_state *mt = &input->mt;
     950             :         struct mt_slot *mts;
     951             :         int slot, pressure;
     952             : 
     953           0 :         wsmouse_ptr_ctrl(input);
     954             : 
     955           0 :         if (mt->ptr) {
     956           0 :                 slot = ffs(mt->ptr) - 1;
     957           0 :                 mts = &mt->slots[slot];
     958           0 :                 if (mts->pos.x != input->motion.pos.x)
     959           0 :                         input->motion.sync |= SYNC_X;
     960           0 :                 if (mts->pos.y != input->motion.pos.y)
     961           0 :                         input->motion.sync |= SYNC_Y;
     962           0 :                 if (mt->ptr != mt->prev_ptr)
     963             :                         /* Suppress pointer movement. */
     964           0 :                         mts->pos.dx = mts->pos.dy = 0;
     965           0 :                 memcpy(&input->motion.pos, &mts->pos, sizeof(struct position));
     966             : 
     967           0 :                 pressure = mts->pressure;
     968           0 :         } else {
     969             :                 pressure = 0;
     970             :         }
     971             : 
     972           0 :         wsmouse_touch(sc, pressure, mt->num_touches);
     973           0 : }
     974             : 
     975             : void
     976           0 : wsmouse_evq_put(struct evq_access *evq, int ev_type, int ev_value)
     977             : {
     978             :         struct wscons_event *ev;
     979             :         int space;
     980             : 
     981           0 :         space = evq->evar->get - evq->put;
     982           0 :         if (space != 1 && space != 1 - WSEVENT_QSIZE) {
     983           0 :                 ev = &evq->evar->q[evq->put++];
     984           0 :                 evq->put %= WSEVENT_QSIZE;
     985           0 :                 ev->type = ev_type;
     986           0 :                 ev->value = ev_value;
     987           0 :                 memcpy(&ev->time, &evq->ts, sizeof(struct timespec));
     988           0 :                 evq->result |= EVQ_RESULT_SUCCESS;
     989           0 :         } else {
     990           0 :                 evq->result = EVQ_RESULT_OVERFLOW;
     991             :         }
     992           0 : }
     993             : 
     994             : 
     995             : void
     996           0 : wsmouse_btn_sync(struct btn_state *btn, struct evq_access *evq)
     997             : {
     998             :         int button, ev_type;
     999             :         u_int bit, sync;
    1000             : 
    1001           0 :         for (sync = btn->sync; sync; sync ^= bit) {
    1002           0 :                 button = ffs(sync) - 1;
    1003           0 :                 bit = (1 << button);
    1004           0 :                 ev_type = (btn->buttons & bit) ? BTN_DOWN_EV : BTN_UP_EV;
    1005           0 :                 wsmouse_evq_put(evq, ev_type, button);
    1006             :         }
    1007           0 : }
    1008             : 
    1009             : /*
    1010             :  * Scale with a [*.12] fixed-point factor and a remainder:
    1011             :  */
    1012             : static inline int
    1013           0 : scale(int val, int factor, int *rmdr)
    1014             : {
    1015           0 :         val = val * factor + *rmdr;
    1016           0 :         if (val >= 0) {
    1017           0 :                 *rmdr = val & 0xfff;
    1018           0 :                 return (val >> 12);
    1019             :         } else {
    1020           0 :                 *rmdr = -(-val & 0xfff);
    1021           0 :                 return -(-val >> 12);
    1022             :         }
    1023           0 : }
    1024             : 
    1025             : void
    1026           0 : wsmouse_motion_sync(struct wsmouseinput *input, struct evq_access *evq)
    1027             : {
    1028           0 :         struct motion_state *motion = &input->motion;
    1029           0 :         struct axis_filter *h = &input->filter.h;
    1030           0 :         struct axis_filter *v = &input->filter.v;
    1031             :         int x, y, dx, dy;
    1032             : 
    1033           0 :         if (motion->sync & SYNC_DELTAS) {
    1034           0 :                 dx = h->inv ? -motion->dx : motion->dx;
    1035           0 :                 dy = v->inv ? -motion->dy : motion->dy;
    1036           0 :                 if (h->scale)
    1037           0 :                         dx = scale(dx, h->scale, &h->rmdr);
    1038           0 :                 if (v->scale)
    1039           0 :                         dy = scale(dy, v->scale, &v->rmdr);
    1040           0 :                 if (dx)
    1041           0 :                         wsmouse_evq_put(evq, DELTA_X_EV(input), dx);
    1042           0 :                 if (dy)
    1043           0 :                         wsmouse_evq_put(evq, DELTA_Y_EV(input), dy);
    1044           0 :                 if (motion->dz)
    1045           0 :                         wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
    1046           0 :                 if (motion->dw)
    1047           0 :                         wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
    1048             :         }
    1049           0 :         if (motion->sync & SYNC_POSITION) {
    1050           0 :                 if (motion->sync & SYNC_X) {
    1051           0 :                         x = (h->inv ? h->inv - motion->pos.x : motion->pos.x);
    1052           0 :                         wsmouse_evq_put(evq, ABS_X_EV(input), x);
    1053           0 :                 }
    1054           0 :                 if (motion->sync & SYNC_Y) {
    1055           0 :                         y = (v->inv ? v->inv - motion->pos.y : motion->pos.y);
    1056           0 :                         wsmouse_evq_put(evq, ABS_Y_EV(input), y);
    1057           0 :                 }
    1058           0 :                 if (motion->pos.dx == 0 && motion->pos.dy == 0
    1059           0 :                     && (input->flags & TPAD_NATIVE_MODE ))
    1060             :                         /* Suppress pointer motion. */
    1061           0 :                         wsmouse_evq_put(evq, WSCONS_EVENT_TOUCH_RESET, 0);
    1062             :         }
    1063           0 : }
    1064             : 
    1065             : void
    1066           0 : wsmouse_touch_sync(struct wsmouseinput *input, struct evq_access *evq)
    1067             : {
    1068           0 :         struct touch_state *touch = &input->touch;
    1069             : 
    1070           0 :         if (touch->sync & SYNC_PRESSURE)
    1071           0 :                 wsmouse_evq_put(evq, ABS_Z_EV, touch->pressure);
    1072           0 :         if (touch->sync & SYNC_CONTACTS)
    1073           0 :                 wsmouse_evq_put(evq, ABS_W_EV, touch->contacts);
    1074           0 :         if ((touch->sync & SYNC_TOUCH_WIDTH)
    1075           0 :             && (input->flags & TPAD_NATIVE_MODE))
    1076           0 :                 wsmouse_evq_put(evq, WSCONS_EVENT_TOUCH_WIDTH, touch->width);
    1077           0 : }
    1078             : 
    1079             : void
    1080           0 : wsmouse_log_input(struct wsmouseinput *input, struct timespec *ts)
    1081             : {
    1082           0 :         struct motion_state *motion = &input->motion;
    1083             :         int t_sync, mt_sync;
    1084             : 
    1085           0 :         t_sync = (input->touch.sync & SYNC_CONTACTS);
    1086           0 :         mt_sync = (input->mt.frame && (input->mt.sync[MTS_TOUCH]
    1087           0 :             || input->mt.ptr != input->mt.prev_ptr));
    1088             : 
    1089           0 :         if (motion->sync || mt_sync || t_sync || input->btn.sync)
    1090           0 :                 printf("[%s-in][%04d]", DEVNAME(input), LOGTIME(ts));
    1091             :         else
    1092           0 :                 return;
    1093             : 
    1094           0 :         if (motion->sync & SYNC_POSITION)
    1095           0 :                 printf(" abs:%d,%d", motion->pos.x, motion->pos.y);
    1096           0 :         if (motion->sync & SYNC_DELTAS)
    1097           0 :                 printf(" rel:%d,%d,%d,%d", motion->dx, motion->dy,
    1098           0 :                     motion->dz, motion->dw);
    1099           0 :         if (mt_sync)
    1100           0 :                 printf(" mt:0x%02x:%d", input->mt.touches,
    1101           0 :                     ffs(input->mt.ptr) - 1);
    1102           0 :         else if (t_sync)
    1103           0 :                 printf(" t:%d", input->touch.contacts);
    1104           0 :         if (input->btn.sync)
    1105           0 :                 printf(" btn:0x%02x", input->btn.buttons);
    1106           0 :         printf("\n");
    1107           0 : }
    1108             : 
    1109             : void
    1110           0 : wsmouse_log_events(struct wsmouseinput *input, struct evq_access *evq)
    1111             : {
    1112             :         struct wscons_event *ev;
    1113           0 :         int n = evq->evar->put;
    1114             : 
    1115           0 :         if (n != evq->put) {
    1116           0 :                 printf("[%s-ev][%04d]", DEVNAME(input), LOGTIME(&evq->ts));
    1117           0 :                 while (n != evq->put) {
    1118           0 :                         ev = &evq->evar->q[n++];
    1119           0 :                         n %= WSEVENT_QSIZE;
    1120           0 :                         printf(" %d:%d", ev->type, ev->value);
    1121             :                 }
    1122           0 :                 printf("\n");
    1123           0 :         }
    1124           0 : }
    1125             : 
    1126             : static inline void
    1127           0 : clear_sync_flags(struct wsmouseinput *input)
    1128             : {
    1129             :         int i;
    1130             : 
    1131           0 :         input->btn.sync = 0;
    1132           0 :         input->sbtn.sync = 0;
    1133           0 :         input->motion.sync = 0;
    1134           0 :         input->touch.sync = 0;
    1135           0 :         input->touch.prev_contacts = input->touch.contacts;
    1136           0 :         if (input->mt.frame) {
    1137           0 :                 input->mt.frame = 0;
    1138           0 :                 for (i = 0; i < MTS_SIZE; i++)
    1139           0 :                         input->mt.sync[i] = 0;
    1140             :         }
    1141           0 : }
    1142             : 
    1143             : void
    1144           0 : wsmouse_input_sync(struct device *sc)
    1145             : {
    1146           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1147           0 :         struct evq_access evq;
    1148             : 
    1149           0 :         evq.evar = *input->evar;
    1150           0 :         if (evq.evar == NULL)
    1151           0 :                 return;
    1152           0 :         evq.put = evq.evar->put;
    1153           0 :         evq.result = EVQ_RESULT_NONE;
    1154           0 :         getnanotime(&evq.ts);
    1155             : 
    1156           0 :         enqueue_randomness(input->btn.buttons
    1157           0 :             ^ input->motion.dx ^ input->motion.dy
    1158           0 :             ^ input->motion.pos.x ^ input->motion.pos.y
    1159           0 :             ^ input->motion.dz ^ input->motion.dw);
    1160             : 
    1161           0 :         if (input->mt.frame) {
    1162           0 :                 wsmouse_mt_update(input);
    1163           0 :                 wsmouse_mt_convert(sc);
    1164           0 :         }
    1165           0 :         if (input->touch.sync)
    1166           0 :                 wsmouse_touch_update(input);
    1167             : 
    1168           0 :         if (input->flags & LOG_INPUT)
    1169           0 :                 wsmouse_log_input(input, &evq.ts);
    1170             : 
    1171           0 :         if (input->flags & TPAD_COMPAT_MODE)
    1172           0 :                 wstpad_compat_convert(input, &evq);
    1173             : 
    1174           0 :         if (input->flags & RESYNC) {
    1175           0 :                 input->flags &= ~RESYNC;
    1176           0 :                 input->motion.sync &= SYNC_POSITION;
    1177           0 :         }
    1178             : 
    1179           0 :         if (input->btn.sync)
    1180           0 :                 wsmouse_btn_sync(&input->btn, &evq);
    1181           0 :         if (input->sbtn.sync)
    1182           0 :                 wsmouse_btn_sync(&input->sbtn, &evq);
    1183           0 :         if (input->motion.sync)
    1184           0 :                 wsmouse_motion_sync(input, &evq);
    1185           0 :         if (input->touch.sync)
    1186           0 :                 wsmouse_touch_sync(input, &evq);
    1187             :         /* No MT events are generated yet. */
    1188             : 
    1189           0 :         if (evq.result == EVQ_RESULT_SUCCESS) {
    1190           0 :                 wsmouse_evq_put(&evq, WSCONS_EVENT_SYNC, 0);
    1191           0 :                 if (evq.result == EVQ_RESULT_SUCCESS) {
    1192           0 :                         if (input->flags & LOG_EVENTS) {
    1193           0 :                                 wsmouse_log_events(input, &evq);
    1194           0 :                         }
    1195           0 :                         evq.evar->put = evq.put;
    1196           0 :                         WSEVENT_WAKEUP(evq.evar);
    1197             :                 }
    1198             :         }
    1199             : 
    1200           0 :         if (evq.result != EVQ_RESULT_OVERFLOW)
    1201           0 :                 clear_sync_flags(input);
    1202             :         else
    1203           0 :                 input->flags |= RESYNC;
    1204           0 : }
    1205             : 
    1206             : int
    1207           0 : wsmouse_id_to_slot(struct device *sc, int id)
    1208             : {
    1209           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1210           0 :         struct mt_state *mt = &input->mt;
    1211             :         int slot;
    1212             : 
    1213           0 :         if (mt->num_slots == 0)
    1214           0 :                 return (-1);
    1215             : 
    1216           0 :         FOREACHBIT(mt->touches, slot) {
    1217           0 :                 if (mt->slots[slot].id == id)
    1218           0 :                         return slot;
    1219             :         }
    1220           0 :         slot = ffs(~(mt->touches | mt->frame)) - 1;
    1221           0 :         if (slot >= 0 && slot < mt->num_slots) {
    1222           0 :                 mt->frame |= 1 << slot;
    1223           0 :                 mt->slots[slot].id = id;
    1224           0 :                 return (slot);
    1225             :         } else {
    1226           0 :                 return (-1);
    1227             :         }
    1228           0 : }
    1229             : 
    1230             : /*
    1231             :  * Find a minimum-weight matching for an m-by-n matrix.
    1232             :  *
    1233             :  * m must be greater than or equal to n. The size of the buffer must be
    1234             :  * at least 3m + 3n.
    1235             :  *
    1236             :  * On return, the first m elements of the buffer contain the row-to-
    1237             :  * column mappings, i.e., buffer[i] is the column index for row i, or -1
    1238             :  * if there is no assignment for that row (which may happen if n < m).
    1239             :  *
    1240             :  * Wrong results because of overflows will not occur with input values
    1241             :  * in the range of 0 to INT_MAX / 2 inclusive.
    1242             :  *
    1243             :  * The function applies the Dinic-Kronrod algorithm. It is not modern or
    1244             :  * popular, but it seems to be a good choice for small matrices at least.
    1245             :  * The original form of the algorithm is modified as follows: There is no
    1246             :  * initial search for row minima, the initial assignments are in a
    1247             :  * "virtual" column with the index -1 and zero values. This permits inputs
    1248             :  * with n < m, and it simplifies the reassignments.
    1249             :  */
    1250             : void
    1251           0 : wsmouse_matching(int *matrix, int m, int n, int *buffer)
    1252             : {
    1253             :         int i, j, k, d, e, row, col, delta;
    1254             :         int *p;
    1255             :         int *r2c = buffer;      /* row-to-column assignments */
    1256           0 :         int *red = r2c + m;     /* reduced values of the assignments */
    1257           0 :         int *mc = red + m;      /* row-wise minimal elements of cs */
    1258           0 :         int *cs = mc + m;       /* the column set */
    1259           0 :         int *c2r = cs + n;      /* column-to-row assignments in cs */
    1260           0 :         int *cd = c2r + n;      /* column deltas (reduction) */
    1261             : 
    1262           0 :         for (p = r2c; p < red; *p++ = -1) {}
    1263           0 :         for (; p < mc; *p++ = 0) {}
    1264           0 :         for (col = 0; col < n; col++) {
    1265             :                 delta = INT_MAX;
    1266           0 :                 for (i = 0, p = matrix + col; i < m; i++, p += n) {
    1267           0 :                         d = *p - red[i];
    1268           0 :                         if (d < delta || (d == delta && r2c[i] < 0)) {
    1269             :                                 delta = d;
    1270             :                                 row = i;
    1271           0 :                         }
    1272             :                 }
    1273           0 :                 cd[col] = delta;
    1274           0 :                 if (r2c[row] < 0) {
    1275           0 :                         r2c[row] = col;
    1276           0 :                         continue;
    1277             :                 }
    1278           0 :                 for (p = mc; p < cs; *p++ = col) {}
    1279           0 :                 for (k = 0; (j = r2c[row]) >= 0;) {
    1280           0 :                         cs[k++] = j;
    1281           0 :                         c2r[j] = row;
    1282           0 :                         mc[row] -= n;
    1283             :                         delta = INT_MAX;
    1284           0 :                         for (i = 0, p = matrix; i < m; i++, p += n)
    1285           0 :                                 if (mc[i] >= 0) {
    1286           0 :                                         d = p[mc[i]] - cd[mc[i]];
    1287           0 :                                         e = p[j] - cd[j];
    1288           0 :                                         if (e < d) {
    1289             :                                                 d = e;
    1290           0 :                                                 mc[i] = j;
    1291           0 :                                         }
    1292           0 :                                         d -= red[i];
    1293           0 :                                         if (d < delta || (d == delta
    1294           0 :                                             && r2c[i] < 0)) {
    1295             :                                                 delta = d;
    1296             :                                                 row = i;
    1297           0 :                                         }
    1298             :                                 }
    1299           0 :                         cd[col] += delta;
    1300           0 :                         for (i = 0; i < k; i++) {
    1301           0 :                                 cd[cs[i]] += delta;
    1302           0 :                                 red[c2r[cs[i]]] -= delta;
    1303             :                         }
    1304             :                 }
    1305           0 :                 for (j = mc[row]; (r2c[row] = j) != col;) {
    1306           0 :                         row = c2r[j];
    1307           0 :                         j = mc[row] + n;
    1308             :                 }
    1309             :         }
    1310           0 : }
    1311             : 
    1312             : /*
    1313             :  * Assign slot numbers to the points in the pt array, and update all slots by
    1314             :  * calling wsmouse_mtstate internally.  The slot numbers are passed to the
    1315             :  * caller in the pt->slot fields.
    1316             :  *
    1317             :  * The slot assignment pairs the points with points of the previous frame in
    1318             :  * such a way that the sum of the squared distances is minimal.  Using
    1319             :  * squares instead of simple distances favours assignments with more uniform
    1320             :  * distances, and it is faster.
    1321             :  */
    1322             : void
    1323           0 : wsmouse_mtframe(struct device *sc, struct mtpoint *pt, int size)
    1324             : {
    1325           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1326           0 :         struct mt_state *mt = &input->mt;
    1327             :         int i, j, m, n, dx, dy, slot, maxdist;
    1328             :         int *p, *r2c, *c2r;
    1329             :         u_int touches;
    1330             : 
    1331           0 :         if (mt->num_slots == 0 || mt->matrix == NULL)
    1332           0 :                 return;
    1333             : 
    1334           0 :         size = imax(0, imin(size, mt->num_slots));
    1335           0 :         p = mt->matrix;
    1336           0 :         touches = mt->touches;
    1337           0 :         if (mt->num_touches >= size) {
    1338           0 :                 FOREACHBIT(touches, slot)
    1339           0 :                         for (i = 0; i < size; i++) {
    1340           0 :                                 dx = pt[i].x - mt->slots[slot].pos.x;
    1341           0 :                                 dy = pt[i].y - mt->slots[slot].pos.y;
    1342           0 :                                 *p++ = dx * dx + dy * dy;
    1343             :                         }
    1344           0 :                 m = mt->num_touches;
    1345             :                 n = size;
    1346           0 :         } else {
    1347           0 :                 for (i = 0; i < size; i++)
    1348           0 :                         FOREACHBIT(touches, slot) {
    1349           0 :                                 dx = pt[i].x - mt->slots[slot].pos.x;
    1350           0 :                                 dy = pt[i].y - mt->slots[slot].pos.y;
    1351           0 :                                 *p++ = dx * dx + dy * dy;
    1352             :                         }
    1353             :                 m = size;
    1354           0 :                 n = mt->num_touches;
    1355             :         }
    1356           0 :         wsmouse_matching(mt->matrix, m, n, p);
    1357             : 
    1358             :         r2c = p;
    1359           0 :         c2r = p + m;
    1360           0 :         maxdist = input->filter.tracking_maxdist;
    1361           0 :         maxdist = (maxdist ? maxdist * maxdist : INT_MAX);
    1362           0 :         for (i = 0, p = mt->matrix; i < m; i++, p += n)
    1363           0 :                 if ((j = r2c[i]) >= 0) {
    1364           0 :                         if (p[j] <= maxdist)
    1365           0 :                                 c2r[j] = i;
    1366             :                         else
    1367           0 :                                 c2r[j] = r2c[i] = -1;
    1368             :                 }
    1369             : 
    1370           0 :         p = (n == size ? c2r : r2c);
    1371           0 :         for (i = 0; i < size; i++)
    1372           0 :                 if (*p++ < 0) {
    1373           0 :                         slot = ffs(~(mt->touches | mt->frame)) - 1;
    1374           0 :                         if (slot < 0 || slot >= mt->num_slots)
    1375             :                                 break;
    1376           0 :                         wsmouse_mtstate(sc, slot,
    1377           0 :                             pt[i].x, pt[i].y, pt[i].pressure);
    1378           0 :                         pt[i].slot = slot;
    1379           0 :                 }
    1380             : 
    1381           0 :         p = (n == size ? r2c : c2r);
    1382           0 :         FOREACHBIT(touches, slot)
    1383           0 :                 if ((i = *p++) >= 0) {
    1384           0 :                         wsmouse_mtstate(sc, slot,
    1385           0 :                             pt[i].x, pt[i].y, pt[i].pressure);
    1386           0 :                         pt[i].slot = slot;
    1387           0 :                 } else {
    1388           0 :                         wsmouse_mtstate(sc, slot, 0, 0, 0);
    1389             :                 }
    1390           0 : }
    1391             : 
    1392             : static inline void
    1393           0 : free_mt_slots(struct wsmouseinput *input)
    1394             : {
    1395             :         int n, size;
    1396             : 
    1397           0 :         if ((n = input->mt.num_slots)) {
    1398           0 :                 size = n * sizeof(struct mt_slot);
    1399           0 :                 if (input->flags & MT_TRACKING)
    1400           0 :                         size += MATRIX_SIZE(n);
    1401           0 :                 input->mt.num_slots = 0;
    1402           0 :                 free(input->mt.slots, M_DEVBUF, size);
    1403           0 :                 input->mt.slots = NULL;
    1404           0 :                 input->mt.matrix = NULL;
    1405           0 :         }
    1406           0 : }
    1407             : 
    1408             : /* Allocate the MT slots and, if necessary, the buffers for MT tracking. */
    1409             : int
    1410           0 : wsmouse_mt_init(struct device *sc, int num_slots, int tracking)
    1411             : {
    1412           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1413             :         int n, size;
    1414             : 
    1415           0 :         if (num_slots == input->mt.num_slots
    1416           0 :             && (!tracking == ((input->flags & MT_TRACKING) == 0)))
    1417           0 :                 return (0);
    1418             : 
    1419           0 :         free_mt_slots(input);
    1420             : 
    1421           0 :         if (tracking)
    1422           0 :                 input->flags |= MT_TRACKING;
    1423             :         else
    1424           0 :                 input->flags &= ~MT_TRACKING;
    1425           0 :         n = imin(imax(num_slots, 0), WSMOUSE_MT_SLOTS_MAX);
    1426           0 :         if (n) {
    1427           0 :                 size = n * sizeof(struct mt_slot);
    1428           0 :                 if (input->flags & MT_TRACKING)
    1429           0 :                         size += MATRIX_SIZE(n);
    1430           0 :                 input->mt.slots = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
    1431           0 :                 if (input->mt.slots != NULL) {
    1432           0 :                         if (input->flags & MT_TRACKING)
    1433           0 :                                 input->mt.matrix = (int *)
    1434           0 :                                     (input->mt.slots + n);
    1435           0 :                         input->mt.num_slots = n;
    1436           0 :                         return (0);
    1437             :                 }
    1438             :         }
    1439           0 :         return (-1);
    1440           0 : }
    1441             : 
    1442             : int
    1443           0 : wsmouse_get_params(struct device *sc,
    1444             :     struct wsmouse_param *params, u_int nparams)
    1445             : {
    1446           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1447             :         int i, key, error = 0;
    1448             : 
    1449           0 :         for (i = 0; i < nparams; i++) {
    1450           0 :                 key = params[i].key;
    1451           0 :                 switch (key) {
    1452             :                 case WSMOUSECFG_DX_SCALE:
    1453           0 :                         params[i].value = input->filter.h.scale;
    1454           0 :                         break;
    1455             :                 case WSMOUSECFG_DY_SCALE:
    1456           0 :                         params[i].value = input->filter.v.scale;
    1457           0 :                         break;
    1458             :                 case WSMOUSECFG_PRESSURE_LO:
    1459           0 :                         params[i].value = input->filter.pressure_lo;
    1460           0 :                         break;
    1461             :                 case WSMOUSECFG_PRESSURE_HI:
    1462           0 :                         params[i].value = input->filter.pressure_hi;
    1463           0 :                         break;
    1464             :                 case WSMOUSECFG_TRKMAXDIST:
    1465           0 :                         params[i].value = input->filter.tracking_maxdist;
    1466           0 :                         break;
    1467             :                 case WSMOUSECFG_SWAPXY:
    1468           0 :                         params[i].value = input->filter.swapxy;
    1469           0 :                         break;
    1470             :                 case WSMOUSECFG_X_INV:
    1471           0 :                         params[i].value = input->filter.h.inv;
    1472           0 :                         break;
    1473             :                 case WSMOUSECFG_Y_INV:
    1474           0 :                         params[i].value = input->filter.v.inv;
    1475           0 :                         break;
    1476             :                 case WSMOUSECFG_DX_MAX:
    1477           0 :                         params[i].value = input->filter.h.dmax;
    1478           0 :                         break;
    1479             :                 case WSMOUSECFG_DY_MAX:
    1480           0 :                         params[i].value = input->filter.v.dmax;
    1481           0 :                         break;
    1482             :                 case WSMOUSECFG_X_HYSTERESIS:
    1483           0 :                         params[i].value = input->filter.h.hysteresis;
    1484           0 :                         break;
    1485             :                 case WSMOUSECFG_Y_HYSTERESIS:
    1486           0 :                         params[i].value = input->filter.v.hysteresis;
    1487           0 :                         break;
    1488             :                 case WSMOUSECFG_DECELERATION:
    1489           0 :                         params[i].value = input->filter.dclr;
    1490           0 :                         break;
    1491             :                 case WSMOUSECFG_STRONG_HYSTERESIS:
    1492           0 :                         params[i].value =
    1493           0 :                             !!(input->filter.mode & STRONG_HYSTERESIS);
    1494           0 :                         break;
    1495             :                 case WSMOUSECFG_SMOOTHING:
    1496           0 :                         params[i].value =
    1497           0 :                             input->filter.mode & SMOOTHING_MASK;
    1498           0 :                         break;
    1499             :                 case WSMOUSECFG_LOG_INPUT:
    1500           0 :                         params[i].value = !!(input->flags & LOG_INPUT);
    1501           0 :                         break;
    1502             :                 case WSMOUSECFG_LOG_EVENTS:
    1503           0 :                         params[i].value = !!(input->flags & LOG_EVENTS);
    1504           0 :                         break;
    1505             :                 default:
    1506           0 :                         error = wstpad_get_param(input, key, &params[i].value);
    1507           0 :                         if (error != 0)
    1508           0 :                                 return (error);
    1509             :                         break;
    1510             :                 }
    1511             :         }
    1512             : 
    1513           0 :         return (0);
    1514           0 : }
    1515             : 
    1516             : int
    1517           0 : wsmouse_set_params(struct device *sc,
    1518             :     const struct wsmouse_param *params, u_int nparams)
    1519             : {
    1520           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1521             :         int i, val, key, needreset = 0, error = 0;
    1522             : 
    1523           0 :         for (i = 0; i < nparams; i++) {
    1524           0 :                 key = params[i].key;
    1525           0 :                 val = params[i].value;
    1526           0 :                 switch (params[i].key) {
    1527             :                 case WSMOUSECFG_PRESSURE_LO:
    1528           0 :                         input->filter.pressure_lo = val;
    1529           0 :                         if (val > input->filter.pressure_hi)
    1530           0 :                                 input->filter.pressure_hi = val;
    1531           0 :                         input->touch.min_pressure = input->filter.pressure_hi;
    1532           0 :                         break;
    1533             :                 case WSMOUSECFG_PRESSURE_HI:
    1534           0 :                         input->filter.pressure_hi = val;
    1535           0 :                         if (val < input->filter.pressure_lo)
    1536           0 :                                 input->filter.pressure_lo = val;
    1537           0 :                         input->touch.min_pressure = val;
    1538           0 :                         break;
    1539             :                 case WSMOUSECFG_X_HYSTERESIS:
    1540           0 :                         input->filter.h.hysteresis = val;
    1541           0 :                         break;
    1542             :                 case WSMOUSECFG_Y_HYSTERESIS:
    1543           0 :                         input->filter.v.hysteresis = val;
    1544           0 :                         break;
    1545             :                 case WSMOUSECFG_DECELERATION:
    1546           0 :                         input->filter.dclr = val;
    1547           0 :                         wstpad_init_deceleration(input);
    1548           0 :                         break;
    1549             :                 case WSMOUSECFG_DX_SCALE:
    1550           0 :                         input->filter.h.scale = val;
    1551           0 :                         break;
    1552             :                 case WSMOUSECFG_DY_SCALE:
    1553           0 :                         input->filter.v.scale = val;
    1554           0 :                         break;
    1555             :                 case WSMOUSECFG_TRKMAXDIST:
    1556           0 :                         input->filter.tracking_maxdist = val;
    1557           0 :                         break;
    1558             :                 case WSMOUSECFG_SWAPXY:
    1559           0 :                         input->filter.swapxy = val;
    1560           0 :                         break;
    1561             :                 case WSMOUSECFG_X_INV:
    1562           0 :                         input->filter.h.inv = val;
    1563           0 :                         break;
    1564             :                 case WSMOUSECFG_Y_INV:
    1565           0 :                         input->filter.v.inv = val;
    1566           0 :                         break;
    1567             :                 case WSMOUSECFG_DX_MAX:
    1568           0 :                         input->filter.h.dmax = val;
    1569           0 :                         break;
    1570             :                 case WSMOUSECFG_DY_MAX:
    1571           0 :                         input->filter.v.dmax = val;
    1572           0 :                         break;
    1573             :                 case WSMOUSECFG_STRONG_HYSTERESIS:
    1574           0 :                         if (val)
    1575           0 :                                 input->filter.mode |= STRONG_HYSTERESIS;
    1576             :                         else
    1577           0 :                                 input->filter.mode &= ~STRONG_HYSTERESIS;
    1578             :                         break;
    1579             :                 case WSMOUSECFG_SMOOTHING:
    1580           0 :                         input->filter.mode &= ~SMOOTHING_MASK;
    1581           0 :                         input->filter.mode |= (val & SMOOTHING_MASK);
    1582           0 :                         break;
    1583             :                 case WSMOUSECFG_LOG_INPUT:
    1584           0 :                         if (val)
    1585           0 :                                 input->flags |= LOG_INPUT;
    1586             :                         else
    1587           0 :                                 input->flags &= ~LOG_INPUT;
    1588             :                         break;
    1589             :                 case WSMOUSECFG_LOG_EVENTS:
    1590           0 :                         if (val)
    1591           0 :                                 input->flags |= LOG_EVENTS;
    1592             :                         else
    1593           0 :                                 input->flags &= ~LOG_EVENTS;
    1594             :                         break;
    1595             :                 default:
    1596             :                         needreset = 1;
    1597           0 :                         error = wstpad_set_param(input, key, val);
    1598           0 :                         if (error != 0)
    1599           0 :                                 return (error);
    1600             :                         break;
    1601             :                 }
    1602             :         }
    1603             : 
    1604             :         /* Reset soft-states if touchpad parameters changed */
    1605           0 :         if (needreset) {
    1606           0 :                 wstpad_reset(input);
    1607           0 :                 return (wstpad_configure(input));
    1608             :         }
    1609             : 
    1610           0 :         return (0);
    1611           0 : }
    1612             : 
    1613             : int
    1614           0 : wsmouse_set_mode(struct device *sc, int mode)
    1615             : {
    1616           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1617             : 
    1618           0 :         if (mode == WSMOUSE_COMPAT) {
    1619           0 :                 input->flags &= ~TPAD_NATIVE_MODE;
    1620           0 :                 input->flags |= TPAD_COMPAT_MODE;
    1621           0 :                 return (0);
    1622           0 :         } else if (mode == WSMOUSE_NATIVE) {
    1623           0 :                 input->flags &= ~TPAD_COMPAT_MODE;
    1624           0 :                 input->flags |= TPAD_NATIVE_MODE;
    1625           0 :                 return (0);
    1626             :         }
    1627           0 :         return (-1);
    1628           0 : }
    1629             : 
    1630           0 : struct wsmousehw *wsmouse_get_hw(struct device *sc)
    1631             : {
    1632           0 :         return &((struct wsmouse_softc *) sc)->sc_input.hw;
    1633             : }
    1634             : 
    1635             : /*
    1636             :  * Create a default configuration based on the hardware infos in the 'hw'
    1637             :  * fields. The 'params' argument is optional, hardware drivers can use it
    1638             :  * to modify the generic defaults. Up to now this function is only useful
    1639             :  * for touchpads.
    1640             :  */
    1641             : int
    1642           0 : wsmouse_configure(struct device *sc,
    1643             :     struct wsmouse_param *params, u_int nparams)
    1644             : {
    1645           0 :         struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
    1646             :         int error;
    1647             : 
    1648           0 :         if (!(input->flags & CONFIGURED)) {
    1649           0 :                 if (input->hw.x_max && input->hw.y_max) {
    1650           0 :                         if (input->hw.flags & WSMOUSEHW_LR_DOWN) {
    1651           0 :                                 input->filter.v.inv =
    1652           0 :                                     input->hw.y_max + input->hw.y_min;
    1653           0 :                         }
    1654             :                 }
    1655           0 :                 input->filter.ratio = 1 << 12;
    1656           0 :                 if (input->hw.h_res > 0 && input->hw.v_res > 0) {
    1657           0 :                         input->filter.ratio *= input->hw.h_res;
    1658           0 :                         input->filter.ratio /= input->hw.v_res;
    1659           0 :                 }
    1660           0 :                 if (wsmouse_mt_init(sc, input->hw.mt_slots,
    1661           0 :                     (input->hw.flags & WSMOUSEHW_MT_TRACKING))) {
    1662           0 :                         printf("wsmouse_configure: "
    1663             :                             "MT initialization failed.\n");
    1664           0 :                         return (-1);
    1665             :                 }
    1666           0 :                 if (IS_TOUCHPAD(input) && wstpad_configure(input)) {
    1667           0 :                         printf("wstpad_configure: "
    1668             :                             "Initialization failed.\n");
    1669           0 :                         return (-1);
    1670             :                 }
    1671           0 :                 if (params != NULL) {
    1672           0 :                         if ((error = wsmouse_set_params(sc, params, nparams)))
    1673           0 :                                 return (error);
    1674             :                 }
    1675           0 :                 input->flags |= CONFIGURED;
    1676           0 :         }
    1677           0 :         if (IS_TOUCHPAD(input))
    1678           0 :                 wsmouse_set_mode(sc, WSMOUSE_COMPAT);
    1679             : 
    1680           0 :         return (0);
    1681           0 : }
    1682             : 
    1683             : 
    1684             : void
    1685           0 : wsmouse_input_reset(struct wsmouseinput *input)
    1686             : {
    1687             :         int num_slots, *matrix;
    1688             :         struct mt_slot *slots;
    1689             : 
    1690           0 :         memset(&input->btn, 0, sizeof(struct btn_state));
    1691           0 :         memset(&input->motion, 0, sizeof(struct motion_state));
    1692           0 :         memset(&input->touch, 0, sizeof(struct touch_state));
    1693           0 :         input->touch.min_pressure = input->filter.pressure_hi;
    1694           0 :         if ((num_slots = input->mt.num_slots)) {
    1695           0 :                 slots = input->mt.slots;
    1696           0 :                 matrix = input->mt.matrix;
    1697           0 :                 memset(&input->mt, 0, sizeof(struct mt_state));
    1698           0 :                 memset(slots, 0, num_slots * sizeof(struct mt_slot));
    1699           0 :                 input->mt.num_slots = num_slots;
    1700           0 :                 input->mt.slots = slots;
    1701           0 :                 input->mt.matrix = matrix;
    1702           0 :         }
    1703           0 :         if (input->tp != NULL)
    1704           0 :                 wstpad_reset(input);
    1705           0 : }
    1706             : 
    1707             : void
    1708           0 : wsmouse_input_cleanup(struct wsmouseinput *input)
    1709             : {
    1710           0 :         free_mt_slots(input);
    1711           0 : }

Generated by: LCOV version 1.13