Bug Summary

File:dev/wscons/wstpad.c
Warning:line 942, 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 wstpad.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/wstpad.c
1/* $OpenBSD: wstpad.c,v 1.30 2021/03/24 18:28:24 bru Exp $ */
2
3/*
4 * Copyright (c) 2015, 2016 Ulf Brosziewski
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * touchpad input processing
21 */
22
23#include <sys/param.h>
24#include <sys/kernel.h>
25#include <sys/malloc.h>
26#include <sys/proc.h>
27#include <sys/systm.h>
28#include <sys/signalvar.h>
29#include <sys/timeout.h>
30
31#include <dev/wscons/wsconsio.h>
32#include <dev/wscons/wsmousevar.h>
33#include <dev/wscons/wseventvar.h>
34#include <dev/wscons/wsmouseinput.h>
35
36#define BTNMASK(n)((n) > 0 && (n) <= 32 ? 1 << ((n) - 1) : 0
)
((n) > 0 && (n) <= 32 ? 1 << ((n) - 1) : 0)
37
38#define LEFTBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
BTNMASK(1)((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
39#define MIDDLEBTN((2) > 0 && (2) <= 32 ? 1 << ((2) - 1) : 0
)
BTNMASK(2)((2) > 0 && (2) <= 32 ? 1 << ((2) - 1) : 0
)
40#define RIGHTBTN((3) > 0 && (3) <= 32 ? 1 << ((3) - 1) : 0
)
BTNMASK(3)((3) > 0 && (3) <= 32 ? 1 << ((3) - 1) : 0
)
41
42#define PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
LEFTBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
43
44#define PRIMARYBTN_CLICKED(tp)((tp)->btns_sync & ((1) > 0 && (1) <= 32
? 1 << ((1) - 1) : 0) & (tp)->btns)
((tp)->btns_sync & PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
& (tp)->btns)
45#define PRIMARYBTN_RELEASED(tp)((tp)->btns_sync & ((1) > 0 && (1) <= 32
? 1 << ((1) - 1) : 0) & ~(tp)->btns)
((tp)->btns_sync & PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
& ~(tp)->btns)
46
47#define IS_MT(tp)((tp)->features & (1 << 31)) ((tp)->features & WSTPAD_MT(1 << 31))
48#define DISABLE(tp)((tp)->features & (1 << 7)) ((tp)->features & WSTPAD_DISABLE(1 << 7))
49
50/*
51 * Ratios to the height or width of the touchpad surface, in
52 * [*.12] fixed-point format:
53 */
54#define V_EDGE_RATIO_DEFAULT205 205
55#define B_EDGE_RATIO_DEFAULT410 410
56#define T_EDGE_RATIO_DEFAULT512 512
57#define CENTER_RATIO_DEFAULT512 512
58
59#define TAP_MAXTIME_DEFAULT180 180
60#define TAP_CLICKTIME_DEFAULT180 180
61#define TAP_LOCKTIME_DEFAULT0 0
62#define TAP_BTNMAP_SIZE3 3
63
64#define CLICKDELAY_MS20 20
65#define FREEZE_MS100 100
66#define MATCHINTERVAL_MS45 45
67#define STOPINTERVAL_MS55 55
68
69#define MAG_LOW(10 << 12) (10 << 12)
70#define MAG_MEDIUM(18 << 12) (18 << 12)
71
72enum tpad_handlers {
73 SOFTBUTTON_HDLR,
74 TOPBUTTON_HDLR,
75 TAP_HDLR,
76 F2SCROLL_HDLR,
77 EDGESCROLL_HDLR,
78 CLICK_HDLR,
79};
80
81enum tap_state {
82 TAP_DETECT,
83 TAP_IGNORE,
84 TAP_LIFTED,
85 TAP_2ND_TOUCH,
86 TAP_LOCKED,
87 TAP_NTH_TOUCH,
88};
89
90enum tpad_cmd {
91 CLEAR_MOTION_DELTAS,
92 SOFTBUTTON_DOWN,
93 SOFTBUTTON_UP,
94 TAPBUTTON_DOWN,
95 TAPBUTTON_UP,
96 TAPBUTTON_DOUBLECLK,
97 VSCROLL,
98 HSCROLL,
99};
100
101/*
102 * tpad_touch.flags:
103 */
104#define L_EDGE(1 << 0) (1 << 0)
105#define R_EDGE(1 << 1) (1 << 1)
106#define T_EDGE(1 << 2) (1 << 2)
107#define B_EDGE(1 << 3) (1 << 3)
108#define THUMB(1 << 4) (1 << 4)
109
110#define EDGES((1 << 0) | (1 << 1) | (1 << 2) | (1 <<
3))
(L_EDGE(1 << 0) | R_EDGE(1 << 1) | T_EDGE(1 << 2) | B_EDGE(1 << 3))
111
112/*
113 * A touch is "centered" if it does not start and remain at the top
114 * edge or one of the vertical edges. Two-finger scrolling and tapping
115 * require that at least one touch is centered.
116 */
117#define CENTERED(t)(((t)->flags & ((1 << 0) | (1 << 1) | (1 <<
2))) == 0)
(((t)->flags & (L_EDGE(1 << 0) | R_EDGE(1 << 1) | T_EDGE(1 << 2))) == 0)
118
119enum touchstates {
120 TOUCH_NONE,
121 TOUCH_BEGIN,
122 TOUCH_UPDATE,
123 TOUCH_END,
124};
125
126struct tpad_touch {
127 u_int flags;
128 enum touchstates state;
129 int x;
130 int y;
131 int dir;
132 struct timespec start;
133 struct timespec match;
134 struct position *pos;
135 struct {
136 int x;
137 int y;
138 struct timespec time;
139 } orig;
140};
141
142/*
143 * wstpad.features
144 */
145#define WSTPAD_SOFTBUTTONS(1 << 0) (1 << 0)
146#define WSTPAD_SOFTMBTN(1 << 1) (1 << 1)
147#define WSTPAD_TOPBUTTONS(1 << 2) (1 << 2)
148#define WSTPAD_TWOFINGERSCROLL(1 << 3) (1 << 3)
149#define WSTPAD_EDGESCROLL(1 << 4) (1 << 4)
150#define WSTPAD_HORIZSCROLL(1 << 5) (1 << 5)
151#define WSTPAD_SWAPSIDES(1 << 6) (1 << 6)
152#define WSTPAD_DISABLE(1 << 7) (1 << 7)
153
154#define WSTPAD_MT(1 << 31) (1 << 31)
155
156
157struct wstpad {
158 u_int features;
159 u_int handlers;
160
161 /*
162 * t always points into the tpad_touches array, which has at
163 * least one element. If there is more than one, t selects
164 * the pointer-controlling touch.
165 */
166 struct tpad_touch *t;
167 struct tpad_touch *tpad_touches;
168
169 u_int mtcycle;
170 u_int ignore;
171
172 int contacts;
173 int prev_contacts;
174 u_int btns;
175 u_int btns_sync;
176 int ratio;
177
178 struct timespec time;
179
180 u_int freeze;
181 struct timespec freeze_ts;
182
183 /* edge coordinates */
184 struct {
185 int left;
186 int right;
187 int top;
188 int bottom;
189 int center;
190 int center_left;
191 int center_right;
192 int low;
193 } edge;
194
195 struct {
196 /* ratios to the surface width or height */
197 int left_edge;
198 int right_edge;
199 int top_edge;
200 int bottom_edge;
201 int center_width;
202 /* two-finger contacts */
203 int f2pressure;
204 int f2width;
205 } params;
206
207 /* handler state and configuration: */
208
209 u_int softbutton;
210 u_int sbtnswap;
211
212 struct {
213 enum tap_state state;
214 int contacts;
215 int centered;
216 u_int button;
217 int maxdist;
218 struct timeout to;
219 /* parameters: */
220 struct timespec maxtime;
221 int clicktime;
222 int locktime;
223 u_int btnmap[TAP_BTNMAP_SIZE3];
224 } tap;
225
226 struct {
227 int dz;
228 int dw;
229 int hdist;
230 int vdist;
231 int mag;
232 } scroll;
233};
234
235static const struct timespec match_interval =
236 { .tv_sec = 0, .tv_nsec = MATCHINTERVAL_MS45 * 1000000 };
237
238static const struct timespec stop_interval =
239 { .tv_sec = 0, .tv_nsec = STOPINTERVAL_MS55 * 1000000 };
240
241/*
242 * Coordinates in the wstpad struct are "normalized" device coordinates,
243 * the orientation is left-to-right and upward.
244 */
245static inline int
246normalize_abs(struct axis_filter *filter, int val)
247{
248 return (filter->inv ? filter->inv - val : val);
249}
250
251static inline int
252normalize_rel(struct axis_filter *filter, int val)
253{
254 return (filter->inv ? -val : val);
255}
256
257/*
258 * Directions of motion are represented by numbers in the range 0 - 11,
259 * corresponding to clockwise counted circle sectors:
260 *
261 * 11 | 0
262 * 10 | 1
263 * 9 | 2
264 * -------+-------
265 * 8 | 3
266 * 7 | 4
267 * 6 | 5
268 *
269 */
270/* Tangent constants in [*.12] fixed-point format: */
271#define TAN_DEG_607094 7094
272#define TAN_DEG_302365 2365
273
274#define NORTH(d)((d) == 0 || (d) == 11) ((d) == 0 || (d) == 11)
275#define SOUTH(d)((d) == 5 || (d) == 6) ((d) == 5 || (d) == 6)
276#define EAST(d)((d) == 2 || (d) == 3) ((d) == 2 || (d) == 3)
277#define WEST(d)((d) == 8 || (d) == 9) ((d) == 8 || (d) == 9)
278
279static inline int
280direction(int dx, int dy, int ratio)
281{
282 int rdy, dir = -1;
283
284 if (dx || dy) {
285 rdy = abs(dy) * ratio;
286 if (abs(dx) * TAN_DEG_607094 < rdy)
287 dir = 0;
288 else if (abs(dx) * TAN_DEG_302365 < rdy)
289 dir = 1;
290 else
291 dir = 2;
292 if ((dx < 0) != (dy < 0))
293 dir = 5 - dir;
294 if (dx < 0)
295 dir += 6;
296 }
297 return dir;
298}
299
300static inline int
301dircmp(int dir1, int dir2)
302{
303 int diff = abs(dir1 - dir2);
304 return (diff <= 6 ? diff : 12 - diff);
305}
306
307/*
308 * Update direction and timespec attributes for a touch. They are used to
309 * determine whether it is moving - or resting - stably.
310 *
311 * The callers pass touches from the current frame and the touches that are
312 * no longer present in the update cycle to this function. Even though this
313 * ensures that pairs of zero deltas do not result from stale coordinates,
314 * zero deltas do not reset the state immediately. A short time span - the
315 * "stop interval" - must pass before the state is cleared, which is
316 * necessary because some touchpads report intermediate stops when a touch
317 * is moving very slowly.
318 */
319void
320wstpad_set_direction(struct wstpad *tp, struct tpad_touch *t, int dx, int dy)
321{
322 int dir;
323 struct timespec ts;
324
325 if (t->state != TOUCH_UPDATE) {
326 t->dir = -1;
327 memcpy(&t->start, &tp->time, sizeof(struct timespec))__builtin_memcpy((&t->start), (&tp->time), (sizeof
(struct timespec)))
;
328 return;
329 }
330
331 dir = direction(dx, dy, tp->ratio);
332 if (dir >= 0) {
333 if (t->dir < 0 || dircmp(dir, t->dir) > 1) {
334 memcpy(&t->start, &tp->time, sizeof(struct timespec))__builtin_memcpy((&t->start), (&tp->time), (sizeof
(struct timespec)))
;
335 }
336 t->dir = dir;
337 memcpy(&t->match, &tp->time, sizeof(struct timespec))__builtin_memcpy((&t->match), (&tp->time), (sizeof
(struct timespec)))
;
338 } else if (t->dir >= 0) {
339 timespecsub(&tp->time, &t->match, &ts)do { (&ts)->tv_sec = (&tp->time)->tv_sec - (
&t->match)->tv_sec; (&ts)->tv_nsec = (&tp
->time)->tv_nsec - (&t->match)->tv_nsec; if (
(&ts)->tv_nsec < 0) { (&ts)->tv_sec--; (&
ts)->tv_nsec += 1000000000L; } } while (0)
;
340 if (timespeccmp(&ts, &stop_interval, >=)(((&ts)->tv_sec == (&stop_interval)->tv_sec) ? (
(&ts)->tv_nsec >= (&stop_interval)->tv_nsec)
: ((&ts)->tv_sec >= (&stop_interval)->tv_sec
))
) {
341 t->dir = -1;
342 memcpy(&t->start, &t->match, sizeof(struct timespec))__builtin_memcpy((&t->start), (&t->match), (sizeof
(struct timespec)))
;
343 }
344 }
345}
346
347/*
348 * Make a rough, but quick estimation of the speed of a touch. Its
349 * distance to the previous position is scaled by factors derived
350 * from the average update rate and the deceleration parameter
351 * (filter.dclr). The unit of the result is:
352 * (filter.dclr / 100) device units per millisecond
353 *
354 * Magnitudes are returned in [*.12] fixed-point format. For purposes
355 * of filtering, they are divided into medium and high speeds
356 * (> MAG_MEDIUM), low speeds, and very low speeds (< MAG_LOW).
357 *
358 * The scale factors are not affected if deceleration is turned off.
359 */
360static inline int
361magnitude(struct wsmouseinput *input, int dx, int dy)
362{
363 int h, v;
364
365 h = abs(dx) * input->filter.h.mag_scale;
366 v = abs(dy) * input->filter.v.mag_scale;
367 /* Return an "alpha-max-plus-beta-min" approximation: */
368 return (h >= v ? h + 3 * v / 8 : v + 3 * h / 8);
369}
370
371/*
372 * Treat a touch as stable if it is moving at a medium or high speed,
373 * if it is moving continuously, or if it has stopped for a certain
374 * time span.
375 */
376int
377wstpad_is_stable(struct wsmouseinput *input, struct tpad_touch *t)
378{
379 struct timespec ts;
380
381 if (t->dir >= 0) {
382 if (magnitude(input, t->pos->dx, t->pos->dy) > MAG_MEDIUM(18 << 12))
383 return (1);
384 timespecsub(&t->match, &t->start, &ts)do { (&ts)->tv_sec = (&t->match)->tv_sec - (
&t->start)->tv_sec; (&ts)->tv_nsec = (&t
->match)->tv_nsec - (&t->start)->tv_nsec; if (
(&ts)->tv_nsec < 0) { (&ts)->tv_sec--; (&
ts)->tv_nsec += 1000000000L; } } while (0)
;
385 } else {
386 timespecsub(&input->tp->time, &t->start, &ts)do { (&ts)->tv_sec = (&input->tp->time)->
tv_sec - (&t->start)->tv_sec; (&ts)->tv_nsec
= (&input->tp->time)->tv_nsec - (&t->start
)->tv_nsec; if ((&ts)->tv_nsec < 0) { (&ts)->
tv_sec--; (&ts)->tv_nsec += 1000000000L; } } while (0)
;
387 }
388
389 return (timespeccmp(&ts, &match_interval, >=)(((&ts)->tv_sec == (&match_interval)->tv_sec) ?
((&ts)->tv_nsec >= (&match_interval)->tv_nsec
) : ((&ts)->tv_sec >= (&match_interval)->tv_sec
))
);
390}
391
392/*
393 * If a touch starts in an edge area, pointer movement will be
394 * suppressed as long as it stays in that area.
395 */
396static inline u_int
397edge_flags(struct wstpad *tp, int x, int y)
398{
399 u_int flags = 0;
400
401 if (x < tp->edge.left)
402 flags |= L_EDGE(1 << 0);
403 else if (x >= tp->edge.right)
404 flags |= R_EDGE(1 << 1);
405 if (y < tp->edge.bottom)
406 flags |= B_EDGE(1 << 3);
407 else if (y >= tp->edge.top)
408 flags |= T_EDGE(1 << 2);
409
410 return (flags);
411}
412
413static inline struct tpad_touch *
414get_2nd_touch(struct wsmouseinput *input)
415{
416 struct wstpad *tp = input->tp;
417 int slot;
418
419 if (IS_MT(tp)((tp)->features & (1 << 31))) {
420 slot = ffs(input->mt.touches & ~(input->mt.ptr | tp->ignore));
421 if (slot)
422 return &tp->tpad_touches[--slot];
423 }
424 return NULL((void *)0);
425}
426
427/* Suppress pointer motion for a short period of time. */
428static inline void
429set_freeze_ts(struct wstpad *tp, int sec, int ms)
430{
431 tp->freeze_ts.tv_sec = sec;
432 tp->freeze_ts.tv_nsec = ms * 1000000;
433 timespecadd(&tp->time, &tp->freeze_ts, &tp->freeze_ts)do { (&tp->freeze_ts)->tv_sec = (&tp->time)->
tv_sec + (&tp->freeze_ts)->tv_sec; (&tp->freeze_ts
)->tv_nsec = (&tp->time)->tv_nsec + (&tp->
freeze_ts)->tv_nsec; if ((&tp->freeze_ts)->tv_nsec
>= 1000000000L) { (&tp->freeze_ts)->tv_sec++; (
&tp->freeze_ts)->tv_nsec -= 1000000000L; } } while (
0)
;
434}
435
436
437/* Return TRUE if two-finger- or edge-scrolling would be valid. */
438int
439wstpad_scroll_coords(struct wsmouseinput *input, int *dx, int *dy)
440{
441 struct wstpad *tp = input->tp;
442
443 if (tp->contacts != tp->prev_contacts || tp->btns || tp->btns_sync) {
444 tp->scroll.dz = 0;
445 tp->scroll.dw = 0;
446 return (0);
447 }
448 if ((input->motion.sync & SYNC_POSITION((1 << 1) | (1 << 2))) == 0)
449 return (0);
450 /*
451 * Try to exclude accidental scroll events by checking whether the
452 * pointer-controlling touch is stable. The check, which may cause
453 * a short delay, is only applied initially, a touch that stops and
454 * resumes scrolling is not affected.
455 */
456 if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t)) {
457 *dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
458 *dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
459 return (*dx || *dy);
460 }
461
462 return (0);
463}
464
465void
466wstpad_scroll(struct wstpad *tp, int dx, int dy, int mag, u_int *cmds)
467{
468 int dz, dw, n = 1;
469
470 /*
471 * The function applies strong deceleration, but only to input with
472 * very low speeds. A higher threshold might make applications
473 * without support for precision scrolling appear unresponsive.
474 */
475 mag = tp->scroll.mag = imin(MAG_MEDIUM(18 << 12),
476 (mag + 3 * tp->scroll.mag) / 4);
477 if (mag < MAG_LOW(10 << 12))
478 n = (MAG_LOW(10 << 12) - mag) / 4096 + 1;
479
480 if (dy && tp->scroll.vdist) {
481 if (tp->scroll.dw) {
482 /*
483 * Before switching the axis, wstpad_scroll_coords()
484 * should check again whether the movement is stable.
485 */
486 tp->scroll.dw = 0;
487 return;
488 }
489 dz = -dy * 4096 / (tp->scroll.vdist * n);
490 if (tp->scroll.dz) {
491 if ((dy < 0) != (tp->scroll.dz > 0))
492 tp->scroll.dz = -tp->scroll.dz;
493 dz = (dz + 3 * tp->scroll.dz) / 4;
494 }
495 if (dz) {
496 tp->scroll.dz = dz;
497 *cmds |= 1 << VSCROLL;
498 }
499
500 } else if (dx && tp->scroll.hdist) {
501 if (tp->scroll.dz) {
502 tp->scroll.dz = 0;
503 return;
504 }
505 dw = dx * 4096 / (tp->scroll.hdist * n);
506 if (tp->scroll.dw) {
507 if ((dx > 0) != (tp->scroll.dw > 0))
508 tp->scroll.dw = -tp->scroll.dw;
509 dw = (dw + 3 * tp->scroll.dw) / 4;
510 }
511 if (dw) {
512 tp->scroll.dw = dw;
513 *cmds |= 1 << HSCROLL;
514 }
515 }
516}
517
518void
519wstpad_f2scroll(struct wsmouseinput *input, u_int *cmds)
520{
521 struct wstpad *tp = input->tp;
522 struct tpad_touch *t2;
523 int dir, dx, dy, centered;
524
525 if (tp->ignore == 0) {
526 if (tp->contacts != 2)
527 return;
528 } else if (tp->contacts != 3 || (tp->ignore == input->mt.ptr)) {
529 return;
530 }
531
532 if (!wstpad_scroll_coords(input, &dx, &dy))
533 return;
534
535 dir = tp->t->dir;
536 if (!(NORTH(dir)((dir) == 0 || (dir) == 11) || SOUTH(dir)((dir) == 5 || (dir) == 6)))
537 dy = 0;
538 if (!(EAST(dir)((dir) == 2 || (dir) == 3) || WEST(dir)((dir) == 8 || (dir) == 9)))
539 dx = 0;
540
541 if (dx || dy) {
542 centered = CENTERED(tp->t)(((tp->t)->flags & ((1 << 0) | (1 << 1)
| (1 << 2))) == 0)
;
543 if (IS_MT(tp)((tp)->features & (1 << 31))) {
544 t2 = get_2nd_touch(input);
545 if (t2 == NULL((void *)0))
546 return;
547 dir = t2->dir;
548 if ((dy > 0 && !NORTH(dir)((dir) == 0 || (dir) == 11)) || (dy < 0 && !SOUTH(dir)((dir) == 5 || (dir) == 6)))
549 return;
550 if ((dx > 0 && !EAST(dir)((dir) == 2 || (dir) == 3)) || (dx < 0 && !WEST(dir)((dir) == 8 || (dir) == 9)))
551 return;
552 if (!wstpad_is_stable(input, t2) &&
553 !(tp->scroll.dz || tp->scroll.dw))
554 return;
555 centered |= CENTERED(t2)(((t2)->flags & ((1 << 0) | (1 << 1) | (1 <<
2))) == 0)
;
556 }
557 if (centered) {
558 wstpad_scroll(tp, dx, dy,
559 magnitude(input, dx, dy), cmds);
560 set_freeze_ts(tp, 0, FREEZE_MS100);
561 }
562 }
563}
564
565void
566wstpad_edgescroll(struct wsmouseinput *input, u_int *cmds)
567{
568 struct wstpad *tp = input->tp;
569 struct tpad_touch *t = tp->t;
570 u_int v_edge, b_edge;
571 int dx, dy;
572
573 if (!wstpad_scroll_coords(input, &dx, &dy) || tp->contacts != 1)
574 return;
575
576 v_edge = (tp->features & WSTPAD_SWAPSIDES(1 << 6)) ? L_EDGE(1 << 0) : R_EDGE(1 << 1);
577 b_edge = (tp->features & WSTPAD_HORIZSCROLL(1 << 5)) ? B_EDGE(1 << 3) : 0;
578
579 if ((t->flags & v_edge) == 0)
580 dy = 0;
581 if ((t->flags & b_edge) == 0)
582 dx = 0;
583
584 if (dx || dy)
585 wstpad_scroll(tp, dx, dy, magnitude(input, dx, dy), cmds);
586}
587
588static inline u_int
589sbtn(struct wstpad *tp, int x, int y)
590{
591 if (y >= tp->edge.bottom)
592 return (0);
593 if ((tp->features & WSTPAD_SOFTMBTN(1 << 1))
594 && x >= tp->edge.center_left
595 && x < tp->edge.center_right)
596 return (MIDDLEBTN((2) > 0 && (2) <= 32 ? 1 << ((2) - 1) : 0
)
);
597 return ((x < tp->edge.center ? LEFTBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
: RIGHTBTN((3) > 0 && (3) <= 32 ? 1 << ((3) - 1) : 0
)
) ^ tp->sbtnswap);
598}
599
600static inline u_int
601top_sbtn(struct wstpad *tp, int x, int y)
602{
603 if (y < tp->edge.top)
604 return (0);
605 if (x < tp->edge.center_left)
606 return (LEFTBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
^ tp->sbtnswap);
607 return (x > tp->edge.center_right
608 ? (RIGHTBTN((3) > 0 && (3) <= 32 ? 1 << ((3) - 1) : 0
)
^ tp->sbtnswap) : MIDDLEBTN((2) > 0 && (2) <= 32 ? 1 << ((2) - 1) : 0
)
);
609}
610
611u_int
612wstpad_get_sbtn(struct wsmouseinput *input, int top)
613{
614 struct wstpad *tp = input->tp;
615 struct tpad_touch *t = tp->t;
616 u_int btn;
617
618 btn = 0;
619 if (tp->contacts) {
620 btn = top ? top_sbtn(tp, t->x, t->y) : sbtn(tp, t->x, t->y);
621 /*
622 * If there is no middle-button area, but contacts in both
623 * halves of the edge zone, generate a middle-button event:
624 */
625 if (btn && IS_MT(tp)((tp)->features & (1 << 31)) && tp->contacts == 2
626 && !top && !(tp->features & WSTPAD_SOFTMBTN(1 << 1))) {
627 if ((t = get_2nd_touch(input)) != NULL((void *)0))
628 btn |= sbtn(tp, t->x, t->y);
629 if (btn == (LEFTBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
| RIGHTBTN((3) > 0 && (3) <= 32 ? 1 << ((3) - 1) : 0
)
))
630 btn = MIDDLEBTN((2) > 0 && (2) <= 32 ? 1 << ((2) - 1) : 0
)
;
631 }
632 }
633 return (btn != PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
? btn : 0);
634}
635
636void
637wstpad_softbuttons(struct wsmouseinput *input, u_int *cmds, int hdlr)
638{
639 struct wstpad *tp = input->tp;
640 int top = (hdlr == TOPBUTTON_HDLR);
641
642 if (tp->softbutton && PRIMARYBTN_RELEASED(tp)((tp)->btns_sync & ((1) > 0 && (1) <= 32
? 1 << ((1) - 1) : 0) & ~(tp)->btns)
) {
643 *cmds |= 1 << SOFTBUTTON_UP;
644 return;
645 }
646
647 if (tp->softbutton == 0 && PRIMARYBTN_CLICKED(tp)((tp)->btns_sync & ((1) > 0 && (1) <= 32
? 1 << ((1) - 1) : 0) & (tp)->btns)
) {
648 tp->softbutton = wstpad_get_sbtn(input, top);
649 if (tp->softbutton)
650 *cmds |= 1 << SOFTBUTTON_DOWN;
651 }
652}
653
654int
655wstpad_is_tap(struct wstpad *tp, struct tpad_touch *t)
656{
657 struct timespec ts;
658
659 timespecsub(&tp->time, &t->orig.time, &ts)do { (&ts)->tv_sec = (&tp->time)->tv_sec - (
&t->orig.time)->tv_sec; (&ts)->tv_nsec = (&
tp->time)->tv_nsec - (&t->orig.time)->tv_nsec
; if ((&ts)->tv_nsec < 0) { (&ts)->tv_sec--;
(&ts)->tv_nsec += 1000000000L; } } while (0)
;
660 return (timespeccmp(&ts, &tp->tap.maxtime, <)(((&ts)->tv_sec == (&tp->tap.maxtime)->tv_sec
) ? ((&ts)->tv_nsec < (&tp->tap.maxtime)->
tv_nsec) : ((&ts)->tv_sec < (&tp->tap.maxtime
)->tv_sec))
);
661}
662
663/*
664 * At least one MT touch must remain close to its origin and end
665 * in the main area. The same conditions apply to one-finger taps
666 * on single-touch devices.
667 */
668void
669wstpad_tap_filter(struct wstpad *tp, struct tpad_touch *t)
670{
671 int dx, dy, dist = 0;
672
673 if (IS_MT(tp)((tp)->features & (1 << 31)) || tp->tap.contacts == 1) {
674 dx = abs(t->x - t->orig.x) << 12;
675 dy = abs(t->y - t->orig.y) * tp->ratio;
676 dist = (dx >= dy ? dx + 3 * dy / 8 : dy + 3 * dx / 8);
677 }
678 tp->tap.centered = (CENTERED(t)(((t)->flags & ((1 << 0) | (1 << 1) | (1 <<
2))) == 0)
&& dist <= (tp->tap.maxdist << 12));
679}
680
681
682/*
683 * Return the oldest touch in the TOUCH_END state, or NULL.
684 */
685struct tpad_touch *
686wstpad_tap_touch(struct wsmouseinput *input)
687{
688 struct wstpad *tp = input->tp;
689 struct tpad_touch *s, *t = NULL((void *)0);
690 u_int lifted;
691 int slot;
692
693 if (IS_MT(tp)((tp)->features & (1 << 31))) {
694 lifted = (input->mt.sync[MTS_TOUCH0] & ~input->mt.touches);
695 FOREACHBIT(lifted, slot)for ((slot) = ffs(lifted) - 1; (slot) != -1; (slot) = ffs((lifted
) & (~1 << (slot))) - 1)
{
696 s = &tp->tpad_touches[slot];
697 if (tp->tap.state == TAP_DETECT && !tp->tap.centered)
698 wstpad_tap_filter(tp, s);
699 if (t == NULL((void *)0) || timespeccmp(&t->orig.time,(((&t->orig.time)->tv_sec == (&s->orig.time)
->tv_sec) ? ((&t->orig.time)->tv_nsec > (&
s->orig.time)->tv_nsec) : ((&t->orig.time)->tv_sec
> (&s->orig.time)->tv_sec))
700 &s->orig.time, >)(((&t->orig.time)->tv_sec == (&s->orig.time)
->tv_sec) ? ((&t->orig.time)->tv_nsec > (&
s->orig.time)->tv_nsec) : ((&t->orig.time)->tv_sec
> (&s->orig.time)->tv_sec))
)
701 t = s;
702 }
703 } else {
704 if (tp->t->state == TOUCH_END) {
705 t = tp->t;
706 if (tp->tap.state == TAP_DETECT && !tp->tap.centered)
707 wstpad_tap_filter(tp, t);
708 }
709 }
710
711 return (t);
712}
713
714/*
715 * If each contact in a sequence of contacts that overlap in time
716 * is a tap, a button event may be generated when the number of
717 * contacts drops to zero, or to one if there is a masked touch.
718 */
719static inline int
720tap_finished(struct wstpad *tp, int nmasked)
721{
722 return (tp->contacts == nmasked
723 && (nmasked == 0 || !wstpad_is_tap(tp, tp->t)));
724}
725
726static inline u_int
727tap_btn(struct wstpad *tp, int nmasked)
728{
729 int n = tp->tap.contacts - nmasked;
730
731 return (n <= TAP_BTNMAP_SIZE3 ? tp->tap.btnmap[n - 1] : 0);
732}
733
734/*
735 * This handler supports one-, two-, and three-finger-taps, which
736 * are mapped to left-button, right-button and middle-button events,
737 * respectively; moreover, it supports tap-and-drag operations with
738 * "locked drags", which are finished by a timeout or a tap-to-end
739 * gesture.
740 */
741void
742wstpad_tap(struct wsmouseinput *input, u_int *cmds)
743{
744 struct wstpad *tp = input->tp;
745 struct tpad_touch *t;
746 int nmasked, err = 0;
747
748 if (tp->btns) {
749 /*
750 * Don't process tapping while hardware buttons are being
751 * pressed. If the handler is not in its initial state,
752 * release the "tap button".
753 */
754 if (tp->tap.state > TAP_IGNORE) {
755 timeout_del(&tp->tap.to);
756 *cmds |= 1 << TAPBUTTON_UP;
757 }
758 /*
759 * It might be possible to produce a click within the tap
760 * timeout; ignore the current touch.
761 */
762 tp->tap.state = TAP_IGNORE;
763 tp->tap.contacts = 0;
764 tp->tap.centered = 0;
765 }
766
767 /*
768 * If a touch from the bottom area is masked, reduce the
769 * contact counts and ignore it.
770 */
771 nmasked = (input->mt.ptr_mask ? 1 : 0);
772
773 /*
774 * Only touches in the TOUCH_END state are relevant here.
775 * t is NULL if no touch has been lifted.
776 */
777 t = wstpad_tap_touch(input);
778
779 switch (tp->tap.state) {
780 case TAP_DETECT:
781 if (tp->contacts > tp->tap.contacts)
782 tp->tap.contacts = tp->contacts;
783
784 if (t) {
785 if (wstpad_is_tap(tp, t)) {
786 if (tap_finished(tp, nmasked)) {
787 if (tp->tap.centered) {
788 tp->tap.state = TAP_LIFTED;
789 tp->tap.button =
790 tap_btn(tp, nmasked);
791 }
792 tp->tap.contacts = 0;
793 tp->tap.centered = 0;
794 }
795 } else {
796 if (tp->contacts > nmasked)
797 tp->tap.state = TAP_IGNORE;
798 tp->tap.contacts = 0;
799 tp->tap.centered = 0;
800 }
801 if (tp->tap.state == TAP_LIFTED) {
802 if (tp->tap.button != 0) {
803 *cmds |= 1 << TAPBUTTON_DOWN;
804 err = !timeout_add_msec(&tp->tap.to,
805 tp->tap.clicktime);
806 } else {
807 tp->tap.state = TAP_DETECT;
808 }
809 }
810 }
811 break;
812
813 case TAP_IGNORE:
814 if (tp->contacts == nmasked)
815 tp->tap.state = TAP_DETECT;
816 break;
817 case TAP_LIFTED:
818 if (tp->contacts > nmasked) {
819 timeout_del(&tp->tap.to);
820 if (tp->tap.button == LEFTBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
) {
821 tp->tap.state = TAP_2ND_TOUCH;
822 } else {
823 *cmds |= 1 << TAPBUTTON_UP;
824 tp->tap.state = TAP_DETECT;
825 }
826 }
827 break;
828 case TAP_2ND_TOUCH:
829 if (t) {
830 if (wstpad_is_tap(tp, t)) {
831 *cmds |= 1 << TAPBUTTON_DOUBLECLK;
832 tp->tap.state = TAP_LIFTED;
833 err = !timeout_add_msec(&tp->tap.to,
834 CLICKDELAY_MS20);
835 } else if (tp->contacts == nmasked) {
836 if (tp->tap.locktime == 0) {
837 *cmds |= 1 << TAPBUTTON_UP;
838 tp->tap.state = TAP_DETECT;
839 } else {
840 tp->tap.state = TAP_LOCKED;
841 err = !timeout_add_msec(&tp->tap.to,
842 tp->tap.locktime);
843 }
844 }
845 } else if (tp->contacts != nmasked + 1) {
846 *cmds |= 1 << TAPBUTTON_UP;
847 tp->tap.state = TAP_DETECT;
848 }
849 break;
850 case TAP_LOCKED:
851 if (tp->contacts > nmasked) {
852 timeout_del(&tp->tap.to);
853 tp->tap.state = TAP_NTH_TOUCH;
854 }
855 break;
856 case TAP_NTH_TOUCH:
857 if (t) {
858 if (wstpad_is_tap(tp, t)) {
859 /* "tap-to-end" */
860 *cmds |= 1 << TAPBUTTON_UP;
861 tp->tap.state = TAP_DETECT;
862 } else if (tp->contacts == nmasked) {
863 tp->tap.state = TAP_LOCKED;
864 err = !timeout_add_msec(&tp->tap.to,
865 tp->tap.locktime);
866 }
867 } else if (tp->contacts != nmasked + 1) {
868 *cmds |= 1 << TAPBUTTON_UP;
869 tp->tap.state = TAP_DETECT;
870 }
871 break;
872 }
873
874 if (err) { /* Did timeout_add fail? */
875 if (tp->tap.state == TAP_LIFTED)
876 *cmds &= ~(1 << TAPBUTTON_DOWN);
877 else
878 *cmds |= 1 << TAPBUTTON_UP;
879
880 tp->tap.state = TAP_DETECT;
881 }
882}
883
884void
885wstpad_tap_timeout(void *p)
886{
887 struct wsmouseinput *input = p;
888 struct wstpad *tp = input->tp;
889 struct evq_access evq;
890 u_int btn;
891 int s;
892
893 s = spltty()splraise(0x9);
894 evq.evar = *input->evar;
895 if (evq.evar != NULL((void *)0) && tp != NULL((void *)0) &&
896 (tp->tap.state == TAP_LIFTED || tp->tap.state == TAP_LOCKED)) {
897 tp->tap.state = TAP_DETECT;
898 input->sbtn.buttons &= ~tp->tap.button;
899 btn = ffs(tp->tap.button) - 1;
900 evq.put = evq.evar->put;
901 evq.result = EVQ_RESULT_NONE0;
902 getnanotime(&evq.ts);
903 wsmouse_evq_put(&evq, BTN_UP_EV4, btn);
904 wsmouse_evq_put(&evq, SYNC_EV18, 0);
905 if (evq.result == EVQ_RESULT_SUCCESS1) {
906 if (input->flags & LOG_EVENTS(1 << 20)) {
907 wsmouse_log_events(input, &evq);
908 }
909 evq.evar->put = evq.put;
910 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); }
;
911 } else {
912 input->sbtn.sync |= tp->tap.button;
913 }
914 }
915 splx(s)spllower(s);
916}
917
918/*
919 * Suppress accidental pointer movements after a click on a clickpad.
920 */
921void
922wstpad_click(struct wsmouseinput *input)
923{
924 struct wstpad *tp = input->tp;
925
926 if (tp->contacts == 1 &&
927 (PRIMARYBTN_CLICKED(tp)((tp)->btns_sync & ((1) > 0 && (1) <= 32
? 1 << ((1) - 1) : 0) & (tp)->btns)
|| PRIMARYBTN_RELEASED(tp)((tp)->btns_sync & ((1) > 0 && (1) <= 32
? 1 << ((1) - 1) : 0) & ~(tp)->btns)
))
928 set_freeze_ts(tp, 0, FREEZE_MS100);
929}
930
931/*
932 * Translate the "command" bits into the sync-state of wsmouse, or into
933 * wscons events.
934 */
935void
936wstpad_cmds(struct wsmouseinput *input, struct evq_access *evq, u_int cmds)
937{
938 struct wstpad *tp = input->tp;
939 u_int btn, sbtns_dn = 0, sbtns_up = 0;
940 int n;
941
942 FOREACHBIT(cmds, n)for ((n) = ffs(cmds) - 1; (n) != -1; (n) = ffs((cmds) & (
~1 << (n))) - 1)
{
14
Assuming the condition is true
15
Loop condition is true. Entering loop body
18
The result of the left shift is undefined because the left operand is negative
943 switch (n) {
16
Control jumps to 'case TAPBUTTON_UP:' at line 961
944 case CLEAR_MOTION_DELTAS:
945 input->motion.dx = input->motion.dy = 0;
946 if (input->motion.dz == 0 && input->motion.dw == 0)
947 input->motion.sync &= ~SYNC_DELTAS(1 << 0);
948 continue;
949 case SOFTBUTTON_DOWN:
950 input->btn.sync &= ~PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
;
951 sbtns_dn |= tp->softbutton;
952 continue;
953 case SOFTBUTTON_UP:
954 input->btn.sync &= ~PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
;
955 sbtns_up |= tp->softbutton;
956 tp->softbutton = 0;
957 continue;
958 case TAPBUTTON_DOWN:
959 sbtns_dn |= tp->tap.button;
960 continue;
961 case TAPBUTTON_UP:
962 sbtns_up |= tp->tap.button;
963 continue;
17
Execution continues on line 942
964 case TAPBUTTON_DOUBLECLK:
965 /*
966 * We cannot add the final BTN_UP event here, a
967 * delay is required. This is the reason why the
968 * tap handler returns from the 2ND_TOUCH state
969 * into the LIFTED state with a short timeout
970 * (CLICKDELAY_MS).
971 */
972 btn = ffs(PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
) - 1;
973 wsmouse_evq_put(evq, BTN_UP_EV4, btn);
974 wsmouse_evq_put(evq, SYNC_EV18, 0);
975 wsmouse_evq_put(evq, BTN_DOWN_EV5, btn);
976 continue;
977 case HSCROLL:
978 input->motion.dw = tp->scroll.dw;
979 input->motion.sync |= SYNC_DELTAS(1 << 0);
980 continue;
981 case VSCROLL:
982 input->motion.dz = tp->scroll.dz;
983 input->motion.sync |= SYNC_DELTAS(1 << 0);
984 continue;
985 default:
986 printf("[wstpad] invalid cmd %d\n", n);
987 break;
988 }
989 }
990 if (sbtns_dn || sbtns_up) {
991 input->sbtn.buttons |= sbtns_dn;
992 input->sbtn.buttons &= ~sbtns_up;
993 input->sbtn.sync |= (sbtns_dn | sbtns_up);
994 }
995}
996
997
998/*
999 * Set the state of touches that have ended. TOUCH_END is a transitional
1000 * state and will be changed to TOUCH_NONE before process_input() returns.
1001 */
1002static inline void
1003clear_touchstates(struct wsmouseinput *input, enum touchstates state)
1004{
1005 u_int touches;
1006 int slot;
1007
1008 touches = input->mt.sync[MTS_TOUCH0] & ~input->mt.touches;
1009 FOREACHBIT(touches, slot)for ((slot) = ffs(touches) - 1; (slot) != -1; (slot) = ffs((touches
) & (~1 << (slot))) - 1)
1010 input->tp->tpad_touches[slot].state = state;
1011}
1012
1013void
1014wstpad_mt_inputs(struct wsmouseinput *input)
1015{
1016 struct wstpad *tp = input->tp;
1017 struct tpad_touch *t;
1018 int slot, dx, dy;
1019 u_int touches, inactive;
1020
1021 /* TOUCH_BEGIN */
1022 touches = input->mt.touches & input->mt.sync[MTS_TOUCH0];
1023 FOREACHBIT(touches, slot)for ((slot) = ffs(touches) - 1; (slot) != -1; (slot) = ffs((touches
) & (~1 << (slot))) - 1)
{
1024 t = &tp->tpad_touches[slot];
1025 t->state = TOUCH_BEGIN;
1026 t->x = normalize_abs(&input->filter.h, t->pos->x);
1027 t->y = normalize_abs(&input->filter.v, t->pos->y);
1028 t->orig.x = t->x;
1029 t->orig.y = t->y;
1030 memcpy(&t->orig.time, &tp->time, sizeof(struct timespec))__builtin_memcpy((&t->orig.time), (&tp->time), (
sizeof(struct timespec)))
;
1031 t->flags = edge_flags(tp, t->x, t->y);
1032 wstpad_set_direction(tp, t, 0, 0);
1033 }
1034
1035 /* TOUCH_UPDATE */
1036 touches = input->mt.touches & input->mt.frame;
1037 if (touches & tp->mtcycle) {
1038 /*
1039 * Slot data may be synchronized separately, in any order,
1040 * or not at all if there is no delta. Identify the touches
1041 * without deltas.
1042 */
1043 inactive = input->mt.touches & ~tp->mtcycle;
1044 tp->mtcycle = touches;
1045 } else {
1046 inactive = 0;
1047 tp->mtcycle |= touches;
1048 }
1049 touches = input->mt.touches & ~input->mt.sync[MTS_TOUCH0];
1050 FOREACHBIT(touches, slot)for ((slot) = ffs(touches) - 1; (slot) != -1; (slot) = ffs((touches
) & (~1 << (slot))) - 1)
{
1051 t = &tp->tpad_touches[slot];
1052 t->state = TOUCH_UPDATE;
1053 if ((1 << slot) & input->mt.frame) {
1054 dx = normalize_abs(&input->filter.h, t->pos->x) - t->x;
1055 t->x += dx;
1056 dy = normalize_abs(&input->filter.v, t->pos->y) - t->y;
1057 t->y += dy;
1058 t->flags &= (~EDGES((1 << 0) | (1 << 1) | (1 << 2) | (1 <<
3))
| edge_flags(tp, t->x, t->y));
1059 if (wsmouse_hysteresis(input, t->pos))
1060 dx = dy = 0;
1061 wstpad_set_direction(tp, t, dx, dy);
1062 } else if ((1 << slot) & inactive) {
1063 wstpad_set_direction(tp, t, 0, 0);
1064 }
1065 }
1066
1067 clear_touchstates(input, TOUCH_END);
1068}
1069
1070/*
1071 * Identify "thumb" contacts in the bottom area. The identification
1072 * has three stages:
1073 * 1. If exactly one of two or more touches is in the bottom area, it
1074 * is masked, which means it does not receive pointer control as long
1075 * as there are alternatives. Once set, the mask will only be cleared
1076 * when the touch is released.
1077 * Tap detection ignores a masked touch if it does not participate in
1078 * a tap gesture.
1079 * 2. If the pointer-controlling touch is moving stably while a masked
1080 * touch in the bottom area is resting, or only moving minimally, the
1081 * pointer mask is copied to tp->ignore. In this stage, the masked
1082 * touch does not block pointer movement, and it is ignored by
1083 * wstpad_f2scroll().
1084 * Decisions are made more or less immediately, there may be errors
1085 * in edge cases. If a fast or long upward movement is detected,
1086 * tp->ignore is cleared. There is no other transition from stage 2
1087 * to scrolling, or vice versa, for a pair of touches.
1088 * 3. If tp->ignore is set and the touch is resting, it is marked as
1089 * thumb, and it will be ignored until it ends.
1090 */
1091void
1092wstpad_mt_masks(struct wsmouseinput *input)
1093{
1094 struct wstpad *tp = input->tp;
1095 struct tpad_touch *t;
1096 struct position *pos;
1097 u_int mask;
1098 int slot;
1099
1100 tp->ignore &= input->mt.touches;
1101
1102 if (tp->contacts < 2)
1103 return;
1104
1105 if (tp->ignore) {
1106 slot = ffs(tp->ignore) - 1;
1107 t = &tp->tpad_touches[slot];
1108 if (t->flags & THUMB(1 << 4))
1109 return;
1110 if (t->dir < 0 && wstpad_is_stable(input, t)) {
1111 t->flags |= THUMB(1 << 4);
1112 return;
1113 }
1114 /* The edge.low area is a bit larger than the bottom area. */
1115 if (t->y >= tp->edge.low || (NORTH(t->dir)((t->dir) == 0 || (t->dir) == 11) &&
1116 magnitude(input, t->pos->dx, t->pos->dy) >= MAG_MEDIUM(18 << 12)))
1117 tp->ignore = 0;
1118 return;
1119 }
1120
1121 if (input->mt.ptr_mask == 0) {
1122 mask = ~0;
1123 FOREACHBIT(input->mt.touches, slot)for ((slot) = ffs(input->mt.touches) - 1; (slot) != -1; (slot
) = ffs((input->mt.touches) & (~1 << (slot))) - 1
)
{
1124 t = &tp->tpad_touches[slot];
1125 if (t->flags & B_EDGE(1 << 3)) {
1126 mask &= (1 << slot);
1127 input->mt.ptr_mask = mask;
1128 }
1129 }
1130 }
1131
1132 if ((input->mt.ptr_mask & ~input->mt.ptr)
1133 && !(tp->scroll.dz || tp->scroll.dw)
1134 && tp->t->dir >= 0
1135 && wstpad_is_stable(input, tp->t)) {
1136
1137 slot = ffs(input->mt.ptr_mask) - 1;
1138 t = &tp->tpad_touches[slot];
1139
1140 if (t->y >= tp->edge.low)
1141 return;
1142
1143 if (!wstpad_is_stable(input, t))
1144 return;
1145
1146 /* Default hysteresis limits are low. Make a strict check. */
1147 pos = tp->t->pos;
1148 if (abs(pos->acc_dx) < 3 * input->filter.h.hysteresis
1149 && abs(pos->acc_dy) < 3 * input->filter.v.hysteresis)
1150 return;
1151
1152 if (t->dir >= 0) {
1153 /* Treat t as thumb if it is slow while tp->t is fast. */
1154 if (magnitude(input, t->pos->dx, t->pos->dy) > MAG_LOW(10 << 12)
1155 || magnitude(input, pos->dx, pos->dy) < MAG_MEDIUM(18 << 12))
1156 return;
1157 }
1158
1159 tp->ignore = input->mt.ptr_mask;
1160 }
1161}
1162
1163void
1164wstpad_touch_inputs(struct wsmouseinput *input)
1165{
1166 struct wstpad *tp = input->tp;
1167 struct tpad_touch *t;
1168 int slot, x, y, dx, dy;
1169
1170 tp->btns = input->btn.buttons;
1171 tp->btns_sync = input->btn.sync;
1172
1173 tp->prev_contacts = tp->contacts;
1174 tp->contacts = input->touch.contacts;
1175
1176 if (tp->contacts == 1 &&
1177 ((tp->params.f2width &&
1178 input->touch.width >= tp->params.f2width)
1179 || (tp->params.f2pressure &&
1180 input->touch.pressure >= tp->params.f2pressure)))
1181 tp->contacts = 2;
1182
1183 if (IS_MT(tp)((tp)->features & (1 << 31))) {
1184 wstpad_mt_inputs(input);
1185 if (input->mt.ptr) {
1186 slot = ffs(input->mt.ptr) - 1;
1187 tp->t = &tp->tpad_touches[slot];
1188 }
1189 wstpad_mt_masks(input);
1190 } else {
1191 t = tp->t;
1192 if (tp->contacts)
1193 t->state = (tp->prev_contacts ?
1194 TOUCH_UPDATE : TOUCH_BEGIN);
1195 else
1196 t->state = (tp->prev_contacts ?
1197 TOUCH_END : TOUCH_NONE);
1198
1199 dx = dy = 0;
1200 x = normalize_abs(&input->filter.h, t->pos->x);
1201 y = normalize_abs(&input->filter.v, t->pos->y);
1202 if (t->state == TOUCH_BEGIN) {
1203 t->x = t->orig.x = x;
1204 t->y = t->orig.y = y;
1205 memcpy(&t->orig.time, &tp->time,__builtin_memcpy((&t->orig.time), (&tp->time), (
sizeof(struct timespec)))
1206 sizeof(struct timespec))__builtin_memcpy((&t->orig.time), (&tp->time), (
sizeof(struct timespec)))
;
1207 t->flags = edge_flags(tp, x, y);
1208 } else if (input->motion.sync & SYNC_POSITION((1 << 1) | (1 << 2))) {
1209 if (!wsmouse_hysteresis(input, t->pos)) {
1210 dx = x - t->x;
1211 dy = y - t->y;
1212 }
1213 t->x = x;
1214 t->y = y;
1215 t->flags &= (~EDGES((1 << 0) | (1 << 1) | (1 << 2) | (1 <<
3))
| edge_flags(tp, x, y));
1216 }
1217 wstpad_set_direction(tp, t, dx, dy);
1218 }
1219}
1220
1221static inline int
1222t2_ignore(struct wsmouseinput *input)
1223{
1224 /*
1225 * If there are two touches, do not block pointer movement if they
1226 * perform a click-and-drag action, or if the second touch is
1227 * resting in the bottom area.
1228 */
1229 return (input->tp->contacts == 2 && ((input->tp->btns & PRIMARYBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
)
1230 || (input->tp->ignore & ~input->mt.ptr)));
1231}
1232
1233void
1234wstpad_process_input(struct wsmouseinput *input, struct evq_access *evq)
1235{
1236 struct wstpad *tp = input->tp;
1237 u_int handlers, hdlr, cmds;
1238
1239 memcpy(&tp->time, &evq->ts, sizeof(struct timespec))__builtin_memcpy((&tp->time), (&evq->ts), (sizeof
(struct timespec)))
;
1240 wstpad_touch_inputs(input);
1241
1242 cmds = 0;
1243 handlers = tp->handlers;
1244 if (DISABLE(tp)((tp)->features & (1 << 7)))
8
Assuming the condition is false
9
Taking false branch
1245 handlers &= ((1 << TOPBUTTON_HDLR) | (1 << SOFTBUTTON_HDLR));
1246
1247 FOREACHBIT(handlers, hdlr)for ((hdlr) = ffs(handlers) - 1; (hdlr) != -1; (hdlr) = ffs((
handlers) & (~1 << (hdlr))) - 1)
{
10
Assuming the condition is false
11
Loop condition is false. Execution continues on line 1269
1248 switch (hdlr) {
1249 case SOFTBUTTON_HDLR:
1250 case TOPBUTTON_HDLR:
1251 wstpad_softbuttons(input, &cmds, hdlr);
1252 continue;
1253 case TAP_HDLR:
1254 wstpad_tap(input, &cmds);
1255 continue;
1256 case F2SCROLL_HDLR:
1257 wstpad_f2scroll(input, &cmds);
1258 continue;
1259 case EDGESCROLL_HDLR:
1260 wstpad_edgescroll(input, &cmds);
1261 continue;
1262 case CLICK_HDLR:
1263 wstpad_click(input);
1264 continue;
1265 }
1266 }
1267
1268 /* Check whether pointer movement should be blocked. */
1269 if (input->motion.dx
11.1
Field 'dx' is 0
|| input->motion.dy
11.2
Field 'dy' is 0
) {
12
Taking false branch
1270 if (DISABLE(tp)((tp)->features & (1 << 7))
1271 || (tp->t->flags & tp->freeze)
1272 || timespeccmp(&tp->time, &tp->freeze_ts, <)(((&tp->time)->tv_sec == (&tp->freeze_ts)->
tv_sec) ? ((&tp->time)->tv_nsec < (&tp->freeze_ts
)->tv_nsec) : ((&tp->time)->tv_sec < (&tp
->freeze_ts)->tv_sec))
1273 || (tp->contacts > 1 && !t2_ignore(input))) {
1274
1275 cmds |= 1 << CLEAR_MOTION_DELTAS;
1276 }
1277 }
1278
1279 wstpad_cmds(input, evq, cmds);
13
Calling 'wstpad_cmds'
1280
1281 if (IS_MT(tp)((tp)->features & (1 << 31)))
1282 clear_touchstates(input, TOUCH_NONE);
1283}
1284
1285/*
1286 * Try to determine the average interval between two updates. Various
1287 * conditions are checked in order to ensure that only valid samples enter
1288 * into the calculation. Above all, it is restricted to motion events
1289 * occurring when there is only one contact. MT devices may need more than
1290 * one packet to transmit their state if there are multiple touches, and
1291 * the update frequency may be higher in this case.
1292 */
1293void
1294wstpad_track_interval(struct wsmouseinput *input, struct timespec *time)
1295{
1296 static const struct timespec limit = { 0, 30 * 1000000L };
1297 struct timespec ts;
1298 int samples;
1299
1300 if (input->motion.sync == 0
1301 || (input->touch.sync & SYNC_CONTACTS(1 << 1))
1302 || (input->touch.contacts > 1)) {
1303 input->intv.track = 0;
1304 return;
1305 }
1306 if (input->intv.track) {
1307 timespecsub(time, &input->intv.ts, &ts)do { (&ts)->tv_sec = (time)->tv_sec - (&input->
intv.ts)->tv_sec; (&ts)->tv_nsec = (time)->tv_nsec
- (&input->intv.ts)->tv_nsec; if ((&ts)->tv_nsec
< 0) { (&ts)->tv_sec--; (&ts)->tv_nsec += 1000000000L
; } } while (0)
;
1308 if (timespeccmp(&ts, &limit, <)(((&ts)->tv_sec == (&limit)->tv_sec) ? ((&ts
)->tv_nsec < (&limit)->tv_nsec) : ((&ts)->
tv_sec < (&limit)->tv_sec))
) {
1309 /* The unit of the sum is 4096 nanoseconds. */
1310 input->intv.sum += ts.tv_nsec >> 12;
1311 samples = ++input->intv.samples;
1312 /*
1313 * Make the first calculation quickly and later
1314 * a more reliable one:
1315 */
1316 if (samples == 8) {
1317 input->intv.avg = input->intv.sum << 9;
1318 wstpad_init_deceleration(input);
1319 } else if (samples == 128) {
1320 input->intv.avg = input->intv.sum << 5;
1321 wstpad_init_deceleration(input);
1322 input->intv.samples = 0;
1323 input->intv.sum = 0;
1324 input->flags &= ~TRACK_INTERVAL(1 << 17);
1325 }
1326 }
1327 }
1328 memcpy(&input->intv.ts, time, sizeof(struct timespec))__builtin_memcpy((&input->intv.ts), (time), (sizeof(struct
timespec)))
;
1329 input->intv.track = 1;
1330}
1331
1332
1333
1334/*
1335 * The default acceleration options of X don't work convincingly with
1336 * touchpads (the synaptics driver installs its own "acceleration
1337 * profile" and callback function). As a preliminary workaround, this
1338 * filter applies a simple deceleration scheme to small deltas, based
1339 * on the "magnitude" of the delta pair. A magnitude of 8 corresponds,
1340 * roughly, to a speed of (filter.dclr / 12.5) device units per milli-
1341 * second. If its magnitude is smaller than 7 a delta will be downscaled
1342 * by the factor 2/8, deltas with magnitudes from 7 to 11 by factors
1343 * ranging from 3/8 to 7/8.
1344 */
1345int
1346wstpad_decelerate(struct wsmouseinput *input, int *dx, int *dy)
1347{
1348 int mag, n, h, v;
1349
1350 mag = magnitude(input, *dx, *dy);
1351
1352 /* Don't change deceleration levels abruptly. */
1353 mag = (mag + 7 * input->filter.mag) / 8;
1354 /* Don't use arbitrarily high values. */
1355 input->filter.mag = imin(mag, 24 << 12);
1356
1357 n = imax((mag >> 12) - 4, 2);
1358 if (n < 8) {
1359 /* Scale by (n / 8). */
1360 h = *dx * n + input->filter.h.dclr_rmdr;
1361 v = *dy * n + input->filter.v.dclr_rmdr;
1362 input->filter.h.dclr_rmdr = (h >= 0 ? h & 7 : -(-h & 7));
1363 input->filter.v.dclr_rmdr = (v >= 0 ? v & 7 : -(-v & 7));
1364 *dx = h / 8;
1365 *dy = v / 8;
1366 return (1);
1367 }
1368 return (0);
1369}
1370
1371void
1372wstpad_filter(struct wsmouseinput *input)
1373{
1374 struct axis_filter *h = &input->filter.h;
1375 struct axis_filter *v = &input->filter.v;
1376 struct position *pos = &input->motion.pos;
1377 int strength = input->filter.mode & 7;
1378 int dx, dy;
1379
1380 if (!(input->motion.sync & SYNC_POSITION((1 << 1) | (1 << 2)))
1381 || (h->dmax && (abs(pos->dx) > h->dmax))
1382 || (v->dmax && (abs(pos->dy) > v->dmax))) {
1383 dx = dy = 0;
1384 } else {
1385 dx = pos->dx;
1386 dy = pos->dy;
1387 }
1388
1389 if (wsmouse_hysteresis(input, pos))
1390 dx = dy = 0;
1391
1392 if (input->filter.dclr && wstpad_decelerate(input, &dx, &dy))
1393 /* Strong smoothing may hamper the precision at low speeds. */
1394 strength = imin(strength, 2);
1395
1396 if (strength) {
1397 if ((input->touch.sync & SYNC_CONTACTS(1 << 1))
1398 || input->mt.ptr != input->mt.prev_ptr) {
1399 h->avg = v->avg = 0;
1400 }
1401 /* Use a weighted decaying average for smoothing. */
1402 dx = dx * (8 - strength) + h->avg * strength + h->avg_rmdr;
1403 dy = dy * (8 - strength) + v->avg * strength + v->avg_rmdr;
1404 h->avg_rmdr = (dx >= 0 ? dx & 7 : -(-dx & 7));
1405 v->avg_rmdr = (dy >= 0 ? dy & 7 : -(-dy & 7));
1406 dx = h->avg = dx / 8;
1407 dy = v->avg = dy / 8;
1408 }
1409
1410 input->motion.dx = dx;
1411 input->motion.dy = dy;
1412}
1413
1414
1415/*
1416 * Compatibility-mode conversions. wstpad_filter transforms and filters
1417 * the coordinate inputs, extended functionality is provided by
1418 * wstpad_process_input.
1419 */
1420void
1421wstpad_compat_convert(struct wsmouseinput *input, struct evq_access *evq)
1422{
1423 if (input->flags & TRACK_INTERVAL(1 << 17))
1
Assuming the condition is false
2
Taking false branch
1424 wstpad_track_interval(input, &evq->ts);
1425
1426 wstpad_filter(input);
1427
1428 if ((input->motion.dx || input->motion.dy)
3
Assuming field 'dx' is 0
4
Assuming field 'dy' is 0
1429 && !(input->motion.sync & SYNC_DELTAS(1 << 0))) {
1430 input->motion.dz = input->motion.dw = 0;
1431 input->motion.sync |= SYNC_DELTAS(1 << 0);
1432 }
1433
1434 if (input->tp != NULL((void *)0))
5
Assuming field 'tp' is not equal to NULL
6
Taking true branch
1435 wstpad_process_input(input, evq);
7
Calling 'wstpad_process_input'
1436
1437 input->motion.sync &= ~SYNC_POSITION((1 << 1) | (1 << 2));
1438 input->touch.sync = 0;
1439}
1440
1441int
1442wstpad_init(struct wsmouseinput *input)
1443{
1444 struct wstpad *tp = input->tp;
1445 int i, slots;
1446
1447 if (tp != NULL((void *)0))
1448 return (0);
1449
1450 input->tp = tp = malloc(sizeof(struct wstpad),
1451 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
1452 if (tp == NULL((void *)0))
1453 return (-1);
1454
1455 slots = imax(input->mt.num_slots, 1);
1456 tp->tpad_touches = malloc(slots * sizeof(struct tpad_touch),
1457 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
1458 if (tp->tpad_touches == NULL((void *)0)) {
1459 free(tp, M_DEVBUF2, sizeof(struct wstpad));
1460 return (-1);
1461 }
1462
1463 tp->t = &tp->tpad_touches[0];
1464 if (input->mt.num_slots) {
1465 tp->features |= WSTPAD_MT(1 << 31);
1466 for (i = 0; i < input->mt.num_slots; i++)
1467 tp->tpad_touches[i].pos = &input->mt.slots[i].pos;
1468 } else {
1469 tp->t->pos = &input->motion.pos;
1470 }
1471
1472 timeout_set(&tp->tap.to, wstpad_tap_timeout, input);
1473
1474 tp->ratio = input->filter.ratio;
1475
1476 return (0);
1477}
1478
1479/*
1480 * Integer square root (Halleck's method)
1481 *
1482 * An adaption of code from John B. Halleck (from
1483 * http://www.cc.utah.edu/~nahaj/factoring/code.html). This version is
1484 * used and published under the OpenBSD license terms with his permission.
1485 *
1486 * Cf. also Martin Guy's "Square root by abacus" method.
1487 */
1488static inline u_int
1489isqrt(u_int n)
1490{
1491 u_int root, sqbit;
1492
1493 root = 0;
1494 sqbit = 1 << (sizeof(u_int) * 8 - 2);
1495 while (sqbit) {
1496 if (n >= (sqbit | root)) {
1497 n -= (sqbit | root);
1498 root = (root >> 1) | sqbit;
1499 } else {
1500 root >>= 1;
1501 }
1502 sqbit >>= 2;
1503 }
1504 return (root);
1505}
1506
1507void
1508wstpad_init_deceleration(struct wsmouseinput *input)
1509{
1510 int n, dclr;
1511
1512 if ((dclr = input->filter.dclr) == 0)
1513 return;
1514
1515 dclr = imax(dclr, 4);
1516
1517 /*
1518 * For a standard update rate of about 80Hz, (dclr) units
1519 * will be mapped to a magnitude of 8. If the average rate
1520 * is significantly higher or lower, adjust the coefficient
1521 * accordingly:
1522 */
1523 if (input->intv.avg == 0) {
1524 n = 8;
1525 } else {
1526 n = 8 * 13000000 / input->intv.avg;
1527 n = imax(imin(n, 32), 4);
1528 }
1529 input->filter.h.mag_scale = (n << 12) / dclr;
1530 input->filter.v.mag_scale = (input->filter.ratio ?
1531 n * input->filter.ratio : n << 12) / dclr;
1532 input->filter.h.dclr_rmdr = 0;
1533 input->filter.v.dclr_rmdr = 0;
1534 input->flags |= TRACK_INTERVAL(1 << 17);
1535}
1536
1537int
1538wstpad_configure(struct wsmouseinput *input)
1539{
1540 struct wstpad *tp;
1541 int width, height, diag, offset, h_res, v_res, h_unit, v_unit, i;
1542
1543 width = abs(input->hw.x_max - input->hw.x_min);
1544 height = abs(input->hw.y_max - input->hw.y_min);
1545 if (width == 0 || height == 0)
1546 return (-1); /* We can't do anything. */
1547
1548 if (input->tp == NULL((void *)0) && wstpad_init(input))
1549 return (-1);
1550 tp = input->tp;
1551
1552 if (!(input->flags & CONFIGURED(1 << 18))) {
1553 /*
1554 * The filter parameters are derived from the length of the
1555 * diagonal in device units, with some magic constants which
1556 * are partly adapted from libinput or synaptics code, or are
1557 * based on tests and guess work. The absolute resolution
1558 * values might not be reliable, but if they are present the
1559 * settings are adapted to the ratio.
1560 */
1561 h_res = input->hw.h_res;
1562 v_res = input->hw.v_res;
1563 if (h_res == 0 || v_res == 0)
1564 h_res = v_res = 1;
1565 diag = isqrt(width * width + height * height);
1566 input->filter.h.scale = (imin(920, diag) << 12) / diag;
1567 input->filter.v.scale = input->filter.h.scale * h_res / v_res;
1568 h_unit = imax(diag / 280, 3);
1569 v_unit = imax((h_unit * v_res + h_res / 2) / h_res, 3);
1570 input->filter.h.hysteresis = h_unit;
1571 input->filter.v.hysteresis = v_unit;
1572 input->filter.mode = FILTER_MODE_DEFAULT0;
1573 input->filter.dclr = h_unit - h_unit / 5;
1574 wstpad_init_deceleration(input);
1575
1576 tp->features &= (WSTPAD_MT(1 << 31) | WSTPAD_DISABLE(1 << 7));
1577
1578 if (input->hw.contacts_max != 1)
1579 tp->features |= WSTPAD_TWOFINGERSCROLL(1 << 3);
1580 else
1581 tp->features |= WSTPAD_EDGESCROLL(1 << 4);
1582
1583 if (input->hw.hw_type == WSMOUSEHW_CLICKPAD) {
1584 if (input->hw.type == WSMOUSE_TYPE_SYNAP_SBTN19) {
1585 tp->features |= WSTPAD_TOPBUTTONS(1 << 2);
1586 } else {
1587 tp->features |= WSTPAD_SOFTBUTTONS(1 << 0);
1588 tp->features |= WSTPAD_SOFTMBTN(1 << 1);
1589 }
1590 }
1591
1592 tp->params.left_edge = V_EDGE_RATIO_DEFAULT205;
1593 tp->params.right_edge = V_EDGE_RATIO_DEFAULT205;
1594 tp->params.bottom_edge = ((tp->features & WSTPAD_SOFTBUTTONS(1 << 0))
1595 ? B_EDGE_RATIO_DEFAULT410 : 0);
1596 tp->params.top_edge = ((tp->features & WSTPAD_TOPBUTTONS(1 << 2))
1597 ? T_EDGE_RATIO_DEFAULT512 : 0);
1598 tp->params.center_width = CENTER_RATIO_DEFAULT512;
1599
1600 tp->tap.maxtime.tv_nsec = TAP_MAXTIME_DEFAULT180 * 1000000;
1601 tp->tap.clicktime = TAP_CLICKTIME_DEFAULT180;
1602 tp->tap.locktime = TAP_LOCKTIME_DEFAULT0;
1603
1604 tp->scroll.hdist = 4 * h_unit;
1605 tp->scroll.vdist = 4 * v_unit;
1606 tp->tap.maxdist = 4 * h_unit;
1607 }
1608
1609 /* A touch with a flag set in this mask does not move the pointer. */
1610 tp->freeze = EDGES((1 << 0) | (1 << 1) | (1 << 2) | (1 <<
3))
;
1611
1612 offset = width * tp->params.left_edge / 4096;
1613 tp->edge.left = (offset ? input->hw.x_min + offset : INT_MIN(-0x7fffffff-1));
1614 offset = width * tp->params.right_edge / 4096;
1615 tp->edge.right = (offset ? input->hw.x_max - offset : INT_MAX0x7fffffff);
1616 offset = height * tp->params.bottom_edge / 4096;
1617 tp->edge.bottom = (offset ? input->hw.y_min + offset : INT_MIN(-0x7fffffff-1));
1618 tp->edge.low = tp->edge.bottom + offset / 2;
1619 offset = height * tp->params.top_edge / 4096;
1620 tp->edge.top = (offset ? input->hw.y_max - offset : INT_MAX0x7fffffff);
1621
1622 offset = width * abs(tp->params.center_width) / 8192;
1623 tp->edge.center = input->hw.x_min + width / 2;
1624 tp->edge.center_left = tp->edge.center - offset;
1625 tp->edge.center_right = tp->edge.center + offset;
1626
1627 tp->handlers = 0;
1628
1629 if (tp->features & WSTPAD_SOFTBUTTONS(1 << 0))
1630 tp->handlers |= 1 << SOFTBUTTON_HDLR;
1631 if (tp->features & WSTPAD_TOPBUTTONS(1 << 2))
1632 tp->handlers |= 1 << TOPBUTTON_HDLR;
1633
1634 if (tp->features & WSTPAD_TWOFINGERSCROLL(1 << 3))
1635 tp->handlers |= 1 << F2SCROLL_HDLR;
1636 else if (tp->features & WSTPAD_EDGESCROLL(1 << 4))
1637 tp->handlers |= 1 << EDGESCROLL_HDLR;
1638
1639 for (i = 0; i < TAP_BTNMAP_SIZE3; i++) {
1640 if (tp->tap.btnmap[i] == 0)
1641 continue;
1642
1643 tp->tap.clicktime = imin(imax(tp->tap.clicktime, 80), 350);
1644 if (tp->tap.locktime)
1645 tp->tap.locktime =
1646 imin(imax(tp->tap.locktime, 150), 5000);
1647 tp->handlers |= 1 << TAP_HDLR;
1648 break;
1649 }
1650
1651 if (input->hw.hw_type == WSMOUSEHW_CLICKPAD)
1652 tp->handlers |= 1 << CLICK_HDLR;
1653
1654 tp->sbtnswap = ((tp->features & WSTPAD_SWAPSIDES(1 << 6))
1655 ? (LEFTBTN((1) > 0 && (1) <= 32 ? 1 << ((1) - 1) : 0
)
| RIGHTBTN((3) > 0 && (3) <= 32 ? 1 << ((3) - 1) : 0
)
) : 0);
1656
1657 return (0);
1658}
1659
1660void
1661wstpad_reset(struct wsmouseinput *input)
1662{
1663 struct wstpad *tp = input->tp;
1664
1665 if (tp != NULL((void *)0)) {
1666 timeout_del(&tp->tap.to);
1667 tp->tap.state = TAP_DETECT;
1668 }
1669
1670 if (input->sbtn.buttons) {
1671 input->sbtn.sync = input->sbtn.buttons;
1672 input->sbtn.buttons = 0;
1673 }
1674}
1675
1676void
1677wstpad_cleanup(struct wsmouseinput *input)
1678{
1679 struct wstpad *tp = input->tp;
1680 int slots;
1681
1682 timeout_del(&tp->tap.to);
1683 slots = imax(input->mt.num_slots, 1);
1684 free(tp->tpad_touches, M_DEVBUF2, slots * sizeof(struct tpad_touch));
1685 free(tp, M_DEVBUF2, sizeof(struct wstpad));
1686 input->tp = NULL((void *)0);
1687}
1688
1689int
1690wstpad_set_param(struct wsmouseinput *input, int key, int val)
1691{
1692 struct wstpad *tp = input->tp;
1693 u_int flag;
1694
1695 if (tp == NULL((void *)0))
1696 return (EINVAL22);
1697
1698 switch (key) {
1699 case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE:
1700 switch (key) {
1701 case WSMOUSECFG_SOFTBUTTONS:
1702 flag = WSTPAD_SOFTBUTTONS(1 << 0);
1703 break;
1704 case WSMOUSECFG_SOFTMBTN:
1705 flag = WSTPAD_SOFTMBTN(1 << 1);
1706 break;
1707 case WSMOUSECFG_TOPBUTTONS:
1708 flag = WSTPAD_TOPBUTTONS(1 << 2);
1709 break;
1710 case WSMOUSECFG_TWOFINGERSCROLL:
1711 flag = WSTPAD_TWOFINGERSCROLL(1 << 3);
1712 break;
1713 case WSMOUSECFG_EDGESCROLL:
1714 flag = WSTPAD_EDGESCROLL(1 << 4);
1715 break;
1716 case WSMOUSECFG_HORIZSCROLL:
1717 flag = WSTPAD_HORIZSCROLL(1 << 5);
1718 break;
1719 case WSMOUSECFG_SWAPSIDES:
1720 flag = WSTPAD_SWAPSIDES(1 << 6);
1721 break;
1722 case WSMOUSECFG_DISABLE:
1723 flag = WSTPAD_DISABLE(1 << 7);
1724 break;
1725 }
1726 if (val)
1727 tp->features |= flag;
1728 else
1729 tp->features &= ~flag;
1730 break;
1731 case WSMOUSECFG_LEFT_EDGE:
1732 tp->params.left_edge = val;
1733 break;
1734 case WSMOUSECFG_RIGHT_EDGE:
1735 tp->params.right_edge = val;
1736 break;
1737 case WSMOUSECFG_TOP_EDGE:
1738 tp->params.top_edge = val;
1739 break;
1740 case WSMOUSECFG_BOTTOM_EDGE:
1741 tp->params.bottom_edge = val;
1742 break;
1743 case WSMOUSECFG_CENTERWIDTH:
1744 tp->params.center_width = val;
1745 break;
1746 case WSMOUSECFG_HORIZSCROLLDIST:
1747 tp->scroll.hdist = val;
1748 break;
1749 case WSMOUSECFG_VERTSCROLLDIST:
1750 tp->scroll.vdist = val;
1751 break;
1752 case WSMOUSECFG_F2WIDTH:
1753 tp->params.f2width = val;
1754 break;
1755 case WSMOUSECFG_F2PRESSURE:
1756 tp->params.f2pressure = val;
1757 break;
1758 case WSMOUSECFG_TAP_MAXTIME:
1759 tp->tap.maxtime.tv_nsec = imin(val, 999) * 1000000;
1760 break;
1761 case WSMOUSECFG_TAP_CLICKTIME:
1762 tp->tap.clicktime = val;
1763 break;
1764 case WSMOUSECFG_TAP_LOCKTIME:
1765 tp->tap.locktime = val;
1766 break;
1767 case WSMOUSECFG_TAP_ONE_BTNMAP:
1768 tp->tap.btnmap[0] = BTNMASK(val)((val) > 0 && (val) <= 32 ? 1 << ((val) -
1) : 0)
;
1769 break;
1770 case WSMOUSECFG_TAP_TWO_BTNMAP:
1771 tp->tap.btnmap[1] = BTNMASK(val)((val) > 0 && (val) <= 32 ? 1 << ((val) -
1) : 0)
;
1772 break;
1773 case WSMOUSECFG_TAP_THREE_BTNMAP:
1774 tp->tap.btnmap[2] = BTNMASK(val)((val) > 0 && (val) <= 32 ? 1 << ((val) -
1) : 0)
;
1775 break;
1776 default:
1777 return (ENOTSUP91);
1778 }
1779
1780 return (0);
1781}
1782
1783int
1784wstpad_get_param(struct wsmouseinput *input, int key, int *pval)
1785{
1786 struct wstpad *tp = input->tp;
1787 u_int flag;
1788
1789 if (tp == NULL((void *)0))
1790 return (EINVAL22);
1791
1792 switch (key) {
1793 case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE:
1794 switch (key) {
1795 case WSMOUSECFG_SOFTBUTTONS:
1796 flag = WSTPAD_SOFTBUTTONS(1 << 0);
1797 break;
1798 case WSMOUSECFG_SOFTMBTN:
1799 flag = WSTPAD_SOFTMBTN(1 << 1);
1800 break;
1801 case WSMOUSECFG_TOPBUTTONS:
1802 flag = WSTPAD_TOPBUTTONS(1 << 2);
1803 break;
1804 case WSMOUSECFG_TWOFINGERSCROLL:
1805 flag = WSTPAD_TWOFINGERSCROLL(1 << 3);
1806 break;
1807 case WSMOUSECFG_EDGESCROLL:
1808 flag = WSTPAD_EDGESCROLL(1 << 4);
1809 break;
1810 case WSMOUSECFG_HORIZSCROLL:
1811 flag = WSTPAD_HORIZSCROLL(1 << 5);
1812 break;
1813 case WSMOUSECFG_SWAPSIDES:
1814 flag = WSTPAD_SWAPSIDES(1 << 6);
1815 break;
1816 case WSMOUSECFG_DISABLE:
1817 flag = WSTPAD_DISABLE(1 << 7);
1818 break;
1819 }
1820 *pval = !!(tp->features & flag);
1821 break;
1822 case WSMOUSECFG_LEFT_EDGE:
1823 *pval = tp->params.left_edge;
1824 break;
1825 case WSMOUSECFG_RIGHT_EDGE:
1826 *pval = tp->params.right_edge;
1827 break;
1828 case WSMOUSECFG_TOP_EDGE:
1829 *pval = tp->params.top_edge;
1830 break;
1831 case WSMOUSECFG_BOTTOM_EDGE:
1832 *pval = tp->params.bottom_edge;
1833 break;
1834 case WSMOUSECFG_CENTERWIDTH:
1835 *pval = tp->params.center_width;
1836 break;
1837 case WSMOUSECFG_HORIZSCROLLDIST:
1838 *pval = tp->scroll.hdist;
1839 break;
1840 case WSMOUSECFG_VERTSCROLLDIST:
1841 *pval = tp->scroll.vdist;
1842 break;
1843 case WSMOUSECFG_F2WIDTH:
1844 *pval = tp->params.f2width;
1845 break;
1846 case WSMOUSECFG_F2PRESSURE:
1847 *pval = tp->params.f2pressure;
1848 break;
1849 case WSMOUSECFG_TAP_MAXTIME:
1850 *pval = tp->tap.maxtime.tv_nsec / 1000000;
1851 break;
1852 case WSMOUSECFG_TAP_CLICKTIME:
1853 *pval = tp->tap.clicktime;
1854 break;
1855 case WSMOUSECFG_TAP_LOCKTIME:
1856 *pval = tp->tap.locktime;
1857 break;
1858 case WSMOUSECFG_TAP_ONE_BTNMAP:
1859 *pval = ffs(tp->tap.btnmap[0]);
1860 break;
1861 case WSMOUSECFG_TAP_TWO_BTNMAP:
1862 *pval = ffs(tp->tap.btnmap[1]);
1863 break;
1864 case WSMOUSECFG_TAP_THREE_BTNMAP:
1865 *pval = ffs(tp->tap.btnmap[2]);
1866 break;
1867 default:
1868 return (ENOTSUP91);
1869 }
1870
1871 return (0);
1872}