xref: /freebsd/sys/dev/evdev/evdev_mt.c (revision 66bd52f5e241bd2548015f847f12cdff69176c40)
12b3f6d66SOleksandr Tymoshenko /*-
2e6502802SVladimir Kondratyev  * Copyright (c) 2016 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  */
282b3f6d66SOleksandr Tymoshenko 
292b3f6d66SOleksandr Tymoshenko #include <sys/param.h>
302b3f6d66SOleksandr Tymoshenko #include <sys/lock.h>
31ea2e26b1SVladimir Kondratyev #include <sys/malloc.h>
322b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h>
332b3f6d66SOleksandr Tymoshenko #include <sys/systm.h>
342b3f6d66SOleksandr Tymoshenko 
352b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h>
362b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.h>
37ea2e26b1SVladimir Kondratyev #include <dev/evdev/input.h>
382b3f6d66SOleksandr Tymoshenko 
392b3f6d66SOleksandr Tymoshenko #ifdef DEBUG
402b3f6d66SOleksandr Tymoshenko #define	debugf(fmt, args...)	printf("evdev: " fmt "\n", ##args)
412b3f6d66SOleksandr Tymoshenko #else
422b3f6d66SOleksandr Tymoshenko #define	debugf(fmt, args...)
432b3f6d66SOleksandr Tymoshenko #endif
442b3f6d66SOleksandr Tymoshenko 
452dc7188eSVladimir Kondratyev typedef	u_int	slotset_t;
462dc7188eSVladimir Kondratyev 
472dc7188eSVladimir Kondratyev _Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big");
482dc7188eSVladimir Kondratyev 
492dc7188eSVladimir Kondratyev #define FOREACHBIT(v, i) \
502dc7188eSVladimir Kondratyev 	for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1)
512dc7188eSVladimir Kondratyev 
52127e54deSVladimir Kondratyev struct {
53127e54deSVladimir Kondratyev 	uint16_t	mt;
54127e54deSVladimir Kondratyev 	uint16_t	st;
55127e54deSVladimir Kondratyev 	int32_t		max;
56127e54deSVladimir Kondratyev } static evdev_mtstmap[] = {
57127e54deSVladimir Kondratyev 	{ ABS_MT_POSITION_X,	ABS_X,		0 },
58127e54deSVladimir Kondratyev 	{ ABS_MT_POSITION_Y,	ABS_Y,		0 },
59127e54deSVladimir Kondratyev 	{ ABS_MT_PRESSURE,	ABS_PRESSURE,	255 },
60127e54deSVladimir Kondratyev 	{ ABS_MT_TOUCH_MAJOR,	ABS_TOOL_WIDTH,	15 },
612b3f6d66SOleksandr Tymoshenko };
622b3f6d66SOleksandr Tymoshenko 
632b3f6d66SOleksandr Tymoshenko struct evdev_mt {
6498a7606bSVladimir Kondratyev 	int			last_reported_slot;
65*66bd52f5SVladimir Kondratyev 	uint16_t		tracking_id;
66*66bd52f5SVladimir Kondratyev 	int32_t			tracking_ids[MAX_MT_SLOTS];
67127e54deSVladimir Kondratyev 	u_int			mtst_events;
682dc7188eSVladimir Kondratyev 	/* the set of slots with active touches */
692dc7188eSVladimir Kondratyev 	slotset_t		touches;
702dc7188eSVladimir Kondratyev 	/* the set of slots with unsynchronized state */
712dc7188eSVladimir Kondratyev 	slotset_t		frame;
7205936028SVladimir Kondratyev 	union evdev_mt_slot	slots[];
732b3f6d66SOleksandr Tymoshenko };
742b3f6d66SOleksandr Tymoshenko 
7598a7606bSVladimir Kondratyev static void	evdev_mt_send_st_compat(struct evdev_dev *);
7698a7606bSVladimir Kondratyev static void	evdev_mt_send_autorel(struct evdev_dev *);
7798a7606bSVladimir Kondratyev 
782dc7188eSVladimir Kondratyev static inline int
792dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots)
802dc7188eSVladimir Kondratyev {
812dc7188eSVladimir Kondratyev 	return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1);
822dc7188eSVladimir Kondratyev }
832dc7188eSVladimir Kondratyev 
842b3f6d66SOleksandr Tymoshenko void
852b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev)
862b3f6d66SOleksandr Tymoshenko {
8798a7606bSVladimir Kondratyev 	int slot, slots;
882b3f6d66SOleksandr Tymoshenko 
892b3f6d66SOleksandr Tymoshenko 	slots = MAXIMAL_MT_SLOT(evdev) + 1;
902b3f6d66SOleksandr Tymoshenko 
9198a7606bSVladimir Kondratyev 	evdev->ev_mt = malloc(offsetof(struct evdev_mt, slots) +
9205936028SVladimir Kondratyev 	     sizeof(union evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
932b3f6d66SOleksandr Tymoshenko 
942b3f6d66SOleksandr Tymoshenko 	/* Initialize multitouch protocol type B states */
952dc7188eSVladimir Kondratyev 	for (slot = 0; slot < slots; slot++)
9605936028SVladimir Kondratyev 		evdev->ev_mt->slots[slot].id = -1;
972b3f6d66SOleksandr Tymoshenko 
98*66bd52f5SVladimir Kondratyev 	if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID))
99*66bd52f5SVladimir Kondratyev 		evdev_support_abs(evdev,
100*66bd52f5SVladimir Kondratyev 		    ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0);
1012b3f6d66SOleksandr Tymoshenko 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
1022b3f6d66SOleksandr Tymoshenko 		evdev_support_mt_compat(evdev);
1032b3f6d66SOleksandr Tymoshenko }
1042b3f6d66SOleksandr Tymoshenko 
1052b3f6d66SOleksandr Tymoshenko void
1062b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev)
1072b3f6d66SOleksandr Tymoshenko {
1082b3f6d66SOleksandr Tymoshenko 	free(evdev->ev_mt, M_EVDEV);
1092b3f6d66SOleksandr Tymoshenko }
1102b3f6d66SOleksandr Tymoshenko 
11198a7606bSVladimir Kondratyev void
11298a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev)
1132b3f6d66SOleksandr Tymoshenko {
11498a7606bSVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
11598a7606bSVladimir Kondratyev 		evdev_mt_send_autorel(evdev);
11698a7606bSVladimir Kondratyev 	if (evdev->ev_report_opened &&
11798a7606bSVladimir Kondratyev 	    bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
11898a7606bSVladimir Kondratyev 		evdev_mt_send_st_compat(evdev);
1192dc7188eSVladimir Kondratyev 	evdev->ev_mt->frame = 0;
12098a7606bSVladimir Kondratyev }
1212b3f6d66SOleksandr Tymoshenko 
12205936028SVladimir Kondratyev static void
12305936028SVladimir Kondratyev evdev_mt_send_slot(struct evdev_dev *evdev, int slot,
12405936028SVladimir Kondratyev     union evdev_mt_slot *state)
12505936028SVladimir Kondratyev {
12605936028SVladimir Kondratyev 	int i;
12705936028SVladimir Kondratyev 	bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
12805936028SVladimir Kondratyev 
12905936028SVladimir Kondratyev 	EVDEV_LOCK_ASSERT(evdev);
13005936028SVladimir Kondratyev 	MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)));
13105936028SVladimir Kondratyev 	MPASS(!type_a || state != NULL);
13205936028SVladimir Kondratyev 
13305936028SVladimir Kondratyev 	if (!type_a) {
13405936028SVladimir Kondratyev 		evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
13505936028SVladimir Kondratyev 		if (state == NULL) {
13605936028SVladimir Kondratyev 			evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1);
13705936028SVladimir Kondratyev 			return;
13805936028SVladimir Kondratyev 		}
13905936028SVladimir Kondratyev 	}
14005936028SVladimir Kondratyev 	bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i)
14105936028SVladimir Kondratyev 		evdev_send_event(evdev, EV_ABS, i,
14205936028SVladimir Kondratyev 		    state->val[ABS_MT_INDEX(i)]);
14305936028SVladimir Kondratyev 	if (type_a)
14405936028SVladimir Kondratyev 		evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
14505936028SVladimir Kondratyev }
14605936028SVladimir Kondratyev 
14705936028SVladimir Kondratyev int
14805936028SVladimir Kondratyev evdev_mt_push_slot(struct evdev_dev *evdev, int slot,
14905936028SVladimir Kondratyev     union evdev_mt_slot *state)
15005936028SVladimir Kondratyev {
15105936028SVladimir Kondratyev 	bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
15205936028SVladimir Kondratyev 
15305936028SVladimir Kondratyev 	if (type_a && state == NULL)
15405936028SVladimir Kondratyev 		return (EINVAL);
15505936028SVladimir Kondratyev 	if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev)))
15605936028SVladimir Kondratyev 		return (EINVAL);
15705936028SVladimir Kondratyev 
15805936028SVladimir Kondratyev 	EVDEV_ENTER(evdev);
15905936028SVladimir Kondratyev 	evdev_mt_send_slot(evdev, slot, state);
16005936028SVladimir Kondratyev 	EVDEV_EXIT(evdev);
16105936028SVladimir Kondratyev 
16205936028SVladimir Kondratyev 	return (0);
16305936028SVladimir Kondratyev }
16405936028SVladimir Kondratyev 
16598a7606bSVladimir Kondratyev int
16698a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev)
16798a7606bSVladimir Kondratyev {
16898a7606bSVladimir Kondratyev 	return (evdev->ev_mt->last_reported_slot);
1692b3f6d66SOleksandr Tymoshenko }
1702b3f6d66SOleksandr Tymoshenko 
1712b3f6d66SOleksandr Tymoshenko void
17298a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot)
1732b3f6d66SOleksandr Tymoshenko {
17498a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
1752b3f6d66SOleksandr Tymoshenko 
17698a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
1772b3f6d66SOleksandr Tymoshenko 
1782dc7188eSVladimir Kondratyev 	mt->frame |= 1U << slot;
17998a7606bSVladimir Kondratyev 	mt->last_reported_slot = slot;
1802b3f6d66SOleksandr Tymoshenko }
1812b3f6d66SOleksandr Tymoshenko 
1822b3f6d66SOleksandr Tymoshenko int32_t
18398a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code)
18498a7606bSVladimir Kondratyev {
18598a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
18698a7606bSVladimir Kondratyev 
18798a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
18898a7606bSVladimir Kondratyev 
18998a7606bSVladimir Kondratyev 	return (mt->slots[slot].val[ABS_MT_INDEX(code)]);
19098a7606bSVladimir Kondratyev }
19198a7606bSVladimir Kondratyev 
19298a7606bSVladimir Kondratyev void
19398a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code,
19498a7606bSVladimir Kondratyev     int32_t value)
19598a7606bSVladimir Kondratyev {
19698a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
19798a7606bSVladimir Kondratyev 
19898a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
19998a7606bSVladimir Kondratyev 
2002dc7188eSVladimir Kondratyev 	if (code == ABS_MT_TRACKING_ID) {
2012dc7188eSVladimir Kondratyev 		if (value != -1)
2022dc7188eSVladimir Kondratyev 			mt->touches |= 1U << slot;
2032dc7188eSVladimir Kondratyev 		else
2042dc7188eSVladimir Kondratyev 			mt->touches &= ~(1U << slot);
2052dc7188eSVladimir Kondratyev 	}
20698a7606bSVladimir Kondratyev 	mt->slots[slot].val[ABS_MT_INDEX(code)] = value;
20798a7606bSVladimir Kondratyev }
20898a7606bSVladimir Kondratyev 
20998a7606bSVladimir Kondratyev int
2102b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
2112b3f6d66SOleksandr Tymoshenko {
21298a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
2132dc7188eSVladimir Kondratyev 	int slot;
2142b3f6d66SOleksandr Tymoshenko 
2152dc7188eSVladimir Kondratyev 	FOREACHBIT(mt->touches, slot)
216*66bd52f5SVladimir Kondratyev 		if (mt->tracking_ids[slot] == tracking_id)
2172b3f6d66SOleksandr Tymoshenko 			return (slot);
2182b3f6d66SOleksandr Tymoshenko 	/*
2192dc7188eSVladimir Kondratyev 	 * Do not allow allocation of new slot in a place of just
2202dc7188eSVladimir Kondratyev 	 * released one within the same report.
2212b3f6d66SOleksandr Tymoshenko 	 */
2222dc7188eSVladimir Kondratyev 	return (ffc_slot(evdev, mt->touches | mt->frame));
2232b3f6d66SOleksandr Tymoshenko }
2242b3f6d66SOleksandr Tymoshenko 
225*66bd52f5SVladimir Kondratyev int32_t
226*66bd52f5SVladimir Kondratyev evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id)
227*66bd52f5SVladimir Kondratyev {
228*66bd52f5SVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
229*66bd52f5SVladimir Kondratyev 	int32_t nid;
230*66bd52f5SVladimir Kondratyev 
231*66bd52f5SVladimir Kondratyev 	if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) {
232*66bd52f5SVladimir Kondratyev 		mt->tracking_ids[slot] = id;
233*66bd52f5SVladimir Kondratyev 		return (id);
234*66bd52f5SVladimir Kondratyev 	}
235*66bd52f5SVladimir Kondratyev 
236*66bd52f5SVladimir Kondratyev 	nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID);
237*66bd52f5SVladimir Kondratyev 	if (nid != -1) {
238*66bd52f5SVladimir Kondratyev 		KASSERT(id == mt->tracking_ids[slot],
239*66bd52f5SVladimir Kondratyev 		    ("MT-slot tracking id has changed"));
240*66bd52f5SVladimir Kondratyev 		return (nid);
241*66bd52f5SVladimir Kondratyev 	}
242*66bd52f5SVladimir Kondratyev 
243*66bd52f5SVladimir Kondratyev 	mt->tracking_ids[slot] = id;
244*66bd52f5SVladimir Kondratyev again:
245*66bd52f5SVladimir Kondratyev 	nid = mt->tracking_id++;
246*66bd52f5SVladimir Kondratyev 	FOREACHBIT(mt->touches, slot)
247*66bd52f5SVladimir Kondratyev 		if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid)
248*66bd52f5SVladimir Kondratyev 			goto again;
249*66bd52f5SVladimir Kondratyev 
250*66bd52f5SVladimir Kondratyev 	return (nid);
251*66bd52f5SVladimir Kondratyev }
252*66bd52f5SVladimir Kondratyev 
253127e54deSVladimir Kondratyev static inline int32_t
254127e54deSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax)
255127e54deSVladimir Kondratyev {
256127e54deSVladimir Kondratyev 	if (stmax != 0 && mtmax != mtmin) {
257127e54deSVladimir Kondratyev 		value = (value - mtmin) * stmax / (mtmax - mtmin);
258127e54deSVladimir Kondratyev 		value = MAX(MIN(value, stmax), 0);
259127e54deSVladimir Kondratyev 	}
260127e54deSVladimir Kondratyev 	return (value);
261127e54deSVladimir Kondratyev }
262127e54deSVladimir Kondratyev 
2632b3f6d66SOleksandr Tymoshenko void
2642b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev)
2652b3f6d66SOleksandr Tymoshenko {
266127e54deSVladimir Kondratyev 	struct input_absinfo *ai;
26798a7606bSVladimir Kondratyev 	int i;
2682b3f6d66SOleksandr Tymoshenko 
2692b3f6d66SOleksandr Tymoshenko 	if (evdev->ev_absinfo == NULL)
2702b3f6d66SOleksandr Tymoshenko 		return;
2712b3f6d66SOleksandr Tymoshenko 
2722b3f6d66SOleksandr Tymoshenko 	evdev_support_event(evdev, EV_KEY);
2732b3f6d66SOleksandr Tymoshenko 	evdev_support_key(evdev, BTN_TOUCH);
2742b3f6d66SOleksandr Tymoshenko 
2752b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not advertise tap tool capabilities */
2762b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
2772b3f6d66SOleksandr Tymoshenko 		evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
2782b3f6d66SOleksandr Tymoshenko 
2792b3f6d66SOleksandr Tymoshenko 	/* Echo 0-th MT-slot as ST-slot */
280127e54deSVladimir Kondratyev 	for (i = 0; i < nitems(evdev_mtstmap); i++) {
281127e54deSVladimir Kondratyev 		if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) ||
282127e54deSVladimir Kondratyev 		     bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st))
283127e54deSVladimir Kondratyev 			continue;
284127e54deSVladimir Kondratyev 		ai = evdev->ev_absinfo + evdev_mtstmap[i].mt;
285127e54deSVladimir Kondratyev 		evdev->ev_mt->mtst_events |= 1U << i;
286127e54deSVladimir Kondratyev 		if (evdev_mtstmap[i].max != 0)
287127e54deSVladimir Kondratyev 			evdev_support_abs(evdev, evdev_mtstmap[i].st,
288314913edSVladimir Kondratyev 			    0,
289127e54deSVladimir Kondratyev 			    evdev_mtstmap[i].max,
290127e54deSVladimir Kondratyev 			    0,
291127e54deSVladimir Kondratyev 			    evdev_mt_normalize(
292127e54deSVladimir Kondratyev 			      ai->flat, 0, ai->maximum, evdev_mtstmap[i].max),
293127e54deSVladimir Kondratyev 			    0);
294127e54deSVladimir Kondratyev 		else
295127e54deSVladimir Kondratyev 			evdev_support_abs(evdev, evdev_mtstmap[i].st,
296127e54deSVladimir Kondratyev 			    ai->minimum,
297127e54deSVladimir Kondratyev 			    ai->maximum,
298127e54deSVladimir Kondratyev 			    0,
299127e54deSVladimir Kondratyev 			    ai->flat,
300127e54deSVladimir Kondratyev 			    ai->resolution);
301127e54deSVladimir Kondratyev 	}
3022b3f6d66SOleksandr Tymoshenko }
3032b3f6d66SOleksandr Tymoshenko 
3042b3f6d66SOleksandr Tymoshenko static void
30598a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev)
3062b3f6d66SOleksandr Tymoshenko {
3072dc7188eSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
308fbe17f90SVladimir Kondratyev 	int nfingers, i, st_slot;
3092b3f6d66SOleksandr Tymoshenko 
3102b3f6d66SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
3112b3f6d66SOleksandr Tymoshenko 
3122dc7188eSVladimir Kondratyev 	nfingers = bitcount(mt->touches);
3132b3f6d66SOleksandr Tymoshenko 	evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
3142b3f6d66SOleksandr Tymoshenko 
315fbe17f90SVladimir Kondratyev 	/* Send first active MT-slot state as single touch report */
316fbe17f90SVladimir Kondratyev 	st_slot = ffs(mt->touches) - 1;
317fbe17f90SVladimir Kondratyev 	if (st_slot != -1)
318127e54deSVladimir Kondratyev 		FOREACHBIT(mt->mtst_events, i)
319127e54deSVladimir Kondratyev 			evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st,
320127e54deSVladimir Kondratyev 			    evdev_mt_normalize(evdev_mt_get_value(evdev,
321127e54deSVladimir Kondratyev 			      st_slot, evdev_mtstmap[i].mt),
322127e54deSVladimir Kondratyev 			      evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum,
323127e54deSVladimir Kondratyev 			      evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum,
324127e54deSVladimir Kondratyev 			      evdev_mtstmap[i].max));
3252b3f6d66SOleksandr Tymoshenko 
3262b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not report tool taps */
3272b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
3282b3f6d66SOleksandr Tymoshenko 		evdev_send_nfingers(evdev, nfingers);
3292b3f6d66SOleksandr Tymoshenko 
3302b3f6d66SOleksandr Tymoshenko 	if (nfingers == 0)
3312b3f6d66SOleksandr Tymoshenko 		evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
3322b3f6d66SOleksandr Tymoshenko }
3332b3f6d66SOleksandr Tymoshenko 
3342b3f6d66SOleksandr Tymoshenko void
3352b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev)
3362b3f6d66SOleksandr Tymoshenko {
3372b3f6d66SOleksandr Tymoshenko 
3384c0a4665SVladimir Kondratyev 	EVDEV_ENTER(evdev);
33998a7606bSVladimir Kondratyev 	evdev_mt_send_st_compat(evdev);
3404c0a4665SVladimir Kondratyev 	EVDEV_EXIT(evdev);
3412b3f6d66SOleksandr Tymoshenko }
342c736a757SOleksandr Tymoshenko 
34398a7606bSVladimir Kondratyev static void
34498a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev)
345c736a757SOleksandr Tymoshenko {
34698a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
34798a7606bSVladimir Kondratyev 	int slot;
348c736a757SOleksandr Tymoshenko 
349c736a757SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
350c736a757SOleksandr Tymoshenko 
35105936028SVladimir Kondratyev 	FOREACHBIT(mt->touches & ~mt->frame, slot)
35205936028SVladimir Kondratyev 		evdev_mt_send_slot(evdev, slot, NULL);
353c736a757SOleksandr Tymoshenko }
35498a7606bSVladimir Kondratyev 
35598a7606bSVladimir Kondratyev void
35698a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev)
35798a7606bSVladimir Kondratyev {
35898a7606bSVladimir Kondratyev 	EVDEV_ENTER(evdev);
35998a7606bSVladimir Kondratyev 	evdev_mt_send_autorel(evdev);
36098a7606bSVladimir Kondratyev 	EVDEV_EXIT(evdev);
36198a7606bSVladimir Kondratyev }
362