xref: /freebsd/sys/dev/evdev/evdev_mt.c (revision c736a757129a1a2c1e8e11d18daa9742f7ec0d35)
12b3f6d66SOleksandr Tymoshenko /*-
22b3f6d66SOleksandr Tymoshenko  * Copyright (c) 2016 Vladimir Kondratyev <wulf@cicgroup.ru>
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/malloc.h>
312b3f6d66SOleksandr Tymoshenko #include <sys/lock.h>
322b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h>
332b3f6d66SOleksandr Tymoshenko #include <sys/systm.h>
342b3f6d66SOleksandr Tymoshenko 
352b3f6d66SOleksandr Tymoshenko #include <dev/evdev/input.h>
362b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h>
372b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.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 
452b3f6d66SOleksandr Tymoshenko static uint16_t evdev_fngmap[] = {
462b3f6d66SOleksandr Tymoshenko 	BTN_TOOL_FINGER,
472b3f6d66SOleksandr Tymoshenko 	BTN_TOOL_DOUBLETAP,
482b3f6d66SOleksandr Tymoshenko 	BTN_TOOL_TRIPLETAP,
492b3f6d66SOleksandr Tymoshenko 	BTN_TOOL_QUADTAP,
502b3f6d66SOleksandr Tymoshenko 	BTN_TOOL_QUINTTAP,
512b3f6d66SOleksandr Tymoshenko };
522b3f6d66SOleksandr Tymoshenko 
532b3f6d66SOleksandr Tymoshenko static uint16_t evdev_mtstmap[][2] = {
542b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_POSITION_X, ABS_X },
552b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_POSITION_Y, ABS_Y },
562b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_PRESSURE, ABS_PRESSURE },
572b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH },
582b3f6d66SOleksandr Tymoshenko };
592b3f6d66SOleksandr Tymoshenko 
602b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot {
612b3f6d66SOleksandr Tymoshenko 	uint64_t ev_report;
622b3f6d66SOleksandr Tymoshenko 	int32_t ev_mt_states[MT_CNT];
632b3f6d66SOleksandr Tymoshenko };
642b3f6d66SOleksandr Tymoshenko 
652b3f6d66SOleksandr Tymoshenko struct evdev_mt {
662b3f6d66SOleksandr Tymoshenko 	int32_t	ev_mt_last_reported_slot;
672b3f6d66SOleksandr Tymoshenko 	struct evdev_mt_slot ev_mt_slots[];
682b3f6d66SOleksandr Tymoshenko };
692b3f6d66SOleksandr Tymoshenko 
702b3f6d66SOleksandr Tymoshenko void
712b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev)
722b3f6d66SOleksandr Tymoshenko {
732b3f6d66SOleksandr Tymoshenko 	int32_t slot, slots;
742b3f6d66SOleksandr Tymoshenko 
752b3f6d66SOleksandr Tymoshenko 	slots = MAXIMAL_MT_SLOT(evdev) + 1;
762b3f6d66SOleksandr Tymoshenko 
772b3f6d66SOleksandr Tymoshenko 	evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) +
782b3f6d66SOleksandr Tymoshenko 	     sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
792b3f6d66SOleksandr Tymoshenko 
802b3f6d66SOleksandr Tymoshenko 	/* Initialize multitouch protocol type B states */
812b3f6d66SOleksandr Tymoshenko 	for (slot = 0; slot < slots; slot++) {
822b3f6d66SOleksandr Tymoshenko 		/*
832b3f6d66SOleksandr Tymoshenko 		 * .ev_report should not be initialized to initial value of
842b3f6d66SOleksandr Tymoshenko 		 * report counter (0) as it brokes free slot detection in
852b3f6d66SOleksandr Tymoshenko 		 * evdev_get_mt_slot_by_tracking_id. So initialize it to -1
862b3f6d66SOleksandr Tymoshenko 		 */
872b3f6d66SOleksandr Tymoshenko 		evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) {
882b3f6d66SOleksandr Tymoshenko 			.ev_report = 0xFFFFFFFFFFFFFFFFULL,
892b3f6d66SOleksandr Tymoshenko 			.ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1,
902b3f6d66SOleksandr Tymoshenko 		};
912b3f6d66SOleksandr Tymoshenko 	}
922b3f6d66SOleksandr Tymoshenko 
932b3f6d66SOleksandr Tymoshenko 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
942b3f6d66SOleksandr Tymoshenko 		evdev_support_mt_compat(evdev);
952b3f6d66SOleksandr Tymoshenko }
962b3f6d66SOleksandr Tymoshenko 
972b3f6d66SOleksandr Tymoshenko void
982b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev)
992b3f6d66SOleksandr Tymoshenko {
1002b3f6d66SOleksandr Tymoshenko 
1012b3f6d66SOleksandr Tymoshenko 	free(evdev->ev_mt, M_EVDEV);
1022b3f6d66SOleksandr Tymoshenko }
1032b3f6d66SOleksandr Tymoshenko 
1042b3f6d66SOleksandr Tymoshenko int32_t
1052b3f6d66SOleksandr Tymoshenko evdev_get_last_mt_slot(struct evdev_dev *evdev)
1062b3f6d66SOleksandr Tymoshenko {
1072b3f6d66SOleksandr Tymoshenko 
1082b3f6d66SOleksandr Tymoshenko 	return (evdev->ev_mt->ev_mt_last_reported_slot);
1092b3f6d66SOleksandr Tymoshenko }
1102b3f6d66SOleksandr Tymoshenko 
1112b3f6d66SOleksandr Tymoshenko void
1122b3f6d66SOleksandr Tymoshenko evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot)
1132b3f6d66SOleksandr Tymoshenko {
1142b3f6d66SOleksandr Tymoshenko 
115*c736a757SOleksandr Tymoshenko 	evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count;
1162b3f6d66SOleksandr Tymoshenko 	evdev->ev_mt->ev_mt_last_reported_slot = slot;
1172b3f6d66SOleksandr Tymoshenko }
1182b3f6d66SOleksandr Tymoshenko 
1192b3f6d66SOleksandr Tymoshenko inline int32_t
1202b3f6d66SOleksandr Tymoshenko evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code)
1212b3f6d66SOleksandr Tymoshenko {
1222b3f6d66SOleksandr Tymoshenko 
1232b3f6d66SOleksandr Tymoshenko 	return (evdev->ev_mt->
1242b3f6d66SOleksandr Tymoshenko 	    ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]);
1252b3f6d66SOleksandr Tymoshenko }
1262b3f6d66SOleksandr Tymoshenko 
1272b3f6d66SOleksandr Tymoshenko inline void
1282b3f6d66SOleksandr Tymoshenko evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code,
1292b3f6d66SOleksandr Tymoshenko     int32_t value)
1302b3f6d66SOleksandr Tymoshenko {
1312b3f6d66SOleksandr Tymoshenko 
1322b3f6d66SOleksandr Tymoshenko 	evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] =
1332b3f6d66SOleksandr Tymoshenko 	    value;
1342b3f6d66SOleksandr Tymoshenko }
1352b3f6d66SOleksandr Tymoshenko 
1362b3f6d66SOleksandr Tymoshenko int32_t
1372b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
1382b3f6d66SOleksandr Tymoshenko {
1392b3f6d66SOleksandr Tymoshenko 	int32_t tr_id, slot, free_slot = -1;
1402b3f6d66SOleksandr Tymoshenko 
1412b3f6d66SOleksandr Tymoshenko 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
1422b3f6d66SOleksandr Tymoshenko 		tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID);
1432b3f6d66SOleksandr Tymoshenko 		if (tr_id == tracking_id)
1442b3f6d66SOleksandr Tymoshenko 			return (slot);
1452b3f6d66SOleksandr Tymoshenko 		/*
1462b3f6d66SOleksandr Tymoshenko 		 * Its possible that slot will be reassigned in a place of just
1472b3f6d66SOleksandr Tymoshenko 		 * released one within the same report. To avoid this compare
1482b3f6d66SOleksandr Tymoshenko 		 * report counter with slot`s report number updated with each
1492b3f6d66SOleksandr Tymoshenko 		 * ABS_MT_TRACKING_ID change.
1502b3f6d66SOleksandr Tymoshenko 		 */
1512b3f6d66SOleksandr Tymoshenko 		if (free_slot == -1 && tr_id == -1 &&
1522b3f6d66SOleksandr Tymoshenko 		    evdev->ev_mt->ev_mt_slots[slot].ev_report !=
1532b3f6d66SOleksandr Tymoshenko 		    evdev->ev_report_count)
1542b3f6d66SOleksandr Tymoshenko 			free_slot = slot;
1552b3f6d66SOleksandr Tymoshenko 	}
1562b3f6d66SOleksandr Tymoshenko 
1572b3f6d66SOleksandr Tymoshenko 	return (free_slot);
1582b3f6d66SOleksandr Tymoshenko }
1592b3f6d66SOleksandr Tymoshenko 
1602b3f6d66SOleksandr Tymoshenko void
1612b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers)
1622b3f6d66SOleksandr Tymoshenko {
1632b3f6d66SOleksandr Tymoshenko 	int32_t i;
1642b3f6d66SOleksandr Tymoshenko 
1652b3f6d66SOleksandr Tymoshenko 	for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++)
1662b3f6d66SOleksandr Tymoshenko 		evdev_support_key(evdev, evdev_fngmap[i]);
1672b3f6d66SOleksandr Tymoshenko }
1682b3f6d66SOleksandr Tymoshenko 
1692b3f6d66SOleksandr Tymoshenko void
1702b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev)
1712b3f6d66SOleksandr Tymoshenko {
1722b3f6d66SOleksandr Tymoshenko 	int32_t i;
1732b3f6d66SOleksandr Tymoshenko 
1742b3f6d66SOleksandr Tymoshenko 	if (evdev->ev_absinfo == NULL)
1752b3f6d66SOleksandr Tymoshenko 		return;
1762b3f6d66SOleksandr Tymoshenko 
1772b3f6d66SOleksandr Tymoshenko 	evdev_support_event(evdev, EV_KEY);
1782b3f6d66SOleksandr Tymoshenko 	evdev_support_key(evdev, BTN_TOUCH);
1792b3f6d66SOleksandr Tymoshenko 
1802b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not advertise tap tool capabilities */
1812b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
1822b3f6d66SOleksandr Tymoshenko 		evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
1832b3f6d66SOleksandr Tymoshenko 
1842b3f6d66SOleksandr Tymoshenko 	/* Echo 0-th MT-slot as ST-slot */
1852b3f6d66SOleksandr Tymoshenko 	for (i = 0; i < nitems(evdev_mtstmap); i++)
1862b3f6d66SOleksandr Tymoshenko 		if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
1872b3f6d66SOleksandr Tymoshenko 			evdev_support_abs(evdev, evdev_mtstmap[i][1],
1882b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].value,
1892b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum,
1902b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum,
1912b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz,
1922b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].flat,
1932b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution);
1942b3f6d66SOleksandr Tymoshenko }
1952b3f6d66SOleksandr Tymoshenko 
1962b3f6d66SOleksandr Tymoshenko static int32_t
1972b3f6d66SOleksandr Tymoshenko evdev_count_fingers(struct evdev_dev *evdev)
1982b3f6d66SOleksandr Tymoshenko {
1992b3f6d66SOleksandr Tymoshenko 	int32_t nfingers = 0, i;
2002b3f6d66SOleksandr Tymoshenko 
2012b3f6d66SOleksandr Tymoshenko 	for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
2022b3f6d66SOleksandr Tymoshenko 		if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
2032b3f6d66SOleksandr Tymoshenko 			nfingers++;
2042b3f6d66SOleksandr Tymoshenko 
2052b3f6d66SOleksandr Tymoshenko 	return (nfingers);
2062b3f6d66SOleksandr Tymoshenko }
2072b3f6d66SOleksandr Tymoshenko 
2082b3f6d66SOleksandr Tymoshenko static void
2092b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers)
2102b3f6d66SOleksandr Tymoshenko {
2112b3f6d66SOleksandr Tymoshenko 	int32_t i;
2122b3f6d66SOleksandr Tymoshenko 
2132b3f6d66SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
2142b3f6d66SOleksandr Tymoshenko 
2152b3f6d66SOleksandr Tymoshenko 	if (nfingers > nitems(evdev_fngmap))
2162b3f6d66SOleksandr Tymoshenko 		nfingers = nitems(evdev_fngmap);
2172b3f6d66SOleksandr Tymoshenko 
2182b3f6d66SOleksandr Tymoshenko 	for (i = 0; i < nitems(evdev_fngmap); i++)
2192b3f6d66SOleksandr Tymoshenko 		evdev_send_event(evdev, EV_KEY, evdev_fngmap[i],
2202b3f6d66SOleksandr Tymoshenko 		    nfingers == i + 1);
2212b3f6d66SOleksandr Tymoshenko }
2222b3f6d66SOleksandr Tymoshenko 
2232b3f6d66SOleksandr Tymoshenko void
2242b3f6d66SOleksandr Tymoshenko evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers)
2252b3f6d66SOleksandr Tymoshenko {
2262b3f6d66SOleksandr Tymoshenko 
227bfbd1bb7SOleksandr Tymoshenko 	if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
2282b3f6d66SOleksandr Tymoshenko 		EVDEV_LOCK(evdev);
229bfbd1bb7SOleksandr Tymoshenko 	else
230bfbd1bb7SOleksandr Tymoshenko 		EVDEV_LOCK_ASSERT(evdev);
2312b3f6d66SOleksandr Tymoshenko 	evdev_send_nfingers(evdev, nfingers);
232bfbd1bb7SOleksandr Tymoshenko 	if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
2332b3f6d66SOleksandr Tymoshenko 		EVDEV_UNLOCK(evdev);
2342b3f6d66SOleksandr Tymoshenko }
2352b3f6d66SOleksandr Tymoshenko 
2362b3f6d66SOleksandr Tymoshenko void
2372b3f6d66SOleksandr Tymoshenko evdev_send_mt_compat(struct evdev_dev *evdev)
2382b3f6d66SOleksandr Tymoshenko {
2392b3f6d66SOleksandr Tymoshenko 	int32_t nfingers, i;
2402b3f6d66SOleksandr Tymoshenko 
2412b3f6d66SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
2422b3f6d66SOleksandr Tymoshenko 
2432b3f6d66SOleksandr Tymoshenko 	nfingers = evdev_count_fingers(evdev);
2442b3f6d66SOleksandr Tymoshenko 	evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
2452b3f6d66SOleksandr Tymoshenko 
2462b3f6d66SOleksandr Tymoshenko 	if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
2472b3f6d66SOleksandr Tymoshenko 		/* Echo 0-th MT-slot as ST-slot */
2482b3f6d66SOleksandr Tymoshenko 		for (i = 0; i < nitems(evdev_mtstmap); i++)
2492b3f6d66SOleksandr Tymoshenko 			if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
2502b3f6d66SOleksandr Tymoshenko 				evdev_send_event(evdev, EV_ABS,
2512b3f6d66SOleksandr Tymoshenko 				    evdev_mtstmap[i][1],
2522b3f6d66SOleksandr Tymoshenko 				    evdev_get_mt_value(evdev, 0,
2532b3f6d66SOleksandr Tymoshenko 				    evdev_mtstmap[i][0]));
2542b3f6d66SOleksandr Tymoshenko 
2552b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not report tool taps */
2562b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
2572b3f6d66SOleksandr Tymoshenko 		evdev_send_nfingers(evdev, nfingers);
2582b3f6d66SOleksandr Tymoshenko 
2592b3f6d66SOleksandr Tymoshenko 	if (nfingers == 0)
2602b3f6d66SOleksandr Tymoshenko 		evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
2612b3f6d66SOleksandr Tymoshenko }
2622b3f6d66SOleksandr Tymoshenko 
2632b3f6d66SOleksandr Tymoshenko void
2642b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev)
2652b3f6d66SOleksandr Tymoshenko {
2662b3f6d66SOleksandr Tymoshenko 
267bfbd1bb7SOleksandr Tymoshenko 	if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
2682b3f6d66SOleksandr Tymoshenko 		EVDEV_LOCK(evdev);
269bfbd1bb7SOleksandr Tymoshenko 	else
270bfbd1bb7SOleksandr Tymoshenko 		EVDEV_LOCK_ASSERT(evdev);
2712b3f6d66SOleksandr Tymoshenko 	evdev_send_mt_compat(evdev);
272bfbd1bb7SOleksandr Tymoshenko 	if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
2732b3f6d66SOleksandr Tymoshenko 		EVDEV_UNLOCK(evdev);
2742b3f6d66SOleksandr Tymoshenko }
275*c736a757SOleksandr Tymoshenko 
276*c736a757SOleksandr Tymoshenko void
277*c736a757SOleksandr Tymoshenko evdev_send_mt_autorel(struct evdev_dev *evdev)
278*c736a757SOleksandr Tymoshenko {
279*c736a757SOleksandr Tymoshenko 	int32_t slot;
280*c736a757SOleksandr Tymoshenko 
281*c736a757SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
282*c736a757SOleksandr Tymoshenko 
283*c736a757SOleksandr Tymoshenko 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
284*c736a757SOleksandr Tymoshenko 		if (evdev->ev_mt->ev_mt_slots[slot].ev_report !=
285*c736a757SOleksandr Tymoshenko 		    evdev->ev_report_count &&
286*c736a757SOleksandr Tymoshenko 		    evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){
287*c736a757SOleksandr Tymoshenko 			evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
288*c736a757SOleksandr Tymoshenko 			evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID,
289*c736a757SOleksandr Tymoshenko 			    -1);
290*c736a757SOleksandr Tymoshenko 		}
291*c736a757SOleksandr Tymoshenko 	}
292*c736a757SOleksandr Tymoshenko }
293