Bug Summary

File:dev/wscons/wsmouse.c
Warning:line 1374, column 2
The result of the left shift is undefined because the left operand is negative

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name wsmouse.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/wscons/wsmouse.c
1/* $OpenBSD: wsmouse.c,v 1.70 2022/10/16 18:23:44 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/malloc.h>
107
108#include <dev/wscons/wscons_features.h>
109#include <dev/wscons/wsconsio.h>
110#include <dev/wscons/wsmousevar.h>
111#include <dev/wscons/wseventvar.h>
112#include <dev/wscons/wsmouseinput.h>
113
114#include "wsmux.h"
115#include "wsdisplay.h"
116#include "wskbd.h"
117
118#include <dev/wscons/wsmuxvar.h>
119
120#if defined(WSMUX_DEBUG) && NWSMUX1 > 0
121#define DPRINTF(x) if (wsmuxdebug) printf x
122extern int wsmuxdebug;
123#else
124#define DPRINTF(x)
125#endif
126
127struct wsmouse_softc {
128 struct wsevsrc sc_base;
129
130 const struct wsmouse_accessops *sc_accessops;
131 void *sc_accesscookie;
132
133 struct wsmouseinput sc_input;
134
135 int sc_refcnt;
136 u_char sc_dying; /* device is being detached */
137};
138
139int wsmouse_match(struct device *, void *, void *);
140void wsmouse_attach(struct device *, struct device *, void *);
141int wsmouse_detach(struct device *, int);
142int wsmouse_activate(struct device *, int);
143
144int wsmouse_do_ioctl(struct wsmouse_softc *, u_long, caddr_t,
145 int, struct proc *);
146
147#if NWSMUX1 > 0
148int wsmouse_mux_open(struct wsevsrc *, struct wseventvar *);
149int wsmouse_mux_close(struct wsevsrc *);
150#endif
151
152int wsmousedoioctl(struct device *, u_long, caddr_t, int,
153 struct proc *);
154int wsmousedoopen(struct wsmouse_softc *, struct wseventvar *);
155
156struct cfdriver wsmouse_cd = {
157 NULL((void *)0), "wsmouse", DV_TTY
158};
159
160const struct cfattach wsmouse_ca = {
161 sizeof (struct wsmouse_softc), wsmouse_match, wsmouse_attach,
162 wsmouse_detach, wsmouse_activate
163};
164
165#if NWSMUX1 > 0
166struct wssrcops wsmouse_srcops = {
167 .type = WSMUX_MOUSE1,
168 .dopen = wsmouse_mux_open,
169 .dclose = wsmouse_mux_close,
170 .dioctl = wsmousedoioctl,
171 .ddispioctl = NULL((void *)0),
172 .dsetdisplay = NULL((void *)0),
173};
174#endif
175
176/*
177 * Print function (for parent devices).
178 */
179int
180wsmousedevprint(void *aux, const char *pnp)
181{
182
183 if (pnp)
184 printf("wsmouse at %s", pnp);
185 return (UNCONF1);
186}
187
188int
189wsmouse_match(struct device *parent, void *match, void *aux)
190{
191 return (1);
192}
193
194void
195wsmouse_attach(struct device *parent, struct device *self, void *aux)
196{
197 struct wsmouse_softc *sc = (struct wsmouse_softc *)self;
198 struct wsmousedev_attach_args *ap = aux;
199#if NWSMUX1 > 0
200 int mux, error;
201#endif
202
203 sc->sc_accessops = ap->accessops;
204 sc->sc_accesscookie = ap->accesscookie;
205
206 sc->sc_input.evar = &sc->sc_base.me_evp;
207
208#if NWSMUX1 > 0
209 sc->sc_base.me_ops = &wsmouse_srcops;
210 mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_muxcf_loc[0];
211 if (mux >= 0) {
212 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
213 if (error)
214 printf(" attach error=%d", error);
215 else
216 printf(" mux %d", mux);
217 }
218#else
219#if 0 /* not worth keeping, especially since the default value is not -1... */
220 if (sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_muxcf_loc[0] >= 0)
221 printf(" (mux ignored)");
222#endif
223#endif /* NWSMUX > 0 */
224
225 printf("\n");
226}
227
228int
229wsmouse_activate(struct device *self, int act)
230{
231 struct wsmouse_softc *sc = (struct wsmouse_softc *)self;
232
233 if (act == DVACT_DEACTIVATE1)
234 sc->sc_dying = 1;
235 return (0);
236}
237
238/*
239 * Detach a mouse. To keep track of users of the softc we keep
240 * a reference count that's incremented while inside, e.g., read.
241 * If the mouse is active and the reference count is > 0 (0 is the
242 * normal state) we post an event and then wait for the process
243 * that had the reference to wake us up again. Then we blow away the
244 * vnode and return (which will deallocate the softc).
245 */
246int
247wsmouse_detach(struct device *self, int flags)
248{
249 struct wsmouse_softc *sc = (struct wsmouse_softc *)self;
250 struct wseventvar *evar;
251 int maj, mn;
252 int s;
253
254#if NWSMUX1 > 0
255 /* Tell parent mux we're leaving. */
256 if (sc->sc_base.me_parent != NULL((void *)0)) {
257 DPRINTF(("%s\n", __func__));
258 wsmux_detach_sc(&sc->sc_base);
259 }
260#endif
261
262 /* If we're open ... */
263 evar = sc->sc_base.me_evp;
264 if (evar != NULL((void *)0)) {
265 s = spltty()splraise(0x9);
266 if (--sc->sc_refcnt >= 0) {
267 /* Wake everyone by generating a dummy event. */
268 if (++evar->put >= WSEVENT_QSIZE256)
269 evar->put = 0;
270 WSEVENT_WAKEUP(evar){ selwakeup(&(evar)->sel); if ((evar)->wanted) { (evar
)->wanted = 0; wakeup((caddr_t)(evar)); } if ((evar)->async
) pgsigio(&(evar)->sigio, 23, 0); }
;
271 /* Wait for processes to go away. */
272 if (tsleep_nsec(sc, PZERO22, "wsmdet", SEC_TO_NSEC(60)))
273 printf("wsmouse_detach: %s didn't detach\n",
274 sc->sc_base.me_dv.dv_xname);
275 }
276 splx(s)spllower(s);
277 }
278
279 /* locate the major number */
280 for (maj = 0; maj < nchrdev; maj++)
281 if (cdevsw[maj].d_open == wsmouseopen)
282 break;
283
284 /* Nuke the vnodes for any open instances (calls close). */
285 mn = self->dv_unit;
286 vdevgone(maj, mn, mn, VCHR);
287
288 wsmouse_input_cleanup(&sc->sc_input);
289
290 return (0);
291}
292
293int
294wsmouseopen(dev_t dev, int flags, int mode, struct proc *p)
295{
296 struct wsmouse_softc *sc;
297 struct wseventvar *evar;
298 int error, unit;
299
300 unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
;
301 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
302 (sc = wsmouse_cd.cd_devs[unit]) == NULL((void *)0))
303 return (ENXIO6);
304
305#if NWSMUX1 > 0
306 DPRINTF(("%s: %s mux=%p\n", __func__, sc->sc_base.me_dv.dv_xname,
307 sc->sc_base.me_parent));
308#endif
309
310 if (sc->sc_dying)
311 return (EIO5);
312
313 if ((flags & (FREAD0x0001 | FWRITE0x0002)) == FWRITE0x0002)
314 return (0); /* always allow open for write
315 so ioctl() is possible. */
316
317#if NWSMUX1 > 0
318 if (sc->sc_base.me_parent != NULL((void *)0)) {
319 /* Grab the mouse out of the greedy hands of the mux. */
320 DPRINTF(("%s: detach\n", __func__));
321 wsmux_detach_sc(&sc->sc_base);
322 }
323#endif
324
325 if (sc->sc_base.me_evp != NULL((void *)0))
326 return (EBUSY16);
327
328 evar = &sc->sc_base.me_evar;
329 if (wsevent_init(evar))
330 return (EBUSY16);
331
332 error = wsmousedoopen(sc, evar);
333 if (error)
334 wsevent_fini(evar);
335 return (error);
336}
337
338int
339wsmouseclose(dev_t dev, int flags, int mode, struct proc *p)
340{
341 struct wsmouse_softc *sc =
342 (struct wsmouse_softc *)wsmouse_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
];
343 struct wseventvar *evar = sc->sc_base.me_evp;
344
345 if ((flags & (FREAD0x0001 | FWRITE0x0002)) == FWRITE0x0002)
346 /* Not open for read */
347 return (0);
348
349 sc->sc_base.me_evp = NULL((void *)0);
350 (*sc->sc_accessops->disable)(sc->sc_accesscookie);
351 wsevent_fini(evar);
352
353#if NWSMUX1 > 0
354 if (sc->sc_base.me_parent == NULL((void *)0)) {
355 int mux, error;
356
357 DPRINTF(("%s: attach\n", __func__));
358 mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_muxcf_loc[0];
359 if (mux >= 0) {
360 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
361 if (error)
362 printf("%s: can't attach mux (error=%d)\n",
363 sc->sc_base.me_dv.dv_xname, error);
364 }
365 }
366#endif
367
368 return (0);
369}
370
371int
372wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp)
373{
374 int error;
375
376 /* The device could already be attached to a mux. */
377 if (sc->sc_base.me_evp != NULL((void *)0))
378 return (EBUSY16);
379 sc->sc_base.me_evp = evp;
380
381 wsmouse_input_reset(&sc->sc_input);
382
383 /* enable the device, and punt if that's not possible */
384 error = (*sc->sc_accessops->enable)(sc->sc_accesscookie);
385 if (error)
386 sc->sc_base.me_evp = NULL((void *)0);
387 return (error);
388}
389
390int
391wsmouseread(dev_t dev, struct uio *uio, int flags)
392{
393 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
];
394 int error;
395
396 if (sc->sc_dying)
397 return (EIO5);
398
399#ifdef DIAGNOSTIC1
400 if (sc->sc_base.me_evp == NULL((void *)0)) {
401 printf("wsmouseread: evp == NULL\n");
402 return (EINVAL22);
403 }
404#endif
405
406 sc->sc_refcnt++;
407 error = wsevent_read(sc->sc_base.me_evp, uio, flags);
408 if (--sc->sc_refcnt < 0) {
409 wakeup(sc);
410 error = EIO5;
411 }
412 return (error);
413}
414
415int
416wsmouseioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
417{
418 return (wsmousedoioctl(wsmouse_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
],
419 cmd, data, flag, p));
420}
421
422/* A wrapper around the ioctl() workhorse to make reference counting easy. */
423int
424wsmousedoioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
425 struct proc *p)
426{
427 struct wsmouse_softc *sc = (struct wsmouse_softc *)dv;
428 int error;
429
430 sc->sc_refcnt++;
431 error = wsmouse_do_ioctl(sc, cmd, data, flag, p);
432 if (--sc->sc_refcnt < 0)
433 wakeup(sc);
434 return (error);
435}
436
437int
438wsmouse_param_ioctl(struct wsmouse_softc *sc,
439 u_long cmd, struct wsmouse_param *params, u_int nparams)
440{
441 struct wsmouse_param *buf;
442 int error, s, size;
443
444 if (params == NULL((void *)0) || nparams > WSMOUSECFG_MAX((WSMOUSECFG__FILTERS - WSMOUSECFG_DX_SCALE) + (WSMOUSECFG__TPFILTERS
- WSMOUSECFG_DX_MAX) + (WSMOUSECFG__TPFEATURES - WSMOUSECFG_SOFTBUTTONS
) + (WSMOUSECFG__TPSETUP - WSMOUSECFG_LEFT_EDGE) + (WSMOUSECFG__DEBUG
- WSMOUSECFG_LOG_INPUT))
)
445 return (EINVAL22);
446
447 size = nparams * sizeof(struct wsmouse_param);
448 buf = malloc(size, M_DEVBUF2, M_WAITOK0x0001);
449 if (buf == NULL((void *)0))
450 return (ENOMEM12);
451
452 if ((error = copyin(params, buf, size))) {
453 free(buf, M_DEVBUF2, size);
454 return (error);
455 }
456
457 s = spltty()splraise(0x9);
458 if (cmd == WSMOUSEIO_SETPARAMS((unsigned long)0x80000000 | ((sizeof(struct wsmouse_parameters
) & 0x1fff) << 16) | ((('W')) << 8) | ((40)))
) {
459 if (wsmouse_set_params((struct device *) sc, buf, nparams))
460 error = EINVAL22;
461 } else {
462 if (wsmouse_get_params((struct device *) sc, buf, nparams))
463 error = EINVAL22;
464 else
465 error = copyout(buf, params, size);
466 }
467 splx(s)spllower(s);
468 free(buf, M_DEVBUF2, size);
469 return (error);
470}
471
472int
473wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, caddr_t data, int flag,
474 struct proc *p)
475{
476 struct wseventvar *evar;
477 int error;
478
479 if (sc->sc_dying)
480 return (EIO5);
481
482 /*
483 * Try the generic ioctls that the wsmouse interface supports.
484 */
485
486 switch (cmd) {
487 case FIOASYNC((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((125)))
:
488 case FIOSETOWN((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((124)))
:
489 case TIOCSPGRP((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((118)))
:
490 if ((flag & FWRITE0x0002) == 0)
491 return (EACCES13);
492 }
493
494 switch (cmd) {
495 case FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
: /* we will remove this someday (soon???) */
496 return (0);
497
498 case FIOASYNC((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((125)))
:
499 if (sc->sc_base.me_evp == NULL((void *)0))
500 return (EINVAL22);
501 sc->sc_base.me_evp->async = *(int *)data != 0;
502 return (0);
503
504 case FIOGETOWN((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((123)))
:
505 case TIOCGPGRP((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((119)))
:
506 evar = sc->sc_base.me_evp;
507 if (evar == NULL((void *)0))
508 return (EINVAL22);
509 sigio_getown(&evar->sigio, cmd, data);
510 return (0);
511
512 case FIOSETOWN((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((124)))
:
513 case TIOCSPGRP((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((118)))
:
514 evar = sc->sc_base.me_evp;
515 if (evar == NULL((void *)0))
516 return (EINVAL22);
517 return (sigio_setown(&evar->sigio, cmd, data));
518
519 case WSMOUSEIO_GETPARAMS((unsigned long)0x80000000 | ((sizeof(struct wsmouse_parameters
) & 0x1fff) << 16) | ((('W')) << 8) | ((39)))
:
520 case WSMOUSEIO_SETPARAMS((unsigned long)0x80000000 | ((sizeof(struct wsmouse_parameters
) & 0x1fff) << 16) | ((('W')) << 8) | ((40)))
:
521 return (wsmouse_param_ioctl(sc, cmd,
522 ((struct wsmouse_parameters *) data)->params,
523 ((struct wsmouse_parameters *) data)->nparams));
524 }
525
526 /*
527 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1
528 * if it didn't recognize the request.
529 */
530 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
531 data, flag, p);
532 return (error != -1 ? error : ENOTTY25);
533}
534
535int
536wsmousekqfilter(dev_t dev, struct knote *kn)
537{
538 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
];
539
540 if (sc->sc_base.me_evp == NULL((void *)0))
541 return (ENXIO6);
542 return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
543}
544
545#if NWSMUX1 > 0
546int
547wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp)
548{
549 struct wsmouse_softc *sc = (struct wsmouse_softc *)me;
550
551 return (wsmousedoopen(sc, evp));
552}
553
554int
555wsmouse_mux_close(struct wsevsrc *me)
556{
557 struct wsmouse_softc *sc = (struct wsmouse_softc *)me;
558
559 (*sc->sc_accessops->disable)(sc->sc_accesscookie);
560 sc->sc_base.me_evp = NULL((void *)0);
561
562 return (0);
563}
564
565int
566wsmouse_add_mux(int unit, struct wsmux_softc *muxsc)
567{
568 struct wsmouse_softc *sc;
569
570 if (unit < 0 || unit >= wsmouse_cd.cd_ndevs ||
571 (sc = wsmouse_cd.cd_devs[unit]) == NULL((void *)0))
572 return (ENXIO6);
573
574 if (sc->sc_base.me_parent != NULL((void *)0) || sc->sc_base.me_evp != NULL((void *)0))
575 return (EBUSY16);
576
577 return (wsmux_attach_sc(muxsc, &sc->sc_base));
578}
579#endif /* NWSMUX > 0 */
580
581void
582wsmouse_buttons(struct device *sc, u_int buttons)
583{
584 struct btn_state *btn = &((struct wsmouse_softc *) sc)->sc_input.btn;
585
586 if (btn->sync)
587 /* Restore the old state. */
588 btn->buttons ^= btn->sync;
589
590 btn->sync = btn->buttons ^ buttons;
591 btn->buttons = buttons;
592}
593
594void
595wsmouse_motion(struct device *sc, int dx, int dy, int dz, int dw)
596{
597 struct motion_state *motion =
598 &((struct wsmouse_softc *) sc)->sc_input.motion;
599
600 motion->dx = dx;
601 motion->dy = dy;
602 motion->dz = dz;
603 motion->dw = dw;
604 if (dx || dy || dz || dw)
605 motion->sync |= SYNC_DELTAS(1 << 0);
606}
607
608static inline void
609set_x(struct position *pos, int x, u_int *sync, u_int mask)
610{
611 if (*sync & mask) {
612 if (x == pos->x)
613 return;
614 pos->x -= pos->dx;
615 pos->acc_dx -= pos->dx;
616 }
617 if ((pos->dx = x - pos->x)) {
618 pos->x = x;
619 if ((pos->dx > 0) == (pos->acc_dx > 0))
620 pos->acc_dx += pos->dx;
621 else
622 pos->acc_dx = pos->dx;
623 *sync |= mask;
624 }
625}
626
627static inline void
628set_y(struct position *pos, int y, u_int *sync, u_int mask)
629{
630 if (*sync & mask) {
631 if (y == pos->y)
632 return;
633 pos->y -= pos->dy;
634 pos->acc_dy -= pos->dy;
635 }
636 if ((pos->dy = y - pos->y)) {
637 pos->y = y;
638 if ((pos->dy > 0) == (pos->acc_dy > 0))
639 pos->acc_dy += pos->dy;
640 else
641 pos->acc_dy = pos->dy;
642 *sync |= mask;
643 }
644}
645
646static inline void
647cleardeltas(struct position *pos)
648{
649 pos->dx = pos->acc_dx = 0;
650 pos->dy = pos->acc_dy = 0;
651}
652
653void
654wsmouse_position(struct device *sc, int x, int y)
655{
656 struct motion_state *motion =
657 &((struct wsmouse_softc *) sc)->sc_input.motion;
658
659 set_x(&motion->pos, x, &motion->sync, SYNC_X(1 << 1));
660 set_y(&motion->pos, y, &motion->sync, SYNC_Y(1 << 2));
661}
662
663static inline int
664normalized_pressure(struct wsmouseinput *input, int pressure)
665{
666 int limit = imax(input->touch.min_pressure, 1);
667
668 if (pressure >= limit)
669 return pressure;
670 else
671 return (pressure < 0 ? limit : 0);
672}
673
674void
675wsmouse_touch(struct device *sc, int pressure, int contacts)
676{
677 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
678 struct touch_state *touch = &input->touch;
679
680 pressure = normalized_pressure(input, pressure);
681 contacts = (pressure ? imax(contacts, 1) : 0);
682
683 if (pressure == 0 || pressure != touch->pressure) {
684 /*
685 * pressure == 0: Drivers may report possibly arbitrary
686 * coordinates in this case; touch_update will correct them.
687 */
688 touch->pressure = pressure;
689 touch->sync |= SYNC_PRESSURE(1 << 0);
690 }
691 if (contacts != touch->contacts) {
692 touch->contacts = contacts;
693 touch->sync |= SYNC_CONTACTS(1 << 1);
694 }
695}
696
697void
698wsmouse_mtstate(struct device *sc, int slot, int x, int y, int pressure)
699{
700 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
701 struct mt_state *mt = &input->mt;
702 struct mt_slot *mts;
703 u_int bit;
704
705 if (slot < 0 || slot >= mt->num_slots)
706 return;
707
708 bit = (1 << slot);
709 mt->frame |= bit;
710
711 mts = &mt->slots[slot];
712
713 set_x(&mts->pos, x, mt->sync + MTS_X1, bit);
714 set_y(&mts->pos, y, mt->sync + MTS_Y2, bit);
715
716 /* Is this a new touch? */
717 if ((mt->touches & bit) == (mt->sync[MTS_TOUCH0] & bit))
718 cleardeltas(&mts->pos);
719
720 pressure = normalized_pressure(input, pressure);
721 if (pressure != mts->pressure) {
722 mts->pressure = pressure;
723 mt->sync[MTS_PRESSURE3] |= bit;
724
725 if (pressure) {
726 if ((mt->touches & bit) == 0) {
727 mt->num_touches++;
728 mt->touches |= bit;
729 mt->sync[MTS_TOUCH0] |= bit;
730
731 mt->sync[MTS_X1] |= bit;
732 mt->sync[MTS_Y2] |= bit;
733 }
734 } else if (mt->touches & bit) {
735 mt->num_touches--;
736 mt->touches ^= bit;
737 mt->sync[MTS_TOUCH0] |= bit;
738 mt->ptr_mask &= mt->touches;
739 }
740 }
741}
742
743void
744wsmouse_set(struct device *sc, enum wsmouseval type, int value, int aux)
745{
746 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
747 struct mt_slot *mts;
748
749 if (WSMOUSE_IS_MT_CODE(type)((type) >= WSMOUSE_MT_REL_X && (type) <= WSMOUSE_MT_PRESSURE
)
) {
750 if (aux < 0 || aux >= input->mt.num_slots)
751 return;
752 mts = &input->mt.slots[aux];
753 }
754
755 switch (type) {
756 case WSMOUSE_REL_X:
757 value += input->motion.pos.x; /* fall through */
758 case WSMOUSE_ABS_X:
759 wsmouse_position(sc, value, input->motion.pos.y);
760 return;
761 case WSMOUSE_REL_Y:
762 value += input->motion.pos.y; /* fall through */
763 case WSMOUSE_ABS_Y:
764 wsmouse_position(sc, input->motion.pos.x, value);
765 return;
766 case WSMOUSE_PRESSURE:
767 wsmouse_touch(sc, value, input->touch.contacts);
768 return;
769 case WSMOUSE_CONTACTS:
770 /* Contact counts can be overridden by wsmouse_touch. */
771 if (value != input->touch.contacts) {
772 input->touch.contacts = value;
773 input->touch.sync |= SYNC_CONTACTS(1 << 1);
774 }
775 return;
776 case WSMOUSE_TOUCH_WIDTH:
777 if (value != input->touch.width) {
778 input->touch.width = value;
779 input->touch.sync |= SYNC_TOUCH_WIDTH(1 << 2);
780 }
781 return;
782 case WSMOUSE_MT_REL_X:
783 value += mts->pos.x; /* fall through */
784 case WSMOUSE_MT_ABS_X:
785 wsmouse_mtstate(sc, aux, value, mts->pos.y, mts->pressure);
786 return;
787 case WSMOUSE_MT_REL_Y:
788 value += mts->pos.y; /* fall through */
789 case WSMOUSE_MT_ABS_Y:
790 wsmouse_mtstate(sc, aux, mts->pos.x, value, mts->pressure);
791 return;
792 case WSMOUSE_MT_PRESSURE:
793 wsmouse_mtstate(sc, aux, mts->pos.x, mts->pos.y, value);
794 return;
795 }
796}
797
798/* Make touch and motion state consistent. */
799void
800wsmouse_touch_update(struct wsmouseinput *input)
801{
802 struct motion_state *motion = &input->motion;
803 struct touch_state *touch = &input->touch;
804
805 if (touch->pressure == 0) {
806 /*
807 * There may be zero coordinates, or coordinates of
808 * touches with pressure values below min_pressure.
809 */
810 if (motion->sync & SYNC_POSITION((1 << 1) | (1 << 2))) {
811 /* Restore valid coordinates. */
812 motion->pos.x -= motion->pos.dx;
813 motion->pos.y -= motion->pos.dy;
814 motion->sync &= ~SYNC_POSITION((1 << 1) | (1 << 2));
815 }
816
817 if (touch->prev_contacts == 0)
818 touch->sync &= ~SYNC_PRESSURE(1 << 0);
819
820 }
821
822 if (touch->sync & SYNC_CONTACTS(1 << 1))
823 /* Suppress pointer movement. */
824 cleardeltas(&motion->pos);
825
826 if ((touch->sync & SYNC_PRESSURE(1 << 0)) && touch->min_pressure) {
827 if (touch->pressure >= input->filter.pressure_hi)
828 touch->min_pressure = input->filter.pressure_lo;
829 else if (touch->pressure < input->filter.pressure_lo)
830 touch->min_pressure = input->filter.pressure_hi;
831 }
832}
833
834/* Normalize multitouch state. */
835void
836wsmouse_mt_update(struct wsmouseinput *input)
837{
838 int i;
839
840 /*
841 * The same as above: There may be arbitrary coordinates if
842 * (pressure == 0). Clear the sync flags for touches that have
843 * been released.
844 */
845 if (input->mt.frame & ~input->mt.touches) {
846 for (i = MTS_X1; i < MTS_SIZE4; i++)
847 input->mt.sync[i] &= input->mt.touches;
848 }
849}
850
851/* Return TRUE if a coordinate update may be noise. */
852int
853wsmouse_hysteresis(struct wsmouseinput *input, struct position *pos)
854{
855 return (abs(pos->acc_dx) < input->filter.h.hysteresis
856 && abs(pos->acc_dy) < input->filter.v.hysteresis);
857}
858
859/*
860 * Select the pointer-controlling MT slot.
861 *
862 * Pointer-control is assigned to slots with non-zero motion deltas if
863 * at least one such slot exists. This function doesn't impose any
864 * restrictions on the way drivers use wsmouse_mtstate(), it covers
865 * partial, unordered, and "delta-filtered" input.
866 *
867 * The "cycle" is the set of slots with X/Y updates in previous sync
868 * operations; it will be cleared and rebuilt whenever a slot that is
869 * being updated is already a member. If a cycle ends that doesn't
870 * contain the pointer-controlling slot, a new slot will be selected.
871 */
872void
873wsmouse_ptr_ctrl(struct wsmouseinput *input)
874{
875 struct mt_state *mt = &input->mt;
876 u_int updates;
877 int select, slot;
878
879 mt->prev_ptr = mt->ptr;
880
881 if (mt->num_touches <= 1) {
882 mt->ptr = mt->touches;
883 mt->ptr_cycle = mt->ptr;
884 return;
885 }
886
887 updates = (mt->sync[MTS_X1] | mt->sync[MTS_Y2]) & ~mt->sync[MTS_TOUCH0];
888 FOREACHBIT(updates, slot)for ((slot) = ffs(updates) - 1; (slot) != -1; (slot) = ffs((updates
) & (~1 << (slot))) - 1)
{
889 /*
890 * Touches that just produce noise are no problem if the
891 * frequency of zero deltas is high enough, but there might
892 * be no guarantee for that.
893 */
894 if (wsmouse_hysteresis(input, &mt->slots[slot].pos))
895 updates ^= (1 << slot);
896 }
897
898 /*
899 * If there is no pointer-controlling slot, or if it should be
900 * masked, select a new one.
901 */
902 select = ((mt->ptr & mt->touches & ~mt->ptr_mask) == 0);
903
904 /* Remove slots without coordinate deltas from the cycle. */
905 mt->ptr_cycle &= ~(mt->frame ^ updates);
906
907 if (mt->ptr_cycle & updates) {
908 select |= ((mt->ptr_cycle & mt->ptr) == 0);
909 mt->ptr_cycle = updates;
910 } else {
911 mt->ptr_cycle |= updates;
912 }
913 if (select) {
914 if (mt->ptr_cycle & ~mt->ptr_mask)
915 slot = ffs(mt->ptr_cycle & ~mt->ptr_mask) - 1;
916 else if (mt->touches & ~mt->ptr_mask)
917 slot = ffs(mt->touches & ~mt->ptr_mask) - 1;
918 else
919 slot = ffs(mt->touches) - 1;
920 mt->ptr = (1 << slot);
921 }
922}
923
924/* Derive touch and motion state from MT state. */
925void
926wsmouse_mt_convert(struct device *sc)
927{
928 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
929 struct mt_state *mt = &input->mt;
930 struct mt_slot *mts;
931 int slot, pressure;
932
933 wsmouse_ptr_ctrl(input);
934
935 if (mt->ptr) {
936 slot = ffs(mt->ptr) - 1;
937 mts = &mt->slots[slot];
938 if (mts->pos.x != input->motion.pos.x)
939 input->motion.sync |= SYNC_X(1 << 1);
940 if (mts->pos.y != input->motion.pos.y)
941 input->motion.sync |= SYNC_Y(1 << 2);
942 if (mt->ptr != mt->prev_ptr)
943 /* Suppress pointer movement. */
944 mts->pos.dx = mts->pos.dy = 0;
945 memcpy(&input->motion.pos, &mts->pos, sizeof(struct position))__builtin_memcpy((&input->motion.pos), (&mts->pos
), (sizeof(struct position)))
;
946
947 pressure = mts->pressure;
948 } else {
949 pressure = 0;
950 }
951
952 wsmouse_touch(sc, pressure, mt->num_touches);
953}
954
955void
956wsmouse_evq_put(struct evq_access *evq, int ev_type, int ev_value)
957{
958 struct wscons_event *ev;
959 int space;
960
961 space = evq->evar->get - evq->put;
962 if (space != 1 && space != 1 - WSEVENT_QSIZE256) {
963 ev = &evq->evar->q[evq->put++];
964 evq->put %= WSEVENT_QSIZE256;
965 ev->type = ev_type;
966 ev->value = ev_value;
967 memcpy(&ev->time, &evq->ts, sizeof(struct timespec))__builtin_memcpy((&ev->time), (&evq->ts), (sizeof
(struct timespec)))
;
968 evq->result |= EVQ_RESULT_SUCCESS1;
969 } else {
970 evq->result = EVQ_RESULT_OVERFLOW-1;
971 }
972}
973
974
975void
976wsmouse_btn_sync(struct btn_state *btn, struct evq_access *evq)
977{
978 int button, ev_type;
979 u_int bit, sync;
980
981 for (sync = btn->sync; sync; sync ^= bit) {
982 button = ffs(sync) - 1;
983 bit = (1 << button);
984 ev_type = (btn->buttons & bit) ? BTN_DOWN_EV5 : BTN_UP_EV4;
985 wsmouse_evq_put(evq, ev_type, button);
986 }
987}
988
989/*
990 * Scale with a [*.12] fixed-point factor and a remainder:
991 */
992static inline int
993scale(int val, int factor, int *rmdr)
994{
995 val = val * factor + *rmdr;
996 if (val >= 0) {
997 *rmdr = val & 0xfff;
998 return (val >> 12);
999 } else {
1000 *rmdr = -(-val & 0xfff);
1001 return -(-val >> 12);
1002 }
1003}
1004
1005void
1006wsmouse_motion_sync(struct wsmouseinput *input, struct evq_access *evq)
1007{
1008 struct motion_state *motion = &input->motion;
1009 struct axis_filter *h = &input->filter.h;
1010 struct axis_filter *v = &input->filter.v;
1011 int x, y, dx, dy, dz, dw;
1012
1013 if (motion->sync & SYNC_DELTAS(1 << 0)) {
1014 dx = h->inv ? -motion->dx : motion->dx;
1015 dy = v->inv ? -motion->dy : motion->dy;
1016 if (h->scale)
1017 dx = scale(dx, h->scale, &h->rmdr);
1018 if (v->scale)
1019 dy = scale(dy, v->scale, &v->rmdr);
1020 if (dx)
1021 wsmouse_evq_put(evq, DELTA_X_EV(input)((input)->filter.swapxy ? 7 : 6), dx);
1022 if (dy)
1023 wsmouse_evq_put(evq, DELTA_Y_EV(input)((input)->filter.swapxy ? 6 : 7), dy);
1024 if (motion->dz) {
1025 dz = (input->flags & REVERSE_SCROLLING(1 << 3))
1026 ? -motion->dz : motion->dz;
1027 if (IS_TOUCHPAD(input)((input)->hw.hw_type == WSMOUSEHW_TOUCHPAD || (input)->
hw.hw_type == WSMOUSEHW_CLICKPAD)
)
1028 wsmouse_evq_put(evq, VSCROLL_EV27, dz);
1029 else
1030 wsmouse_evq_put(evq, DELTA_Z_EV10, dz);
1031 }
1032 if (motion->dw) {
1033 dw = (input->flags & REVERSE_SCROLLING(1 << 3))
1034 ? -motion->dw : motion->dw;
1035 if (IS_TOUCHPAD(input)((input)->hw.hw_type == WSMOUSEHW_TOUCHPAD || (input)->
hw.hw_type == WSMOUSEHW_CLICKPAD)
)
1036 wsmouse_evq_put(evq, HSCROLL_EV26, dw);
1037 else
1038 wsmouse_evq_put(evq, DELTA_W_EV16, dw);
1039 }
1040 }
1041 if (motion->sync & SYNC_POSITION((1 << 1) | (1 << 2))) {
1042 if (motion->sync & SYNC_X(1 << 1)) {
1043 x = (h->inv ? h->inv - motion->pos.x : motion->pos.x);
1044 wsmouse_evq_put(evq, ABS_X_EV(input)((input)->filter.swapxy ? 9 : 8), x);
1045 }
1046 if (motion->sync & SYNC_Y(1 << 2)) {
1047 y = (v->inv ? v->inv - motion->pos.y : motion->pos.y);
1048 wsmouse_evq_put(evq, ABS_Y_EV(input)((input)->filter.swapxy ? 8 : 9), y);
1049 }
1050 if (motion->pos.dx == 0 && motion->pos.dy == 0
1051 && (input->flags & TPAD_NATIVE_MODE(1 << 1) ))
1052 /* Suppress pointer motion. */
1053 wsmouse_evq_put(evq, WSCONS_EVENT_TOUCH_RESET25, 0);
1054 }
1055}
1056
1057void
1058wsmouse_touch_sync(struct wsmouseinput *input, struct evq_access *evq)
1059{
1060 struct touch_state *touch = &input->touch;
1061
1062 if (touch->sync & SYNC_PRESSURE(1 << 0))
1063 wsmouse_evq_put(evq, ABS_Z_EV11, touch->pressure);
1064 if (touch->sync & SYNC_CONTACTS(1 << 1))
1065 wsmouse_evq_put(evq, ABS_W_EV17, touch->contacts);
1066 if ((touch->sync & SYNC_TOUCH_WIDTH(1 << 2))
1067 && (input->flags & TPAD_NATIVE_MODE(1 << 1)))
1068 wsmouse_evq_put(evq, WSCONS_EVENT_TOUCH_WIDTH24, touch->width);
1069}
1070
1071void
1072wsmouse_log_input(struct wsmouseinput *input, struct timespec *ts)
1073{
1074 struct motion_state *motion = &input->motion;
1075 int t_sync, mt_sync;
1076
1077 t_sync = (input->touch.sync & SYNC_CONTACTS(1 << 1));
1078 mt_sync = (input->mt.frame && (input->mt.sync[MTS_TOUCH0]
1079 || input->mt.ptr != input->mt.prev_ptr));
1080
1081 if (motion->sync || mt_sync || t_sync || input->btn.sync)
1082 printf("[%s-in][%04d]", DEVNAME(input)((char *) (input) - __builtin_offsetof(struct wsmouse_softc, sc_input
) + __builtin_offsetof(struct device, dv_xname))
, LOGTIME(ts)((int) (((ts)->tv_sec % 10) * 1000 + ((ts)->tv_nsec / 1000000
)))
);
1083 else
1084 return;
1085
1086 if (motion->sync & SYNC_POSITION((1 << 1) | (1 << 2)))
1087 printf(" abs:%d,%d", motion->pos.x, motion->pos.y);
1088 if (motion->sync & SYNC_DELTAS(1 << 0))
1089 printf(" rel:%d,%d,%d,%d", motion->dx, motion->dy,
1090 motion->dz, motion->dw);
1091 if (mt_sync)
1092 printf(" mt:0x%02x:%d", input->mt.touches,
1093 ffs(input->mt.ptr) - 1);
1094 else if (t_sync)
1095 printf(" t:%d", input->touch.contacts);
1096 if (input->btn.sync)
1097 printf(" btn:0x%02x", input->btn.buttons);
1098 printf("\n");
1099}
1100
1101void
1102wsmouse_log_events(struct wsmouseinput *input, struct evq_access *evq)
1103{
1104 struct wscons_event *ev;
1105 int n = evq->evar->put;
1106
1107 if (n != evq->put) {
1108 printf("[%s-ev][%04d]", DEVNAME(input)((char *) (input) - __builtin_offsetof(struct wsmouse_softc, sc_input
) + __builtin_offsetof(struct device, dv_xname))
, LOGTIME(&evq->ts)((int) (((&evq->ts)->tv_sec % 10) * 1000 + ((&evq
->ts)->tv_nsec / 1000000)))
);
1109 while (n != evq->put) {
1110 ev = &evq->evar->q[n++];
1111 n %= WSEVENT_QSIZE256;
1112 printf(" %d:%d", ev->type, ev->value);
1113 }
1114 printf("\n");
1115 }
1116}
1117
1118static inline void
1119clear_sync_flags(struct wsmouseinput *input)
1120{
1121 int i;
1122
1123 input->btn.sync = 0;
1124 input->sbtn.sync = 0;
1125 input->motion.sync = 0;
1126 input->touch.sync = 0;
1127 input->touch.prev_contacts = input->touch.contacts;
1128 if (input->mt.frame) {
1129 input->mt.frame = 0;
1130 for (i = 0; i < MTS_SIZE4; i++)
1131 input->mt.sync[i] = 0;
1132 }
1133}
1134
1135void
1136wsmouse_input_sync(struct device *sc)
1137{
1138 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1139 struct evq_access evq;
1140
1141 evq.evar = *input->evar;
1142 if (evq.evar == NULL((void *)0))
1143 return;
1144 evq.put = evq.evar->put;
1145 evq.result = EVQ_RESULT_NONE0;
1146 getnanotime(&evq.ts);
1147
1148 enqueue_randomness(input->btn.buttons
1149 ^ input->motion.dx ^ input->motion.dy
1150 ^ input->motion.pos.x ^ input->motion.pos.y
1151 ^ input->motion.dz ^ input->motion.dw);
1152
1153 if (input->mt.frame) {
1154 wsmouse_mt_update(input);
1155 wsmouse_mt_convert(sc);
1156 }
1157 if (input->touch.sync)
1158 wsmouse_touch_update(input);
1159
1160 if (input->flags & LOG_INPUT(1 << 19))
1161 wsmouse_log_input(input, &evq.ts);
1162
1163 if (input->flags & TPAD_COMPAT_MODE(1 << 0))
1164 wstpad_compat_convert(input, &evq);
1165
1166 if (input->flags & RESYNC(1 << 16)) {
1167 input->flags &= ~RESYNC(1 << 16);
1168 input->motion.sync &= SYNC_POSITION((1 << 1) | (1 << 2));
1169 }
1170
1171 if (input->btn.sync)
1172 wsmouse_btn_sync(&input->btn, &evq);
1173 if (input->sbtn.sync)
1174 wsmouse_btn_sync(&input->sbtn, &evq);
1175 if (input->motion.sync)
1176 wsmouse_motion_sync(input, &evq);
1177 if (input->touch.sync)
1178 wsmouse_touch_sync(input, &evq);
1179 /* No MT events are generated yet. */
1180
1181 if (evq.result == EVQ_RESULT_SUCCESS1) {
1182 wsmouse_evq_put(&evq, WSCONS_EVENT_SYNC18, 0);
1183 if (evq.result == EVQ_RESULT_SUCCESS1) {
1184 if (input->flags & LOG_EVENTS(1 << 20)) {
1185 wsmouse_log_events(input, &evq);
1186 }
1187 evq.evar->put = evq.put;
1188 WSEVENT_WAKEUP(evq.evar){ selwakeup(&(evq.evar)->sel); if ((evq.evar)->wanted
) { (evq.evar)->wanted = 0; wakeup((caddr_t)(evq.evar)); }
if ((evq.evar)->async) pgsigio(&(evq.evar)->sigio,
23, 0); }
;
1189 }
1190 }
1191
1192 if (evq.result != EVQ_RESULT_OVERFLOW-1)
1193 clear_sync_flags(input);
1194 else
1195 input->flags |= RESYNC(1 << 16);
1196}
1197
1198int
1199wsmouse_id_to_slot(struct device *sc, int id)
1200{
1201 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1202 struct mt_state *mt = &input->mt;
1203 int slot;
1204
1205 if (mt->num_slots == 0)
1206 return (-1);
1207
1208 FOREACHBIT(mt->touches, slot)for ((slot) = ffs(mt->touches) - 1; (slot) != -1; (slot) =
ffs((mt->touches) & (~1 << (slot))) - 1)
{
1209 if (mt->slots[slot].id == id)
1210 return slot;
1211 }
1212 slot = ffs(~(mt->touches | mt->frame)) - 1;
1213 if (slot >= 0 && slot < mt->num_slots) {
1214 mt->frame |= 1 << slot;
1215 mt->slots[slot].id = id;
1216 return (slot);
1217 } else {
1218 return (-1);
1219 }
1220}
1221
1222/*
1223 * Find a minimum-weight matching for an m-by-n matrix.
1224 *
1225 * m must be greater than or equal to n. The size of the buffer must be
1226 * at least 3m + 3n.
1227 *
1228 * On return, the first m elements of the buffer contain the row-to-
1229 * column mappings, i.e., buffer[i] is the column index for row i, or -1
1230 * if there is no assignment for that row (which may happen if n < m).
1231 *
1232 * Wrong results because of overflows will not occur with input values
1233 * in the range of 0 to INT_MAX / 2 inclusive.
1234 *
1235 * The function applies the Dinic-Kronrod algorithm. It is not modern or
1236 * popular, but it seems to be a good choice for small matrices at least.
1237 * The original form of the algorithm is modified as follows: There is no
1238 * initial search for row minima, the initial assignments are in a
1239 * "virtual" column with the index -1 and zero values. This permits inputs
1240 * with n < m, and it simplifies the reassignments.
1241 */
1242void
1243wsmouse_matching(int *matrix, int m, int n, int *buffer)
1244{
1245 int i, j, k, d, e, row, col, delta;
1246 int *p;
1247 int *r2c = buffer; /* row-to-column assignments */
1248 int *red = r2c + m; /* reduced values of the assignments */
1249 int *mc = red + m; /* row-wise minimal elements of cs */
1250 int *cs = mc + m; /* the column set */
1251 int *c2r = cs + n; /* column-to-row assignments in cs */
1252 int *cd = c2r + n; /* column deltas (reduction) */
1253
1254 for (p = r2c; p < red; *p++ = -1) {}
1255 for (; p < mc; *p++ = 0) {}
1256 for (col = 0; col < n; col++) {
1257 delta = INT_MAX0x7fffffff;
1258 for (i = 0, p = matrix + col; i < m; i++, p += n) {
1259 d = *p - red[i];
1260 if (d < delta || (d == delta && r2c[i] < 0)) {
1261 delta = d;
1262 row = i;
1263 }
1264 }
1265 cd[col] = delta;
1266 if (r2c[row] < 0) {
1267 r2c[row] = col;
1268 continue;
1269 }
1270 for (p = mc; p < cs; *p++ = col) {}
1271 for (k = 0; (j = r2c[row]) >= 0;) {
1272 cs[k++] = j;
1273 c2r[j] = row;
1274 mc[row] -= n;
1275 delta = INT_MAX0x7fffffff;
1276 for (i = 0, p = matrix; i < m; i++, p += n)
1277 if (mc[i] >= 0) {
1278 d = p[mc[i]] - cd[mc[i]];
1279 e = p[j] - cd[j];
1280 if (e < d) {
1281 d = e;
1282 mc[i] = j;
1283 }
1284 d -= red[i];
1285 if (d < delta || (d == delta
1286 && r2c[i] < 0)) {
1287 delta = d;
1288 row = i;
1289 }
1290 }
1291 cd[col] += delta;
1292 for (i = 0; i < k; i++) {
1293 cd[cs[i]] += delta;
1294 red[c2r[cs[i]]] -= delta;
1295 }
1296 }
1297 for (j = mc[row]; (r2c[row] = j) != col;) {
1298 row = c2r[j];
1299 j = mc[row] + n;
1300 }
1301 }
1302}
1303
1304/*
1305 * Assign slot numbers to the points in the pt array, and update all slots by
1306 * calling wsmouse_mtstate internally. The slot numbers are passed to the
1307 * caller in the pt->slot fields.
1308 *
1309 * The slot assignment pairs the points with points of the previous frame in
1310 * such a way that the sum of the squared distances is minimal. Using
1311 * squares instead of simple distances favours assignments with more uniform
1312 * distances, and it is faster.
1313 */
1314void
1315wsmouse_mtframe(struct device *sc, struct mtpoint *pt, int size)
1316{
1317 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1318 struct mt_state *mt = &input->mt;
1319 int i, j, m, n, dx, dy, slot, maxdist;
1320 int *p, *r2c, *c2r;
1321 u_int touches;
1322
1323 if (mt->num_slots == 0 || mt->matrix == NULL((void *)0))
1
Assuming field 'num_slots' is not equal to 0
2
Assuming field 'matrix' is not equal to NULL
3
Taking false branch
1324 return;
1325
1326 size = imax(0, imin(size, mt->num_slots));
1327 p = mt->matrix;
1328 touches = mt->touches;
1329 if (mt->num_touches >= size) {
4
Assuming 'size' is <= field 'num_touches'
5
Taking true branch
1330 FOREACHBIT(touches, slot)for ((slot) = ffs(touches) - 1; (slot) != -1; (slot) = ffs((touches
) & (~1 << (slot))) - 1)
6
Assuming the condition is false
7
Loop condition is false. Execution continues on line 1336
1331 for (i = 0; i < size; i++) {
1332 dx = pt[i].x - mt->slots[slot].pos.x;
1333 dy = pt[i].y - mt->slots[slot].pos.y;
1334 *p++ = dx * dx + dy * dy;
1335 }
1336 m = mt->num_touches;
1337 n = size;
1338 } else {
1339 for (i = 0; i < size; i++)
1340 FOREACHBIT(touches, slot)for ((slot) = ffs(touches) - 1; (slot) != -1; (slot) = ffs((touches
) & (~1 << (slot))) - 1)
{
1341 dx = pt[i].x - mt->slots[slot].pos.x;
1342 dy = pt[i].y - mt->slots[slot].pos.y;
1343 *p++ = dx * dx + dy * dy;
1344 }
1345 m = size;
1346 n = mt->num_touches;
1347 }
1348 wsmouse_matching(mt->matrix, m, n, p);
1349
1350 r2c = p;
1351 c2r = p + m;
1352 maxdist = input->filter.tracking_maxdist;
1353 maxdist = (maxdist ? maxdist * maxdist : INT_MAX0x7fffffff);
8
Assuming 'maxdist' is not equal to 0
9
'?' condition is true
1354 for (i = 0, p = mt->matrix; i < m; i++, p += n)
10
Loop condition is true. Entering loop body
1355 if ((j = r2c[i]) >= 0) {
11
Taking true branch
1356 if (p[j] <= maxdist)
12
Assuming the condition is false
13
Taking false branch
1357 c2r[j] = i;
1358 else
1359 c2r[j] = r2c[i] = -1;
1360 }
1361
1362 p = (n
14.1
'n' is equal to 'size'
== size ? c2r : r2c);
14
Loop condition is false. Execution continues on line 1362
15
'?' condition is true
1363 for (i = 0; i < size; i++)
16
Loop condition is true. Entering loop body
1364 if (*p++ < 0) {
17
Taking true branch
1365 slot = ffs(~(mt->touches | mt->frame)) - 1;
1366 if (slot < 0 || slot >= mt->num_slots)
18
Assuming 'slot' is < 0
1367 break;
1368 wsmouse_mtstate(sc, slot,
1369 pt[i].x, pt[i].y, pt[i].pressure);
1370 pt[i].slot = slot;
1371 }
1372
1373 p = (n
18.1
'n' is equal to 'size'
== size ? r2c : c2r);
19
'?' condition is true
1374 FOREACHBIT(touches, slot)for ((slot) = ffs(touches) - 1; (slot) != -1; (slot) = ffs((touches
) & (~1 << (slot))) - 1)
20
Assuming the condition is true
21
Loop condition is true. Entering loop body
23
The result of the left shift is undefined because the left operand is negative
1375 if ((i = *p++) >= 0) {
22
Taking false branch
1376 wsmouse_mtstate(sc, slot,
1377 pt[i].x, pt[i].y, pt[i].pressure);
1378 pt[i].slot = slot;
1379 } else {
1380 wsmouse_mtstate(sc, slot, 0, 0, 0);
1381 }
1382}
1383
1384static inline void
1385free_mt_slots(struct wsmouseinput *input)
1386{
1387 int n, size;
1388
1389 if ((n = input->mt.num_slots)) {
1390 size = n * sizeof(struct mt_slot);
1391 if (input->flags & MT_TRACKING(1 << 2))
1392 size += MATRIX_SIZE(n)(((n) + 6) * (n) * sizeof(int));
1393 input->mt.num_slots = 0;
1394 free(input->mt.slots, M_DEVBUF2, size);
1395 input->mt.slots = NULL((void *)0);
1396 input->mt.matrix = NULL((void *)0);
1397 }
1398}
1399
1400/* Allocate the MT slots and, if necessary, the buffers for MT tracking. */
1401int
1402wsmouse_mt_init(struct device *sc, int num_slots, int tracking)
1403{
1404 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1405 int n, size;
1406
1407 if (num_slots == input->mt.num_slots
1408 && (!tracking == ((input->flags & MT_TRACKING(1 << 2)) == 0)))
1409 return (0);
1410
1411 free_mt_slots(input);
1412
1413 if (tracking)
1414 input->flags |= MT_TRACKING(1 << 2);
1415 else
1416 input->flags &= ~MT_TRACKING(1 << 2);
1417 n = imin(imax(num_slots, 0), WSMOUSE_MT_SLOTS_MAX10);
1418 if (n) {
1419 size = n * sizeof(struct mt_slot);
1420 if (input->flags & MT_TRACKING(1 << 2))
1421 size += MATRIX_SIZE(n)(((n) + 6) * (n) * sizeof(int));
1422 input->mt.slots = malloc(size, M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
1423 if (input->mt.slots != NULL((void *)0)) {
1424 if (input->flags & MT_TRACKING(1 << 2))
1425 input->mt.matrix = (int *)
1426 (input->mt.slots + n);
1427 input->mt.num_slots = n;
1428 return (0);
1429 }
1430 }
1431 return (-1);
1432}
1433
1434int
1435wsmouse_get_params(struct device *sc,
1436 struct wsmouse_param *params, u_int nparams)
1437{
1438 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1439 int i, key, error = 0;
1440
1441 for (i = 0; i < nparams; i++) {
1442 key = params[i].key;
1443 switch (key) {
1444 case WSMOUSECFG_DX_SCALE:
1445 params[i].value = input->filter.h.scale;
1446 break;
1447 case WSMOUSECFG_DY_SCALE:
1448 params[i].value = input->filter.v.scale;
1449 break;
1450 case WSMOUSECFG_PRESSURE_LO:
1451 params[i].value = input->filter.pressure_lo;
1452 break;
1453 case WSMOUSECFG_PRESSURE_HI:
1454 params[i].value = input->filter.pressure_hi;
1455 break;
1456 case WSMOUSECFG_TRKMAXDIST:
1457 params[i].value = input->filter.tracking_maxdist;
1458 break;
1459 case WSMOUSECFG_SWAPXY:
1460 params[i].value = input->filter.swapxy;
1461 break;
1462 case WSMOUSECFG_X_INV:
1463 params[i].value = input->filter.h.inv;
1464 break;
1465 case WSMOUSECFG_Y_INV:
1466 params[i].value = input->filter.v.inv;
1467 break;
1468 case WSMOUSECFG_REVERSE_SCROLLING:
1469 params[i].value = !!(input->flags & REVERSE_SCROLLING(1 << 3));
1470 break;
1471 case WSMOUSECFG_DX_MAX:
1472 params[i].value = input->filter.h.dmax;
1473 break;
1474 case WSMOUSECFG_DY_MAX:
1475 params[i].value = input->filter.v.dmax;
1476 break;
1477 case WSMOUSECFG_X_HYSTERESIS:
1478 params[i].value = input->filter.h.hysteresis;
1479 break;
1480 case WSMOUSECFG_Y_HYSTERESIS:
1481 params[i].value = input->filter.v.hysteresis;
1482 break;
1483 case WSMOUSECFG_DECELERATION:
1484 params[i].value = input->filter.dclr;
1485 break;
1486 case WSMOUSECFG_STRONG_HYSTERESIS:
1487 params[i].value = 0; /* The feature has been removed. */
1488 break;
1489 case WSMOUSECFG_SMOOTHING:
1490 params[i].value =
1491 input->filter.mode & SMOOTHING_MASK7;
1492 break;
1493 case WSMOUSECFG_LOG_INPUT:
1494 params[i].value = !!(input->flags & LOG_INPUT(1 << 19));
1495 break;
1496 case WSMOUSECFG_LOG_EVENTS:
1497 params[i].value = !!(input->flags & LOG_EVENTS(1 << 20));
1498 break;
1499 default:
1500 error = wstpad_get_param(input, key, &params[i].value);
1501 if (error != 0)
1502 return (error);
1503 break;
1504 }
1505 }
1506
1507 return (0);
1508}
1509
1510int
1511wsmouse_set_params(struct device *sc,
1512 const struct wsmouse_param *params, u_int nparams)
1513{
1514 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1515 int i, val, key, needreset = 0, error = 0;
1516
1517 for (i = 0; i < nparams; i++) {
1518 key = params[i].key;
1519 val = params[i].value;
1520 switch (params[i].key) {
1521 case WSMOUSECFG_PRESSURE_LO:
1522 input->filter.pressure_lo = val;
1523 if (val > input->filter.pressure_hi)
1524 input->filter.pressure_hi = val;
1525 input->touch.min_pressure = input->filter.pressure_hi;
1526 break;
1527 case WSMOUSECFG_PRESSURE_HI:
1528 input->filter.pressure_hi = val;
1529 if (val < input->filter.pressure_lo)
1530 input->filter.pressure_lo = val;
1531 input->touch.min_pressure = val;
1532 break;
1533 case WSMOUSECFG_X_HYSTERESIS:
1534 input->filter.h.hysteresis = val;
1535 break;
1536 case WSMOUSECFG_Y_HYSTERESIS:
1537 input->filter.v.hysteresis = val;
1538 break;
1539 case WSMOUSECFG_DECELERATION:
1540 input->filter.dclr = val;
1541 wstpad_init_deceleration(input);
1542 break;
1543 case WSMOUSECFG_DX_SCALE:
1544 input->filter.h.scale = val;
1545 break;
1546 case WSMOUSECFG_DY_SCALE:
1547 input->filter.v.scale = val;
1548 break;
1549 case WSMOUSECFG_TRKMAXDIST:
1550 input->filter.tracking_maxdist = val;
1551 break;
1552 case WSMOUSECFG_SWAPXY:
1553 input->filter.swapxy = val;
1554 break;
1555 case WSMOUSECFG_X_INV:
1556 input->filter.h.inv = val;
1557 break;
1558 case WSMOUSECFG_Y_INV:
1559 input->filter.v.inv = val;
1560 break;
1561 case WSMOUSECFG_REVERSE_SCROLLING:
1562 if (val)
1563 input->flags |= REVERSE_SCROLLING(1 << 3);
1564 else
1565 input->flags &= ~REVERSE_SCROLLING(1 << 3);
1566 break;
1567 case WSMOUSECFG_DX_MAX:
1568 input->filter.h.dmax = val;
1569 break;
1570 case WSMOUSECFG_DY_MAX:
1571 input->filter.v.dmax = val;
1572 break;
1573 case WSMOUSECFG_SMOOTHING:
1574 input->filter.mode &= ~SMOOTHING_MASK7;
1575 input->filter.mode |= (val & SMOOTHING_MASK7);
1576 break;
1577 case WSMOUSECFG_LOG_INPUT:
1578 if (val)
1579 input->flags |= LOG_INPUT(1 << 19);
1580 else
1581 input->flags &= ~LOG_INPUT(1 << 19);
1582 break;
1583 case WSMOUSECFG_LOG_EVENTS:
1584 if (val)
1585 input->flags |= LOG_EVENTS(1 << 20);
1586 else
1587 input->flags &= ~LOG_EVENTS(1 << 20);
1588 break;
1589 default:
1590 needreset = 1;
1591 error = wstpad_set_param(input, key, val);
1592 if (error != 0)
1593 return (error);
1594 break;
1595 }
1596 }
1597
1598 /* Reset soft-states if touchpad parameters changed */
1599 if (needreset) {
1600 wstpad_reset(input);
1601 return (wstpad_configure(input));
1602 }
1603
1604 return (0);
1605}
1606
1607int
1608wsmouse_set_mode(struct device *sc, int mode)
1609{
1610 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1611
1612 if (mode == WSMOUSE_COMPAT0) {
1613 input->flags &= ~TPAD_NATIVE_MODE(1 << 1);
1614 input->flags |= TPAD_COMPAT_MODE(1 << 0);
1615 return (0);
1616 } else if (mode == WSMOUSE_NATIVE1) {
1617 input->flags &= ~TPAD_COMPAT_MODE(1 << 0);
1618 input->flags |= TPAD_NATIVE_MODE(1 << 1);
1619 return (0);
1620 }
1621 return (-1);
1622}
1623
1624struct wsmousehw *wsmouse_get_hw(struct device *sc)
1625{
1626 return &((struct wsmouse_softc *) sc)->sc_input.hw;
1627}
1628
1629/*
1630 * Create a default configuration based on the hardware infos in the 'hw'
1631 * fields. The 'params' argument is optional, hardware drivers can use it
1632 * to modify the generic defaults. Up to now this function is only useful
1633 * for touchpads.
1634 */
1635int
1636wsmouse_configure(struct device *sc,
1637 struct wsmouse_param *params, u_int nparams)
1638{
1639 struct wsmouseinput *input = &((struct wsmouse_softc *) sc)->sc_input;
1640 int error;
1641
1642 if (!(input->flags & CONFIGURED(1 << 18))) {
1643 if (input->hw.x_max && input->hw.y_max) {
1644 if (input->hw.flags & WSMOUSEHW_LR_DOWN(1 << 0)) {
1645 input->filter.v.inv =
1646 input->hw.y_max + input->hw.y_min;
1647 }
1648 }
1649 input->filter.ratio = 1 << 12;
1650 if (input->hw.h_res > 0 && input->hw.v_res > 0) {
1651 input->filter.ratio *= input->hw.h_res;
1652 input->filter.ratio /= input->hw.v_res;
1653 }
1654 if (wsmouse_mt_init(sc, input->hw.mt_slots,
1655 (input->hw.flags & WSMOUSEHW_MT_TRACKING(1 << 1)))) {
1656 printf("wsmouse_configure: "
1657 "MT initialization failed.\n");
1658 return (-1);
1659 }
1660 if (IS_TOUCHPAD(input)((input)->hw.hw_type == WSMOUSEHW_TOUCHPAD || (input)->
hw.hw_type == WSMOUSEHW_CLICKPAD)
&& wstpad_configure(input)) {
1661 printf("wstpad_configure: "
1662 "Initialization failed.\n");
1663 return (-1);
1664 }
1665 input->flags |= CONFIGURED(1 << 18);
1666 if (params != NULL((void *)0)) {
1667 if ((error = wsmouse_set_params(sc, params, nparams)))
1668 return (error);
1669 }
1670 }
1671 if (IS_TOUCHPAD(input)((input)->hw.hw_type == WSMOUSEHW_TOUCHPAD || (input)->
hw.hw_type == WSMOUSEHW_CLICKPAD)
)
1672 wsmouse_set_mode(sc, WSMOUSE_COMPAT0);
1673
1674 return (0);
1675}
1676
1677
1678void
1679wsmouse_input_reset(struct wsmouseinput *input)
1680{
1681 int num_slots, *matrix;
1682 struct mt_slot *slots;
1683
1684 memset(&input->btn, 0, sizeof(struct btn_state))__builtin_memset((&input->btn), (0), (sizeof(struct btn_state
)))
;
1685 memset(&input->motion, 0, sizeof(struct motion_state))__builtin_memset((&input->motion), (0), (sizeof(struct
motion_state)))
;
1686 memset(&input->touch, 0, sizeof(struct touch_state))__builtin_memset((&input->touch), (0), (sizeof(struct touch_state
)))
;
1687 input->touch.min_pressure = input->filter.pressure_hi;
1688 if ((num_slots = input->mt.num_slots)) {
1689 slots = input->mt.slots;
1690 matrix = input->mt.matrix;
1691 memset(&input->mt, 0, sizeof(struct mt_state))__builtin_memset((&input->mt), (0), (sizeof(struct mt_state
)))
;
1692 memset(slots, 0, num_slots * sizeof(struct mt_slot))__builtin_memset((slots), (0), (num_slots * sizeof(struct mt_slot
)))
;
1693 input->mt.num_slots = num_slots;
1694 input->mt.slots = slots;
1695 input->mt.matrix = matrix;
1696 }
1697 if (input->tp != NULL((void *)0))
1698 wstpad_reset(input);
1699}
1700
1701void
1702wsmouse_input_cleanup(struct wsmouseinput *input)
1703{
1704 if (input->tp != NULL((void *)0))
1705 wstpad_cleanup(input);
1706
1707 free_mt_slots(input);
1708}