xref: /freebsd/sys/dev/evdev/evdev_mt.c (revision f76051c7dabe952b75127a8031d87d78b603be20)
12b3f6d66SOleksandr Tymoshenko /*-
2*f76051c7SVladimir Kondratyev  * Copyright (c) 2016, 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
32b3f6d66SOleksandr Tymoshenko  * All rights reserved.
42b3f6d66SOleksandr Tymoshenko  *
52b3f6d66SOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
62b3f6d66SOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
72b3f6d66SOleksandr Tymoshenko  * are met:
82b3f6d66SOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
92b3f6d66SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer.
102b3f6d66SOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
112b3f6d66SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
122b3f6d66SOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
132b3f6d66SOleksandr Tymoshenko  *
142b3f6d66SOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152b3f6d66SOleksandr Tymoshenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162b3f6d66SOleksandr Tymoshenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172b3f6d66SOleksandr Tymoshenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182b3f6d66SOleksandr Tymoshenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192b3f6d66SOleksandr Tymoshenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202b3f6d66SOleksandr Tymoshenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212b3f6d66SOleksandr Tymoshenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222b3f6d66SOleksandr Tymoshenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232b3f6d66SOleksandr Tymoshenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242b3f6d66SOleksandr Tymoshenko  * SUCH DAMAGE.
252b3f6d66SOleksandr Tymoshenko  *
262b3f6d66SOleksandr Tymoshenko  * $FreeBSD$
272b3f6d66SOleksandr Tymoshenko  */
284c0a134eSVladimir Kondratyev /*-
294c0a134eSVladimir Kondratyev  * Copyright (c) 2015, 2016 Ulf Brosziewski
304c0a134eSVladimir Kondratyev  *
314c0a134eSVladimir Kondratyev  * Permission to use, copy, modify, and distribute this software for any
324c0a134eSVladimir Kondratyev  * purpose with or without fee is hereby granted, provided that the above
334c0a134eSVladimir Kondratyev  * copyright notice and this permission notice appear in all copies.
344c0a134eSVladimir Kondratyev  *
354c0a134eSVladimir Kondratyev  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
364c0a134eSVladimir Kondratyev  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
374c0a134eSVladimir Kondratyev  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
384c0a134eSVladimir Kondratyev  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
394c0a134eSVladimir Kondratyev  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
404c0a134eSVladimir Kondratyev  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
414c0a134eSVladimir Kondratyev  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
424c0a134eSVladimir Kondratyev  */
432b3f6d66SOleksandr Tymoshenko 
442b3f6d66SOleksandr Tymoshenko #include <sys/param.h>
452b3f6d66SOleksandr Tymoshenko #include <sys/lock.h>
46ea2e26b1SVladimir Kondratyev #include <sys/malloc.h>
472b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h>
482b3f6d66SOleksandr Tymoshenko #include <sys/systm.h>
492b3f6d66SOleksandr Tymoshenko 
502b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h>
512b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.h>
52ea2e26b1SVladimir Kondratyev #include <dev/evdev/input.h>
532b3f6d66SOleksandr Tymoshenko 
542b3f6d66SOleksandr Tymoshenko #ifdef DEBUG
552b3f6d66SOleksandr Tymoshenko #define	debugf(fmt, args...)	printf("evdev: " fmt "\n", ##args)
562b3f6d66SOleksandr Tymoshenko #else
572b3f6d66SOleksandr Tymoshenko #define	debugf(fmt, args...)
582b3f6d66SOleksandr Tymoshenko #endif
592b3f6d66SOleksandr Tymoshenko 
602dc7188eSVladimir Kondratyev typedef	u_int	slotset_t;
612dc7188eSVladimir Kondratyev 
622dc7188eSVladimir Kondratyev _Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big");
632dc7188eSVladimir Kondratyev 
642dc7188eSVladimir Kondratyev #define FOREACHBIT(v, i) \
652dc7188eSVladimir Kondratyev 	for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1)
662dc7188eSVladimir Kondratyev 
67127e54deSVladimir Kondratyev struct {
68127e54deSVladimir Kondratyev 	uint16_t	mt;
69127e54deSVladimir Kondratyev 	uint16_t	st;
70127e54deSVladimir Kondratyev 	int32_t		max;
71127e54deSVladimir Kondratyev } static evdev_mtstmap[] = {
72127e54deSVladimir Kondratyev 	{ ABS_MT_POSITION_X,	ABS_X,		0 },
73127e54deSVladimir Kondratyev 	{ ABS_MT_POSITION_Y,	ABS_Y,		0 },
74127e54deSVladimir Kondratyev 	{ ABS_MT_PRESSURE,	ABS_PRESSURE,	255 },
75127e54deSVladimir Kondratyev 	{ ABS_MT_TOUCH_MAJOR,	ABS_TOOL_WIDTH,	15 },
762b3f6d66SOleksandr Tymoshenko };
772b3f6d66SOleksandr Tymoshenko 
782b3f6d66SOleksandr Tymoshenko struct evdev_mt {
7998a7606bSVladimir Kondratyev 	int			last_reported_slot;
8066bd52f5SVladimir Kondratyev 	uint16_t		tracking_id;
8166bd52f5SVladimir Kondratyev 	int32_t			tracking_ids[MAX_MT_SLOTS];
82127e54deSVladimir Kondratyev 	u_int			mtst_events;
832dc7188eSVladimir Kondratyev 	/* the set of slots with active touches */
842dc7188eSVladimir Kondratyev 	slotset_t		touches;
852dc7188eSVladimir Kondratyev 	/* the set of slots with unsynchronized state */
862dc7188eSVladimir Kondratyev 	slotset_t		frame;
87*f76051c7SVladimir Kondratyev 	/* the set of slots to match with active touches */
88*f76051c7SVladimir Kondratyev 	slotset_t		match_frame;
89*f76051c7SVladimir Kondratyev 	int			match_slot;
90*f76051c7SVladimir Kondratyev 	union evdev_mt_slot	*match_slots;
914c0a134eSVladimir Kondratyev 	int			*matrix;
9205936028SVladimir Kondratyev 	union evdev_mt_slot	slots[];
932b3f6d66SOleksandr Tymoshenko };
942b3f6d66SOleksandr Tymoshenko 
9598a7606bSVladimir Kondratyev static void	evdev_mt_send_st_compat(struct evdev_dev *);
9698a7606bSVladimir Kondratyev static void	evdev_mt_send_autorel(struct evdev_dev *);
97*f76051c7SVladimir Kondratyev static void	evdev_mt_replay_events(struct evdev_dev *);
9898a7606bSVladimir Kondratyev 
992dc7188eSVladimir Kondratyev static inline int
1002dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots)
1012dc7188eSVladimir Kondratyev {
1022dc7188eSVladimir Kondratyev 	return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1);
1032dc7188eSVladimir Kondratyev }
1042dc7188eSVladimir Kondratyev 
1052b3f6d66SOleksandr Tymoshenko void
1062b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev)
1072b3f6d66SOleksandr Tymoshenko {
1084c0a134eSVladimir Kondratyev 	struct evdev_mt *mt;
1094c0a134eSVladimir Kondratyev 	size_t size = offsetof(struct evdev_mt, slots);
11098a7606bSVladimir Kondratyev 	int slot, slots;
1112b3f6d66SOleksandr Tymoshenko 
1122b3f6d66SOleksandr Tymoshenko 	slots = MAXIMAL_MT_SLOT(evdev) + 1;
1134c0a134eSVladimir Kondratyev 	size += sizeof(mt->slots[0]) * slots;
1144c0a134eSVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
115*f76051c7SVladimir Kondratyev 		size += sizeof(mt->match_slots[0]) * slots;
1164c0a134eSVladimir Kondratyev 		size += sizeof(mt->matrix[0]) * (slots + 6) * slots;
1174c0a134eSVladimir Kondratyev 	}
1182b3f6d66SOleksandr Tymoshenko 
1194c0a134eSVladimir Kondratyev 	mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO);
1204c0a134eSVladimir Kondratyev 	evdev->ev_mt = mt;
1214c0a134eSVladimir Kondratyev 
1224c0a134eSVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
123*f76051c7SVladimir Kondratyev 		mt->match_slots = mt->slots + slots;
124*f76051c7SVladimir Kondratyev 		mt->matrix = (int *)(mt->match_slots + slots);
1254c0a134eSVladimir Kondratyev 	}
1262b3f6d66SOleksandr Tymoshenko 
1272b3f6d66SOleksandr Tymoshenko 	/* Initialize multitouch protocol type B states */
1282dc7188eSVladimir Kondratyev 	for (slot = 0; slot < slots; slot++)
129*f76051c7SVladimir Kondratyev 		mt->slots[slot].id = -1;
1302b3f6d66SOleksandr Tymoshenko 
13166bd52f5SVladimir Kondratyev 	if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID))
13266bd52f5SVladimir Kondratyev 		evdev_support_abs(evdev,
13366bd52f5SVladimir Kondratyev 		    ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0);
1342b3f6d66SOleksandr Tymoshenko 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
1352b3f6d66SOleksandr Tymoshenko 		evdev_support_mt_compat(evdev);
1362b3f6d66SOleksandr Tymoshenko }
1372b3f6d66SOleksandr Tymoshenko 
1382b3f6d66SOleksandr Tymoshenko void
1392b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev)
1402b3f6d66SOleksandr Tymoshenko {
1412b3f6d66SOleksandr Tymoshenko 	free(evdev->ev_mt, M_EVDEV);
1422b3f6d66SOleksandr Tymoshenko }
1432b3f6d66SOleksandr Tymoshenko 
14498a7606bSVladimir Kondratyev void
14598a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev)
1462b3f6d66SOleksandr Tymoshenko {
147*f76051c7SVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK))
148*f76051c7SVladimir Kondratyev 		evdev_mt_replay_events(evdev);
14998a7606bSVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
15098a7606bSVladimir Kondratyev 		evdev_mt_send_autorel(evdev);
15198a7606bSVladimir Kondratyev 	if (evdev->ev_report_opened &&
15298a7606bSVladimir Kondratyev 	    bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
15398a7606bSVladimir Kondratyev 		evdev_mt_send_st_compat(evdev);
1542dc7188eSVladimir Kondratyev 	evdev->ev_mt->frame = 0;
15598a7606bSVladimir Kondratyev }
1562b3f6d66SOleksandr Tymoshenko 
15705936028SVladimir Kondratyev static void
15805936028SVladimir Kondratyev evdev_mt_send_slot(struct evdev_dev *evdev, int slot,
15905936028SVladimir Kondratyev     union evdev_mt_slot *state)
16005936028SVladimir Kondratyev {
16105936028SVladimir Kondratyev 	int i;
16205936028SVladimir Kondratyev 	bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
16305936028SVladimir Kondratyev 
16405936028SVladimir Kondratyev 	EVDEV_LOCK_ASSERT(evdev);
16505936028SVladimir Kondratyev 	MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)));
16605936028SVladimir Kondratyev 	MPASS(!type_a || state != NULL);
16705936028SVladimir Kondratyev 
16805936028SVladimir Kondratyev 	if (!type_a) {
16905936028SVladimir Kondratyev 		evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
17005936028SVladimir Kondratyev 		if (state == NULL) {
17105936028SVladimir Kondratyev 			evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1);
17205936028SVladimir Kondratyev 			return;
17305936028SVladimir Kondratyev 		}
17405936028SVladimir Kondratyev 	}
17505936028SVladimir Kondratyev 	bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i)
17605936028SVladimir Kondratyev 		evdev_send_event(evdev, EV_ABS, i,
17705936028SVladimir Kondratyev 		    state->val[ABS_MT_INDEX(i)]);
17805936028SVladimir Kondratyev 	if (type_a)
17905936028SVladimir Kondratyev 		evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
18005936028SVladimir Kondratyev }
18105936028SVladimir Kondratyev 
18205936028SVladimir Kondratyev int
18305936028SVladimir Kondratyev evdev_mt_push_slot(struct evdev_dev *evdev, int slot,
18405936028SVladimir Kondratyev     union evdev_mt_slot *state)
18505936028SVladimir Kondratyev {
186*f76051c7SVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
18705936028SVladimir Kondratyev 	bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
18805936028SVladimir Kondratyev 
18905936028SVladimir Kondratyev 	if (type_a && state == NULL)
19005936028SVladimir Kondratyev 		return (EINVAL);
19105936028SVladimir Kondratyev 	if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev)))
19205936028SVladimir Kondratyev 		return (EINVAL);
19305936028SVladimir Kondratyev 
19405936028SVladimir Kondratyev 	EVDEV_ENTER(evdev);
195*f76051c7SVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
196*f76051c7SVladimir Kondratyev 		evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
197*f76051c7SVladimir Kondratyev 		if (state != NULL)
198*f76051c7SVladimir Kondratyev 			mt->match_slots[mt->match_slot] = *state;
199*f76051c7SVladimir Kondratyev 		else
200*f76051c7SVladimir Kondratyev 			evdev_mt_record_event(evdev, EV_ABS,
201*f76051c7SVladimir Kondratyev 			    ABS_MT_TRACKING_ID, -1);
202*f76051c7SVladimir Kondratyev 	} else
20305936028SVladimir Kondratyev 		evdev_mt_send_slot(evdev, slot, state);
20405936028SVladimir Kondratyev 	EVDEV_EXIT(evdev);
20505936028SVladimir Kondratyev 
20605936028SVladimir Kondratyev 	return (0);
20705936028SVladimir Kondratyev }
20805936028SVladimir Kondratyev 
2094c0a134eSVladimir Kondratyev /*
2104c0a134eSVladimir Kondratyev  * Find a minimum-weight matching for an m-by-n matrix.
2114c0a134eSVladimir Kondratyev  *
2124c0a134eSVladimir Kondratyev  * m must be greater than or equal to n. The size of the buffer must be
2134c0a134eSVladimir Kondratyev  * at least 3m + 3n.
2144c0a134eSVladimir Kondratyev  *
2154c0a134eSVladimir Kondratyev  * On return, the first m elements of the buffer contain the row-to-
2164c0a134eSVladimir Kondratyev  * column mappings, i.e., buffer[i] is the column index for row i, or -1
2174c0a134eSVladimir Kondratyev  * if there is no assignment for that row (which may happen if n < m).
2184c0a134eSVladimir Kondratyev  *
2194c0a134eSVladimir Kondratyev  * Wrong results because of overflows will not occur with input values
2204c0a134eSVladimir Kondratyev  * in the range of 0 to INT_MAX / 2 inclusive.
2214c0a134eSVladimir Kondratyev  *
2224c0a134eSVladimir Kondratyev  * The function applies the Dinic-Kronrod algorithm. It is not modern or
2234c0a134eSVladimir Kondratyev  * popular, but it seems to be a good choice for small matrices at least.
2244c0a134eSVladimir Kondratyev  * The original form of the algorithm is modified as follows: There is no
2254c0a134eSVladimir Kondratyev  * initial search for row minima, the initial assignments are in a
2264c0a134eSVladimir Kondratyev  * "virtual" column with the index -1 and zero values. This permits inputs
2274c0a134eSVladimir Kondratyev  * with n < m, and it simplifies the reassignments.
2284c0a134eSVladimir Kondratyev  */
2294c0a134eSVladimir Kondratyev static void
2304c0a134eSVladimir Kondratyev evdev_mt_matching(int *matrix, int m, int n, int *buffer)
2314c0a134eSVladimir Kondratyev {
2324c0a134eSVladimir Kondratyev 	int i, j, k, d, e, row, col, delta;
2334c0a134eSVladimir Kondratyev 	int *p;
2344c0a134eSVladimir Kondratyev 	int *r2c = buffer;	/* row-to-column assignments */
2354c0a134eSVladimir Kondratyev 	int *red = r2c + m;	/* reduced values of the assignments */
2364c0a134eSVladimir Kondratyev 	int *mc = red + m;	/* row-wise minimal elements of cs */
2374c0a134eSVladimir Kondratyev 	int *cs = mc + m;	/* the column set */
2384c0a134eSVladimir Kondratyev 	int *c2r = cs + n;	/* column-to-row assignments in cs */
2394c0a134eSVladimir Kondratyev 	int *cd = c2r + n;	/* column deltas (reduction) */
2404c0a134eSVladimir Kondratyev 
2414c0a134eSVladimir Kondratyev 	for (p = r2c; p < red; *p++ = -1) {}
2424c0a134eSVladimir Kondratyev 	for (; p < mc; *p++ = 0) {}
2434c0a134eSVladimir Kondratyev 	for (col = 0; col < n; col++) {
2444c0a134eSVladimir Kondratyev 		delta = INT_MAX;
2454c0a134eSVladimir Kondratyev 		for (i = 0, p = matrix + col; i < m; i++, p += n) {
2464c0a134eSVladimir Kondratyev 			d = *p - red[i];
2474c0a134eSVladimir Kondratyev 			if (d < delta || (d == delta && r2c[i] < 0)) {
2484c0a134eSVladimir Kondratyev 				delta = d;
2494c0a134eSVladimir Kondratyev 				row = i;
2504c0a134eSVladimir Kondratyev 			}
2514c0a134eSVladimir Kondratyev 		}
2524c0a134eSVladimir Kondratyev 		cd[col] = delta;
2534c0a134eSVladimir Kondratyev 		if (r2c[row] < 0) {
2544c0a134eSVladimir Kondratyev 			r2c[row] = col;
2554c0a134eSVladimir Kondratyev 			continue;
2564c0a134eSVladimir Kondratyev 		}
2574c0a134eSVladimir Kondratyev 		for (p = mc; p < cs; *p++ = col) {}
2584c0a134eSVladimir Kondratyev 		for (k = 0; (j = r2c[row]) >= 0;) {
2594c0a134eSVladimir Kondratyev 			cs[k++] = j;
2604c0a134eSVladimir Kondratyev 			c2r[j] = row;
2614c0a134eSVladimir Kondratyev 			mc[row] -= n;
2624c0a134eSVladimir Kondratyev 			delta = INT_MAX;
2634c0a134eSVladimir Kondratyev 			for (i = 0, p = matrix; i < m; i++, p += n)
2644c0a134eSVladimir Kondratyev 				if (mc[i] >= 0) {
2654c0a134eSVladimir Kondratyev 					d = p[mc[i]] - cd[mc[i]];
2664c0a134eSVladimir Kondratyev 					e = p[j] - cd[j];
2674c0a134eSVladimir Kondratyev 					if (e < d) {
2684c0a134eSVladimir Kondratyev 						d = e;
2694c0a134eSVladimir Kondratyev 						mc[i] = j;
2704c0a134eSVladimir Kondratyev 					}
2714c0a134eSVladimir Kondratyev 					d -= red[i];
2724c0a134eSVladimir Kondratyev 					if (d < delta || (d == delta
2734c0a134eSVladimir Kondratyev 					    && r2c[i] < 0)) {
2744c0a134eSVladimir Kondratyev 						delta = d;
2754c0a134eSVladimir Kondratyev 						row = i;
2764c0a134eSVladimir Kondratyev 					}
2774c0a134eSVladimir Kondratyev 				}
2784c0a134eSVladimir Kondratyev 			cd[col] += delta;
2794c0a134eSVladimir Kondratyev 			for (i = 0; i < k; i++) {
2804c0a134eSVladimir Kondratyev 				cd[cs[i]] += delta;
2814c0a134eSVladimir Kondratyev 				red[c2r[cs[i]]] -= delta;
2824c0a134eSVladimir Kondratyev 			}
2834c0a134eSVladimir Kondratyev 		}
2844c0a134eSVladimir Kondratyev 		for (j = mc[row]; (r2c[row] = j) != col;) {
2854c0a134eSVladimir Kondratyev 			row = c2r[j];
2864c0a134eSVladimir Kondratyev 			j = mc[row] + n;
2874c0a134eSVladimir Kondratyev 		}
2884c0a134eSVladimir Kondratyev 	}
2894c0a134eSVladimir Kondratyev }
2904c0a134eSVladimir Kondratyev 
2914c0a134eSVladimir Kondratyev /*
2924c0a134eSVladimir Kondratyev  * Assign tracking IDs to the points in the pt array.  The tracking ID
2934c0a134eSVladimir Kondratyev  * assignment pairs the points with points of the previous frame in
2944c0a134eSVladimir Kondratyev  * such a way that the sum of the squared distances is minimal.  Using
2954c0a134eSVladimir Kondratyev  * squares instead of simple distances favours assignments with more uniform
2964c0a134eSVladimir Kondratyev  * distances, and it is faster.
2974c0a134eSVladimir Kondratyev  * Set tracking id to -1 for unassigned (new) points.
2984c0a134eSVladimir Kondratyev  */
2994c0a134eSVladimir Kondratyev void
3004c0a134eSVladimir Kondratyev evdev_mt_match_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt,
3014c0a134eSVladimir Kondratyev     int size)
3024c0a134eSVladimir Kondratyev {
3034c0a134eSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
3044c0a134eSVladimir Kondratyev 	int i, j, m, n, dx, dy, slot, num_touches;
3054c0a134eSVladimir Kondratyev 	int *p, *r2c, *c2r;
3064c0a134eSVladimir Kondratyev 
3074c0a134eSVladimir Kondratyev 	EVDEV_LOCK_ASSERT(evdev);
3084c0a134eSVladimir Kondratyev 	MPASS(mt->matrix != NULL);
3094c0a134eSVladimir Kondratyev 	MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
3104c0a134eSVladimir Kondratyev 
3114c0a134eSVladimir Kondratyev 	if (size == 0)
3124c0a134eSVladimir Kondratyev 		return;
3134c0a134eSVladimir Kondratyev 
3144c0a134eSVladimir Kondratyev 	p = mt->matrix;
3154c0a134eSVladimir Kondratyev 	num_touches = bitcount(mt->touches);
3164c0a134eSVladimir Kondratyev 	if (num_touches >= size) {
3174c0a134eSVladimir Kondratyev 		FOREACHBIT(mt->touches, slot)
3184c0a134eSVladimir Kondratyev 			for (i = 0; i < size; i++) {
3194c0a134eSVladimir Kondratyev 				dx = pt[i].x - mt->slots[slot].x;
3204c0a134eSVladimir Kondratyev 				dy = pt[i].y - mt->slots[slot].y;
3214c0a134eSVladimir Kondratyev 				*p++ = dx * dx + dy * dy;
3224c0a134eSVladimir Kondratyev 			}
3234c0a134eSVladimir Kondratyev 		m = num_touches;
3244c0a134eSVladimir Kondratyev 		n = size;
3254c0a134eSVladimir Kondratyev 	} else {
3264c0a134eSVladimir Kondratyev 		for (i = 0; i < size; i++)
3274c0a134eSVladimir Kondratyev 			FOREACHBIT(mt->touches, slot) {
3284c0a134eSVladimir Kondratyev 				dx = pt[i].x - mt->slots[slot].x;
3294c0a134eSVladimir Kondratyev 				dy = pt[i].y - mt->slots[slot].y;
3304c0a134eSVladimir Kondratyev 				*p++ = dx * dx + dy * dy;
3314c0a134eSVladimir Kondratyev 			}
3324c0a134eSVladimir Kondratyev 		m = size;
3334c0a134eSVladimir Kondratyev 		n = num_touches;
3344c0a134eSVladimir Kondratyev 	}
3354c0a134eSVladimir Kondratyev 	evdev_mt_matching(mt->matrix, m, n, p);
3364c0a134eSVladimir Kondratyev 
3374c0a134eSVladimir Kondratyev 	r2c = p;
3384c0a134eSVladimir Kondratyev 	c2r = p + m;
3394c0a134eSVladimir Kondratyev 	for (i = 0; i < m; i++)
3404c0a134eSVladimir Kondratyev 		if ((j = r2c[i]) >= 0)
3414c0a134eSVladimir Kondratyev 			c2r[j] = i;
3424c0a134eSVladimir Kondratyev 
3434c0a134eSVladimir Kondratyev 	p = (n == size ? c2r : r2c);
3444c0a134eSVladimir Kondratyev 	for (i = 0; i < size; i++)
3454c0a134eSVladimir Kondratyev 		if (*p++ < 0)
3464c0a134eSVladimir Kondratyev 			pt[i].id = -1;
3474c0a134eSVladimir Kondratyev 
3484c0a134eSVladimir Kondratyev 	p = (n == size ? r2c : c2r);
3494c0a134eSVladimir Kondratyev 	FOREACHBIT(mt->touches, slot)
3504c0a134eSVladimir Kondratyev 		if ((i = *p++) >= 0)
3514c0a134eSVladimir Kondratyev 			pt[i].id = mt->tracking_ids[slot];
3524c0a134eSVladimir Kondratyev }
3534c0a134eSVladimir Kondratyev 
3544c0a134eSVladimir Kondratyev static void
3554c0a134eSVladimir Kondratyev evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size)
3564c0a134eSVladimir Kondratyev {
3574c0a134eSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
3584c0a134eSVladimir Kondratyev 	union evdev_mt_slot *slot;
3594c0a134eSVladimir Kondratyev 
3604c0a134eSVladimir Kondratyev 	EVDEV_LOCK_ASSERT(evdev);
3614c0a134eSVladimir Kondratyev 	MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
3624c0a134eSVladimir Kondratyev 
3634c0a134eSVladimir Kondratyev 	/*
3644c0a134eSVladimir Kondratyev 	 * While MT-matching assign tracking IDs of new contacts to be equal
3654c0a134eSVladimir Kondratyev 	 * to a slot number to make things simpler.
3664c0a134eSVladimir Kondratyev 	 */
3674c0a134eSVladimir Kondratyev 	for (slot = pt; slot < pt + size; slot++) {
3684c0a134eSVladimir Kondratyev 		if (slot->id < 0)
3694c0a134eSVladimir Kondratyev 			slot->id = ffc_slot(evdev, mt->touches | mt->frame);
3704c0a134eSVladimir Kondratyev 		if (slot->id >= 0)
3714c0a134eSVladimir Kondratyev 			evdev_mt_send_slot(evdev, slot->id, slot);
3724c0a134eSVladimir Kondratyev 	}
3734c0a134eSVladimir Kondratyev }
3744c0a134eSVladimir Kondratyev 
3754c0a134eSVladimir Kondratyev int
3764c0a134eSVladimir Kondratyev evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size)
3774c0a134eSVladimir Kondratyev {
3784c0a134eSVladimir Kondratyev 	if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1)
3794c0a134eSVladimir Kondratyev 		return (EINVAL);
3804c0a134eSVladimir Kondratyev 
3814c0a134eSVladimir Kondratyev 	EVDEV_ENTER(evdev);
3824c0a134eSVladimir Kondratyev 	evdev_mt_send_frame(evdev, pt, size);
3834c0a134eSVladimir Kondratyev 	EVDEV_EXIT(evdev);
3844c0a134eSVladimir Kondratyev 
3854c0a134eSVladimir Kondratyev 	return (0);
3864c0a134eSVladimir Kondratyev }
3874c0a134eSVladimir Kondratyev 
388*f76051c7SVladimir Kondratyev bool
389*f76051c7SVladimir Kondratyev evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
390*f76051c7SVladimir Kondratyev     int32_t value)
391*f76051c7SVladimir Kondratyev {
392*f76051c7SVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
393*f76051c7SVladimir Kondratyev 
394*f76051c7SVladimir Kondratyev 	EVDEV_LOCK_ASSERT(evdev);
395*f76051c7SVladimir Kondratyev 
396*f76051c7SVladimir Kondratyev 	switch (type) {
397*f76051c7SVladimir Kondratyev 	case EV_ABS:
398*f76051c7SVladimir Kondratyev 		if (code == ABS_MT_SLOT) {
399*f76051c7SVladimir Kondratyev 			/* MT protocol type B support */
400*f76051c7SVladimir Kondratyev 			KASSERT(value >= 0, ("Negative slot number"));
401*f76051c7SVladimir Kondratyev 			mt->match_slot = value;
402*f76051c7SVladimir Kondratyev 			mt->match_frame |= 1U << mt->match_slot;
403*f76051c7SVladimir Kondratyev 			return (true);
404*f76051c7SVladimir Kondratyev 		} else if (code == ABS_MT_TRACKING_ID) {
405*f76051c7SVladimir Kondratyev 			if (value == -1)
406*f76051c7SVladimir Kondratyev 				mt->match_frame &= ~(1U << mt->match_slot);
407*f76051c7SVladimir Kondratyev 			return (true);
408*f76051c7SVladimir Kondratyev 		} else if (ABS_IS_MT(code)) {
409*f76051c7SVladimir Kondratyev 			KASSERT(mt->match_slot >= 0, ("Negative slot"));
410*f76051c7SVladimir Kondratyev 			KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev),
411*f76051c7SVladimir Kondratyev 			    ("Slot number too big"));
412*f76051c7SVladimir Kondratyev 			mt->match_slots[mt->match_slot].
413*f76051c7SVladimir Kondratyev 			    val[ABS_MT_INDEX(code)] = value;
414*f76051c7SVladimir Kondratyev 			return (true);
415*f76051c7SVladimir Kondratyev 		}
416*f76051c7SVladimir Kondratyev 		break;
417*f76051c7SVladimir Kondratyev 	default:
418*f76051c7SVladimir Kondratyev 		break;
419*f76051c7SVladimir Kondratyev 	}
420*f76051c7SVladimir Kondratyev 
421*f76051c7SVladimir Kondratyev 	return (false);
422*f76051c7SVladimir Kondratyev }
423*f76051c7SVladimir Kondratyev 
424*f76051c7SVladimir Kondratyev static void
425*f76051c7SVladimir Kondratyev evdev_mt_replay_events(struct evdev_dev *evdev)
426*f76051c7SVladimir Kondratyev {
427*f76051c7SVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
428*f76051c7SVladimir Kondratyev 	int slot, size = 0;
429*f76051c7SVladimir Kondratyev 
430*f76051c7SVladimir Kondratyev 	EVDEV_LOCK_ASSERT(evdev);
431*f76051c7SVladimir Kondratyev 
432*f76051c7SVladimir Kondratyev 	FOREACHBIT(mt->match_frame, slot) {
433*f76051c7SVladimir Kondratyev 		if (slot != size)
434*f76051c7SVladimir Kondratyev 			mt->match_slots[size] = mt->match_slots[slot];
435*f76051c7SVladimir Kondratyev 		size++;
436*f76051c7SVladimir Kondratyev 	}
437*f76051c7SVladimir Kondratyev 	evdev_mt_match_frame(evdev, mt->match_slots, size);
438*f76051c7SVladimir Kondratyev 	evdev_mt_send_frame(evdev, mt->match_slots, size);
439*f76051c7SVladimir Kondratyev 	mt->match_slot = 0;
440*f76051c7SVladimir Kondratyev 	mt->match_frame = 0;
441*f76051c7SVladimir Kondratyev }
442*f76051c7SVladimir Kondratyev 
443*f76051c7SVladimir Kondratyev union evdev_mt_slot *
444*f76051c7SVladimir Kondratyev evdev_mt_get_match_slots(struct evdev_dev *evdev)
445*f76051c7SVladimir Kondratyev {
446*f76051c7SVladimir Kondratyev 	return (evdev->ev_mt->match_slots);
447*f76051c7SVladimir Kondratyev }
448*f76051c7SVladimir Kondratyev 
44998a7606bSVladimir Kondratyev int
45098a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev)
45198a7606bSVladimir Kondratyev {
45298a7606bSVladimir Kondratyev 	return (evdev->ev_mt->last_reported_slot);
4532b3f6d66SOleksandr Tymoshenko }
4542b3f6d66SOleksandr Tymoshenko 
4552b3f6d66SOleksandr Tymoshenko void
45698a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot)
4572b3f6d66SOleksandr Tymoshenko {
45898a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
4592b3f6d66SOleksandr Tymoshenko 
46098a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
4612b3f6d66SOleksandr Tymoshenko 
4622dc7188eSVladimir Kondratyev 	mt->frame |= 1U << slot;
46398a7606bSVladimir Kondratyev 	mt->last_reported_slot = slot;
4642b3f6d66SOleksandr Tymoshenko }
4652b3f6d66SOleksandr Tymoshenko 
4662b3f6d66SOleksandr Tymoshenko int32_t
46798a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code)
46898a7606bSVladimir Kondratyev {
46998a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
47098a7606bSVladimir Kondratyev 
47198a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
47298a7606bSVladimir Kondratyev 
47398a7606bSVladimir Kondratyev 	return (mt->slots[slot].val[ABS_MT_INDEX(code)]);
47498a7606bSVladimir Kondratyev }
47598a7606bSVladimir Kondratyev 
47698a7606bSVladimir Kondratyev void
47798a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code,
47898a7606bSVladimir Kondratyev     int32_t value)
47998a7606bSVladimir Kondratyev {
48098a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
48198a7606bSVladimir Kondratyev 
48298a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
48398a7606bSVladimir Kondratyev 
4842dc7188eSVladimir Kondratyev 	if (code == ABS_MT_TRACKING_ID) {
4852dc7188eSVladimir Kondratyev 		if (value != -1)
4862dc7188eSVladimir Kondratyev 			mt->touches |= 1U << slot;
4872dc7188eSVladimir Kondratyev 		else
4882dc7188eSVladimir Kondratyev 			mt->touches &= ~(1U << slot);
4892dc7188eSVladimir Kondratyev 	}
49098a7606bSVladimir Kondratyev 	mt->slots[slot].val[ABS_MT_INDEX(code)] = value;
49198a7606bSVladimir Kondratyev }
49298a7606bSVladimir Kondratyev 
49398a7606bSVladimir Kondratyev int
4942b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
4952b3f6d66SOleksandr Tymoshenko {
49698a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
4972dc7188eSVladimir Kondratyev 	int slot;
4982b3f6d66SOleksandr Tymoshenko 
499*f76051c7SVladimir Kondratyev 	/*
500*f76051c7SVladimir Kondratyev 	 * Ignore tracking_id if slot assignment is performed by evdev.
501*f76051c7SVladimir Kondratyev 	 * Events are written sequentially to temporary matching buffer.
502*f76051c7SVladimir Kondratyev 	 */
503*f76051c7SVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK))
504*f76051c7SVladimir Kondratyev 		return (ffc_slot(evdev, mt->match_frame));
505*f76051c7SVladimir Kondratyev 
5062dc7188eSVladimir Kondratyev 	FOREACHBIT(mt->touches, slot)
50766bd52f5SVladimir Kondratyev 		if (mt->tracking_ids[slot] == tracking_id)
5082b3f6d66SOleksandr Tymoshenko 			return (slot);
5092b3f6d66SOleksandr Tymoshenko 	/*
5102dc7188eSVladimir Kondratyev 	 * Do not allow allocation of new slot in a place of just
5112dc7188eSVladimir Kondratyev 	 * released one within the same report.
5122b3f6d66SOleksandr Tymoshenko 	 */
5132dc7188eSVladimir Kondratyev 	return (ffc_slot(evdev, mt->touches | mt->frame));
5142b3f6d66SOleksandr Tymoshenko }
5152b3f6d66SOleksandr Tymoshenko 
51666bd52f5SVladimir Kondratyev int32_t
51766bd52f5SVladimir Kondratyev evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id)
51866bd52f5SVladimir Kondratyev {
51966bd52f5SVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
52066bd52f5SVladimir Kondratyev 	int32_t nid;
52166bd52f5SVladimir Kondratyev 
52266bd52f5SVladimir Kondratyev 	if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) {
52366bd52f5SVladimir Kondratyev 		mt->tracking_ids[slot] = id;
52466bd52f5SVladimir Kondratyev 		return (id);
52566bd52f5SVladimir Kondratyev 	}
52666bd52f5SVladimir Kondratyev 
52766bd52f5SVladimir Kondratyev 	nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID);
52866bd52f5SVladimir Kondratyev 	if (nid != -1) {
52966bd52f5SVladimir Kondratyev 		KASSERT(id == mt->tracking_ids[slot],
53066bd52f5SVladimir Kondratyev 		    ("MT-slot tracking id has changed"));
53166bd52f5SVladimir Kondratyev 		return (nid);
53266bd52f5SVladimir Kondratyev 	}
53366bd52f5SVladimir Kondratyev 
53466bd52f5SVladimir Kondratyev 	mt->tracking_ids[slot] = id;
53566bd52f5SVladimir Kondratyev again:
53666bd52f5SVladimir Kondratyev 	nid = mt->tracking_id++;
53766bd52f5SVladimir Kondratyev 	FOREACHBIT(mt->touches, slot)
53866bd52f5SVladimir Kondratyev 		if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid)
53966bd52f5SVladimir Kondratyev 			goto again;
54066bd52f5SVladimir Kondratyev 
54166bd52f5SVladimir Kondratyev 	return (nid);
54266bd52f5SVladimir Kondratyev }
54366bd52f5SVladimir Kondratyev 
544127e54deSVladimir Kondratyev static inline int32_t
545127e54deSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax)
546127e54deSVladimir Kondratyev {
547127e54deSVladimir Kondratyev 	if (stmax != 0 && mtmax != mtmin) {
548127e54deSVladimir Kondratyev 		value = (value - mtmin) * stmax / (mtmax - mtmin);
549127e54deSVladimir Kondratyev 		value = MAX(MIN(value, stmax), 0);
550127e54deSVladimir Kondratyev 	}
551127e54deSVladimir Kondratyev 	return (value);
552127e54deSVladimir Kondratyev }
553127e54deSVladimir Kondratyev 
5542b3f6d66SOleksandr Tymoshenko void
5552b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev)
5562b3f6d66SOleksandr Tymoshenko {
557127e54deSVladimir Kondratyev 	struct input_absinfo *ai;
55898a7606bSVladimir Kondratyev 	int i;
5592b3f6d66SOleksandr Tymoshenko 
5602b3f6d66SOleksandr Tymoshenko 	if (evdev->ev_absinfo == NULL)
5612b3f6d66SOleksandr Tymoshenko 		return;
5622b3f6d66SOleksandr Tymoshenko 
5632b3f6d66SOleksandr Tymoshenko 	evdev_support_event(evdev, EV_KEY);
5642b3f6d66SOleksandr Tymoshenko 	evdev_support_key(evdev, BTN_TOUCH);
5652b3f6d66SOleksandr Tymoshenko 
5662b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not advertise tap tool capabilities */
5672b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
5682b3f6d66SOleksandr Tymoshenko 		evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
5692b3f6d66SOleksandr Tymoshenko 
5702b3f6d66SOleksandr Tymoshenko 	/* Echo 0-th MT-slot as ST-slot */
571127e54deSVladimir Kondratyev 	for (i = 0; i < nitems(evdev_mtstmap); i++) {
572127e54deSVladimir Kondratyev 		if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) ||
573127e54deSVladimir Kondratyev 		     bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st))
574127e54deSVladimir Kondratyev 			continue;
575127e54deSVladimir Kondratyev 		ai = evdev->ev_absinfo + evdev_mtstmap[i].mt;
576127e54deSVladimir Kondratyev 		evdev->ev_mt->mtst_events |= 1U << i;
577127e54deSVladimir Kondratyev 		if (evdev_mtstmap[i].max != 0)
578127e54deSVladimir Kondratyev 			evdev_support_abs(evdev, evdev_mtstmap[i].st,
579314913edSVladimir Kondratyev 			    0,
580127e54deSVladimir Kondratyev 			    evdev_mtstmap[i].max,
581127e54deSVladimir Kondratyev 			    0,
582127e54deSVladimir Kondratyev 			    evdev_mt_normalize(
583127e54deSVladimir Kondratyev 			      ai->flat, 0, ai->maximum, evdev_mtstmap[i].max),
584127e54deSVladimir Kondratyev 			    0);
585127e54deSVladimir Kondratyev 		else
586127e54deSVladimir Kondratyev 			evdev_support_abs(evdev, evdev_mtstmap[i].st,
587127e54deSVladimir Kondratyev 			    ai->minimum,
588127e54deSVladimir Kondratyev 			    ai->maximum,
589127e54deSVladimir Kondratyev 			    0,
590127e54deSVladimir Kondratyev 			    ai->flat,
591127e54deSVladimir Kondratyev 			    ai->resolution);
592127e54deSVladimir Kondratyev 	}
5932b3f6d66SOleksandr Tymoshenko }
5942b3f6d66SOleksandr Tymoshenko 
5952b3f6d66SOleksandr Tymoshenko static void
59698a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev)
5972b3f6d66SOleksandr Tymoshenko {
5982dc7188eSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
599fbe17f90SVladimir Kondratyev 	int nfingers, i, st_slot;
6002b3f6d66SOleksandr Tymoshenko 
6012b3f6d66SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
6022b3f6d66SOleksandr Tymoshenko 
6032dc7188eSVladimir Kondratyev 	nfingers = bitcount(mt->touches);
6042b3f6d66SOleksandr Tymoshenko 	evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
6052b3f6d66SOleksandr Tymoshenko 
606fbe17f90SVladimir Kondratyev 	/* Send first active MT-slot state as single touch report */
607fbe17f90SVladimir Kondratyev 	st_slot = ffs(mt->touches) - 1;
608fbe17f90SVladimir Kondratyev 	if (st_slot != -1)
609127e54deSVladimir Kondratyev 		FOREACHBIT(mt->mtst_events, i)
610127e54deSVladimir Kondratyev 			evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st,
611127e54deSVladimir Kondratyev 			    evdev_mt_normalize(evdev_mt_get_value(evdev,
612127e54deSVladimir Kondratyev 			      st_slot, evdev_mtstmap[i].mt),
613127e54deSVladimir Kondratyev 			      evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum,
614127e54deSVladimir Kondratyev 			      evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum,
615127e54deSVladimir Kondratyev 			      evdev_mtstmap[i].max));
6162b3f6d66SOleksandr Tymoshenko 
6172b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not report tool taps */
6182b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
6192b3f6d66SOleksandr Tymoshenko 		evdev_send_nfingers(evdev, nfingers);
6202b3f6d66SOleksandr Tymoshenko 
6212b3f6d66SOleksandr Tymoshenko 	if (nfingers == 0)
6222b3f6d66SOleksandr Tymoshenko 		evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
6232b3f6d66SOleksandr Tymoshenko }
6242b3f6d66SOleksandr Tymoshenko 
6252b3f6d66SOleksandr Tymoshenko void
6262b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev)
6272b3f6d66SOleksandr Tymoshenko {
6282b3f6d66SOleksandr Tymoshenko 
6294c0a4665SVladimir Kondratyev 	EVDEV_ENTER(evdev);
63098a7606bSVladimir Kondratyev 	evdev_mt_send_st_compat(evdev);
6314c0a4665SVladimir Kondratyev 	EVDEV_EXIT(evdev);
6322b3f6d66SOleksandr Tymoshenko }
633c736a757SOleksandr Tymoshenko 
63498a7606bSVladimir Kondratyev static void
63598a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev)
636c736a757SOleksandr Tymoshenko {
63798a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
63898a7606bSVladimir Kondratyev 	int slot;
639c736a757SOleksandr Tymoshenko 
640c736a757SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
641*f76051c7SVladimir Kondratyev 	KASSERT(mt->match_frame == 0, ("Unmatched events exist"));
642c736a757SOleksandr Tymoshenko 
64305936028SVladimir Kondratyev 	FOREACHBIT(mt->touches & ~mt->frame, slot)
64405936028SVladimir Kondratyev 		evdev_mt_send_slot(evdev, slot, NULL);
645c736a757SOleksandr Tymoshenko }
64698a7606bSVladimir Kondratyev 
64798a7606bSVladimir Kondratyev void
64898a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev)
64998a7606bSVladimir Kondratyev {
65098a7606bSVladimir Kondratyev 	EVDEV_ENTER(evdev);
65198a7606bSVladimir Kondratyev 	evdev_mt_send_autorel(evdev);
65298a7606bSVladimir Kondratyev 	EVDEV_EXIT(evdev);
65398a7606bSVladimir Kondratyev }
654