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