Bug Summary

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