/* $NetBSD: wsmouse.c,v 1.75 2025/04/07 11:25:42 hans Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Julio M. Merino Vidal.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christopher G. Demetriou
* for the NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ms.c 8.1 (Berkeley) 6/11/93
*/
u_int sc_mb; /* mouse button state */
u_int sc_ub; /* user button state */
int sc_dx; /* delta-x */
int sc_dy; /* delta-y */
int sc_dz; /* delta-z */
int sc_dw; /* delta-w */
int sc_x; /* absolute-x */
int sc_y; /* absolute-y */
int sc_z; /* absolute-z */
int sc_w; /* absolute-w */
int sc_refcnt;
u_char sc_dying; /* device is being detached */
struct wsmouse_repeat sc_repeat;
int sc_repeat_button;
callout_t sc_repeat_callout;
unsigned int sc_repeat_delay;
int sc_reverse_scroll;
int sc_horiz_scroll_dist;
int sc_vert_scroll_dist;
};
static int wsmouse_match(device_t, cfdata_t, void *);
static void wsmouse_attach(device_t, device_t, void *);
static int wsmouse_detach(device_t, int);
static int wsmouse_activate(device_t, enum devact);
static int wsmouse_set_params(struct wsmouse_softc *,
struct wsmouse_param *, size_t);
static int wsmouse_get_params(struct wsmouse_softc *,
struct wsmouse_param *, size_t);
static int wsmouse_handle_params(struct wsmouse_softc *,
struct wsmouse_parameters *, bool);
if (act == DVACT_DEACTIVATE)
sc->sc_dying = 1;
return (0);
}
/*
* Detach a mouse. To keep track of users of the softc we keep
* a reference count that's incremented while inside, e.g., read.
* If the mouse is active and the reference count is > 0 (0 is the
* normal state) we post an event and then wait for the process
* that had the reference to wake us up again. Then we blow away the
* vnode and return (which will deallocate the softc).
*/
int
wsmouse_detach(device_t self, int flags)
{
struct wsmouse_softc *sc = device_private(self);
struct wseventvar *evar;
int maj, mn;
int s;
/* If we're open ... */
evar = sc->sc_base.me_evp;
if (evar != NULL && evar->io != NULL) {
s = spltty();
if (--sc->sc_refcnt >= 0) {
struct wscons_event event;
/* Wake everyone by generating a dummy event. */
event.type = 0;
event.value = 0;
if (wsevent_inject(evar, &event, 1) != 0)
wsevent_wakeup(evar);
/* Wait for processes to go away. */
if (tsleep(sc, PZERO, "wsmdet", hz * 60))
printf("wsmouse_detach: %s didn't detach\n",
device_xname(self));
}
splx(s);
}
/* locate the major number */
maj = cdevsw_lookup_major(&wsmouse_cdevsw);
/* Nuke the vnodes for any open instances (calls close). */
mn = device_unit(self);
vdevgone(maj, mn, mn, VCHR);
return (0);
}
void
wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */,
int x, int y, int z, int w, u_int flags)
{
struct wsmouse_softc *sc = device_private(wsmousedev);
struct wseventvar *evar;
int mb, ub, d, nevents;
/* one for each dimension (4) + a bit for each button */
struct wscons_event events[4 + sizeof(d) * 8];
KERNEL_LOCK(1, NULL);
/*
* Discard input if not open.
*/
evar = sc->sc_base.me_evp;
if (evar == NULL || evar->q == NULL)
goto out;
sc->sc_mb = btns;
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X))
sc->sc_dx += x;
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y))
sc->sc_dy += y;
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z))
sc->sc_dz += z;
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W))
sc->sc_dw += w;
/*
* We have at least one event (mouse button, delta-X, or
* delta-Y; possibly all three, and possibly three separate
* button events). Deliver these events until we are out
* of changes or out of room. As events get delivered,
* mark them `unchanged'.
*/
ub = sc->sc_ub;
nevents = 0;
if (sc->sc_repeat_button == -1) {
/* Race condition: a "button up" event came in when
* this function was already called but did not do
* spltty() yet. */
splx(oldspl);
return;
}
KASSERT(sc->sc_repeat_button >= 0);
/* A wrapper around the ioctl() workhorse to make reference counting easy. */
int
wsmousedoioctl(device_t dv, u_long cmd, void *data, int flag,
struct lwp *l)
{
struct wsmouse_softc *sc = device_private(dv);
int error;
int
wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, void *data,
int flag, struct lwp *l)
{
int error;
struct wsmouse_repeat *wr;
if (sc->sc_dying)
return (EIO);
/*
* Try the generic ioctls that the wsmouse interface supports.
*/
switch (cmd) {
case FIONBIO: /* we will remove this someday (soon???) */
return (0);
case FIOASYNC:
if (sc->sc_base.me_evp == NULL)
return (EINVAL);
sc->sc_base.me_evp->async = *(int *)data != 0;
return (0);
case FIOSETOWN:
if (sc->sc_base.me_evp == NULL)
return (EINVAL);
if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid
&& *(int *)data != sc->sc_base.me_evp->io->p_pid)
return (EPERM);
return (0);
case TIOCSPGRP:
if (sc->sc_base.me_evp == NULL)
return (EINVAL);
if (*(int *)data != sc->sc_base.me_evp->io->p_pgid)
return (EPERM);
return (0);
}
/*
* Try the wsmouse specific ioctls.
*/
switch (cmd) {
case WSMOUSEIO_GETREPEAT:
wr = (struct wsmouse_repeat *)data;
memcpy(wr, &sc->sc_repeat, sizeof(sc->sc_repeat));
return 0;
case WSMOUSEIO_SETREPEAT:
if ((flag & FWRITE) == 0)
return EACCES;
/* Stop current repeating and set new data. */
sc->sc_repeat_button = -1;
callout_stop(&sc->sc_repeat_callout);
memcpy(&sc->sc_repeat, wr, sizeof(sc->sc_repeat));
return 0;
case WSMOUSEIO_SETVERSION:
return wsevent_setversion(sc->sc_base.me_evp, *(int *)data);
case WSMOUSEIO_GETPARAMS:
return wsmouse_handle_params(sc,
(struct wsmouse_parameters *)data, false);
case WSMOUSEIO_SETPARAMS:
if ((flag & FWRITE) == 0)
return EACCES;
return wsmouse_handle_params(sc,
(struct wsmouse_parameters *)data, true);
}
/*
* Try the mouse driver for WSMOUSEIO ioctls. It returns -1
* if it didn't recognize the request.
*/
error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
data, flag, l);
return (error); /* may be EPASSTHROUGH */
}
int
wsmousepoll(dev_t dev, int events, struct lwp *l)
{
struct wsmouse_softc *sc =
device_lookup_private(&wsmouse_cd, minor(dev));