xref: /freebsd/sys/dev/evdev/evdev_mt.c (revision 98a7606b85e05132f328a2498dccab78df31cb7e)
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 
452b3f6d66SOleksandr Tymoshenko static uint16_t evdev_mtstmap[][2] = {
462b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_POSITION_X, ABS_X },
472b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_POSITION_Y, ABS_Y },
482b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_PRESSURE, ABS_PRESSURE },
492b3f6d66SOleksandr Tymoshenko 	{ ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH },
502b3f6d66SOleksandr Tymoshenko };
512b3f6d66SOleksandr Tymoshenko 
522b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot {
532b3f6d66SOleksandr Tymoshenko 	uint64_t	ev_report;
54*98a7606bSVladimir Kondratyev 	int32_t		val[MT_CNT];
552b3f6d66SOleksandr Tymoshenko };
562b3f6d66SOleksandr Tymoshenko 
572b3f6d66SOleksandr Tymoshenko struct evdev_mt {
58*98a7606bSVladimir Kondratyev 	int			last_reported_slot;
59*98a7606bSVladimir Kondratyev 	struct evdev_mt_slot	slots[];
602b3f6d66SOleksandr Tymoshenko };
612b3f6d66SOleksandr Tymoshenko 
62*98a7606bSVladimir Kondratyev static void	evdev_mt_send_st_compat(struct evdev_dev *);
63*98a7606bSVladimir Kondratyev static void	evdev_mt_send_autorel(struct evdev_dev *);
64*98a7606bSVladimir Kondratyev 
652b3f6d66SOleksandr Tymoshenko void
662b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev)
672b3f6d66SOleksandr Tymoshenko {
68*98a7606bSVladimir Kondratyev 	int slot, slots;
692b3f6d66SOleksandr Tymoshenko 
702b3f6d66SOleksandr Tymoshenko 	slots = MAXIMAL_MT_SLOT(evdev) + 1;
712b3f6d66SOleksandr Tymoshenko 
72*98a7606bSVladimir Kondratyev 	evdev->ev_mt = malloc(offsetof(struct evdev_mt, slots) +
732b3f6d66SOleksandr Tymoshenko 	     sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
742b3f6d66SOleksandr Tymoshenko 
752b3f6d66SOleksandr Tymoshenko 	/* Initialize multitouch protocol type B states */
762b3f6d66SOleksandr Tymoshenko 	for (slot = 0; slot < slots; slot++) {
772b3f6d66SOleksandr Tymoshenko 		/*
782b3f6d66SOleksandr Tymoshenko 		 * .ev_report should not be initialized to initial value of
792b3f6d66SOleksandr Tymoshenko 		 * report counter (0) as it brokes free slot detection in
802b3f6d66SOleksandr Tymoshenko 		 * evdev_get_mt_slot_by_tracking_id. So initialize it to -1
812b3f6d66SOleksandr Tymoshenko 		 */
82*98a7606bSVladimir Kondratyev 		evdev->ev_mt->slots[slot] = (struct evdev_mt_slot) {
832b3f6d66SOleksandr Tymoshenko 			.ev_report = 0xFFFFFFFFFFFFFFFFULL,
84*98a7606bSVladimir Kondratyev 			.val[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1,
852b3f6d66SOleksandr Tymoshenko 		};
862b3f6d66SOleksandr Tymoshenko 	}
872b3f6d66SOleksandr Tymoshenko 
882b3f6d66SOleksandr Tymoshenko 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
892b3f6d66SOleksandr Tymoshenko 		evdev_support_mt_compat(evdev);
902b3f6d66SOleksandr Tymoshenko }
912b3f6d66SOleksandr Tymoshenko 
922b3f6d66SOleksandr Tymoshenko void
932b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev)
942b3f6d66SOleksandr Tymoshenko {
952b3f6d66SOleksandr Tymoshenko 	free(evdev->ev_mt, M_EVDEV);
962b3f6d66SOleksandr Tymoshenko }
972b3f6d66SOleksandr Tymoshenko 
98*98a7606bSVladimir Kondratyev void
99*98a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev)
1002b3f6d66SOleksandr Tymoshenko {
101*98a7606bSVladimir Kondratyev 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
102*98a7606bSVladimir Kondratyev 		evdev_mt_send_autorel(evdev);
103*98a7606bSVladimir Kondratyev 	if (evdev->ev_report_opened &&
104*98a7606bSVladimir Kondratyev 	    bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
105*98a7606bSVladimir Kondratyev 		evdev_mt_send_st_compat(evdev);
106*98a7606bSVladimir Kondratyev }
1072b3f6d66SOleksandr Tymoshenko 
108*98a7606bSVladimir Kondratyev int
109*98a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev)
110*98a7606bSVladimir Kondratyev {
111*98a7606bSVladimir Kondratyev 	return (evdev->ev_mt->last_reported_slot);
1122b3f6d66SOleksandr Tymoshenko }
1132b3f6d66SOleksandr Tymoshenko 
1142b3f6d66SOleksandr Tymoshenko void
115*98a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot)
1162b3f6d66SOleksandr Tymoshenko {
117*98a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
1182b3f6d66SOleksandr Tymoshenko 
119*98a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
1202b3f6d66SOleksandr Tymoshenko 
121*98a7606bSVladimir Kondratyev 	mt->slots[slot].ev_report = evdev->ev_report_count;
122*98a7606bSVladimir Kondratyev 	mt->last_reported_slot = slot;
1232b3f6d66SOleksandr Tymoshenko }
1242b3f6d66SOleksandr Tymoshenko 
1252b3f6d66SOleksandr Tymoshenko int32_t
126*98a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code)
127*98a7606bSVladimir Kondratyev {
128*98a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
129*98a7606bSVladimir Kondratyev 
130*98a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
131*98a7606bSVladimir Kondratyev 
132*98a7606bSVladimir Kondratyev 	return (mt->slots[slot].val[ABS_MT_INDEX(code)]);
133*98a7606bSVladimir Kondratyev }
134*98a7606bSVladimir Kondratyev 
135*98a7606bSVladimir Kondratyev void
136*98a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code,
137*98a7606bSVladimir Kondratyev     int32_t value)
138*98a7606bSVladimir Kondratyev {
139*98a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
140*98a7606bSVladimir Kondratyev 
141*98a7606bSVladimir Kondratyev 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
142*98a7606bSVladimir Kondratyev 
143*98a7606bSVladimir Kondratyev 	mt->slots[slot].val[ABS_MT_INDEX(code)] = value;
144*98a7606bSVladimir Kondratyev }
145*98a7606bSVladimir Kondratyev 
146*98a7606bSVladimir Kondratyev int
1472b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
1482b3f6d66SOleksandr Tymoshenko {
149*98a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
150*98a7606bSVladimir Kondratyev 	int32_t tr_id;
151*98a7606bSVladimir Kondratyev 	int slot, free_slot = -1;
1522b3f6d66SOleksandr Tymoshenko 
1532b3f6d66SOleksandr Tymoshenko 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
154*98a7606bSVladimir Kondratyev 		tr_id = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID);
1552b3f6d66SOleksandr Tymoshenko 		if (tr_id == tracking_id)
1562b3f6d66SOleksandr Tymoshenko 			return (slot);
1572b3f6d66SOleksandr Tymoshenko 		/*
1582b3f6d66SOleksandr Tymoshenko 		 * Its possible that slot will be reassigned in a place of just
1592b3f6d66SOleksandr Tymoshenko 		 * released one within the same report. To avoid this compare
1602b3f6d66SOleksandr Tymoshenko 		 * report counter with slot`s report number updated with each
1612b3f6d66SOleksandr Tymoshenko 		 * ABS_MT_TRACKING_ID change.
1622b3f6d66SOleksandr Tymoshenko 		 */
1632b3f6d66SOleksandr Tymoshenko 		if (free_slot == -1 && tr_id == -1 &&
164*98a7606bSVladimir Kondratyev 		    mt->slots[slot].ev_report != evdev->ev_report_count)
1652b3f6d66SOleksandr Tymoshenko 			free_slot = slot;
1662b3f6d66SOleksandr Tymoshenko 	}
1672b3f6d66SOleksandr Tymoshenko 
1682b3f6d66SOleksandr Tymoshenko 	return (free_slot);
1692b3f6d66SOleksandr Tymoshenko }
1702b3f6d66SOleksandr Tymoshenko 
1712b3f6d66SOleksandr Tymoshenko void
1722b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev)
1732b3f6d66SOleksandr Tymoshenko {
174*98a7606bSVladimir Kondratyev 	int i;
1752b3f6d66SOleksandr Tymoshenko 
1762b3f6d66SOleksandr Tymoshenko 	if (evdev->ev_absinfo == NULL)
1772b3f6d66SOleksandr Tymoshenko 		return;
1782b3f6d66SOleksandr Tymoshenko 
1792b3f6d66SOleksandr Tymoshenko 	evdev_support_event(evdev, EV_KEY);
1802b3f6d66SOleksandr Tymoshenko 	evdev_support_key(evdev, BTN_TOUCH);
1812b3f6d66SOleksandr Tymoshenko 
1822b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not advertise tap tool capabilities */
1832b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
1842b3f6d66SOleksandr Tymoshenko 		evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
1852b3f6d66SOleksandr Tymoshenko 
1862b3f6d66SOleksandr Tymoshenko 	/* Echo 0-th MT-slot as ST-slot */
1872b3f6d66SOleksandr Tymoshenko 	for (i = 0; i < nitems(evdev_mtstmap); i++)
1882b3f6d66SOleksandr Tymoshenko 		if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
1892b3f6d66SOleksandr Tymoshenko 			evdev_support_abs(evdev, evdev_mtstmap[i][1],
1902b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum,
1912b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum,
1922b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz,
1932b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].flat,
1942b3f6d66SOleksandr Tymoshenko 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution);
1952b3f6d66SOleksandr Tymoshenko }
1962b3f6d66SOleksandr Tymoshenko 
1972b3f6d66SOleksandr Tymoshenko static int32_t
1982b3f6d66SOleksandr Tymoshenko evdev_count_fingers(struct evdev_dev *evdev)
1992b3f6d66SOleksandr Tymoshenko {
200*98a7606bSVladimir Kondratyev 	int nfingers = 0, i;
2012b3f6d66SOleksandr Tymoshenko 
2022b3f6d66SOleksandr Tymoshenko 	for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
203*98a7606bSVladimir Kondratyev 		if (evdev_mt_get_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
2042b3f6d66SOleksandr Tymoshenko 			nfingers++;
2052b3f6d66SOleksandr Tymoshenko 
2062b3f6d66SOleksandr Tymoshenko 	return (nfingers);
2072b3f6d66SOleksandr Tymoshenko }
2082b3f6d66SOleksandr Tymoshenko 
2092b3f6d66SOleksandr Tymoshenko static void
210*98a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev)
2112b3f6d66SOleksandr Tymoshenko {
212*98a7606bSVladimir Kondratyev 	int nfingers, i;
2132b3f6d66SOleksandr Tymoshenko 
2142b3f6d66SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
2152b3f6d66SOleksandr Tymoshenko 
2162b3f6d66SOleksandr Tymoshenko 	nfingers = evdev_count_fingers(evdev);
2172b3f6d66SOleksandr Tymoshenko 	evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
2182b3f6d66SOleksandr Tymoshenko 
219*98a7606bSVladimir Kondratyev 	if (evdev_mt_get_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
2202b3f6d66SOleksandr Tymoshenko 		/* Echo 0-th MT-slot as ST-slot */
2212b3f6d66SOleksandr Tymoshenko 		for (i = 0; i < nitems(evdev_mtstmap); i++)
2222b3f6d66SOleksandr Tymoshenko 			if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
2232b3f6d66SOleksandr Tymoshenko 				evdev_send_event(evdev, EV_ABS,
2242b3f6d66SOleksandr Tymoshenko 				    evdev_mtstmap[i][1],
225*98a7606bSVladimir Kondratyev 				    evdev_mt_get_value(evdev, 0,
2262b3f6d66SOleksandr Tymoshenko 				    evdev_mtstmap[i][0]));
2272b3f6d66SOleksandr Tymoshenko 
2282b3f6d66SOleksandr Tymoshenko 	/* Touchscreens should not report tool taps */
2292b3f6d66SOleksandr Tymoshenko 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
2302b3f6d66SOleksandr Tymoshenko 		evdev_send_nfingers(evdev, nfingers);
2312b3f6d66SOleksandr Tymoshenko 
2322b3f6d66SOleksandr Tymoshenko 	if (nfingers == 0)
2332b3f6d66SOleksandr Tymoshenko 		evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
2342b3f6d66SOleksandr Tymoshenko }
2352b3f6d66SOleksandr Tymoshenko 
2362b3f6d66SOleksandr Tymoshenko void
2372b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev)
2382b3f6d66SOleksandr Tymoshenko {
2392b3f6d66SOleksandr Tymoshenko 
2404c0a4665SVladimir Kondratyev 	EVDEV_ENTER(evdev);
241*98a7606bSVladimir Kondratyev 	evdev_mt_send_st_compat(evdev);
2424c0a4665SVladimir Kondratyev 	EVDEV_EXIT(evdev);
2432b3f6d66SOleksandr Tymoshenko }
244c736a757SOleksandr Tymoshenko 
245*98a7606bSVladimir Kondratyev static void
246*98a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev)
247c736a757SOleksandr Tymoshenko {
248*98a7606bSVladimir Kondratyev 	struct evdev_mt *mt = evdev->ev_mt;
249*98a7606bSVladimir Kondratyev 	int slot;
250c736a757SOleksandr Tymoshenko 
251c736a757SOleksandr Tymoshenko 	EVDEV_LOCK_ASSERT(evdev);
252c736a757SOleksandr Tymoshenko 
253c736a757SOleksandr Tymoshenko 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
254*98a7606bSVladimir Kondratyev 		if (mt->slots[slot].ev_report != evdev->ev_report_count &&
255*98a7606bSVladimir Kondratyev 		    evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){
256c736a757SOleksandr Tymoshenko 			evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
257c736a757SOleksandr Tymoshenko 			evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID,
258c736a757SOleksandr Tymoshenko 			    -1);
259c736a757SOleksandr Tymoshenko 		}
260c736a757SOleksandr Tymoshenko 	}
261c736a757SOleksandr Tymoshenko }
262*98a7606bSVladimir Kondratyev 
263*98a7606bSVladimir Kondratyev void
264*98a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev)
265*98a7606bSVladimir Kondratyev {
266*98a7606bSVladimir Kondratyev 	EVDEV_ENTER(evdev);
267*98a7606bSVladimir Kondratyev 	evdev_mt_send_autorel(evdev);
268*98a7606bSVladimir Kondratyev 	EVDEV_EXIT(evdev);
269*98a7606bSVladimir Kondratyev }
270