1305706Sgonzo/*-
2324768Swulf * Copyright (c) 2016 Vladimir Kondratyev <wulf@FreeBSD.org>
3305706Sgonzo * All rights reserved.
4305706Sgonzo *
5305706Sgonzo * Redistribution and use in source and binary forms, with or without
6305706Sgonzo * modification, are permitted provided that the following conditions
7305706Sgonzo * are met:
8305706Sgonzo * 1. Redistributions of source code must retain the above copyright
9305706Sgonzo *    notice, this list of conditions and the following disclaimer.
10305706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11305706Sgonzo *    notice, this list of conditions and the following disclaimer in the
12305706Sgonzo *    documentation and/or other materials provided with the distribution.
13305706Sgonzo *
14305706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15305706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16305706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17305706Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18305706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19305706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20305706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21305706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22305706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23305706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24305706Sgonzo * SUCH DAMAGE.
25305706Sgonzo *
26305706Sgonzo * $FreeBSD: stable/11/sys/dev/evdev/evdev_mt.c 324768 2017-10-19 20:16:40Z wulf $
27305706Sgonzo */
28305706Sgonzo
29305706Sgonzo#include <sys/param.h>
30324768Swulf#include <sys/lock.h>
31305706Sgonzo#include <sys/malloc.h>
32305706Sgonzo#include <sys/mutex.h>
33305706Sgonzo#include <sys/systm.h>
34305706Sgonzo
35305706Sgonzo#include <dev/evdev/evdev.h>
36305706Sgonzo#include <dev/evdev/evdev_private.h>
37324768Swulf#include <dev/evdev/input.h>
38305706Sgonzo
39305706Sgonzo#ifdef DEBUG
40305706Sgonzo#define	debugf(fmt, args...)	printf("evdev: " fmt "\n", ##args)
41305706Sgonzo#else
42305706Sgonzo#define	debugf(fmt, args...)
43305706Sgonzo#endif
44305706Sgonzo
45305706Sgonzostatic uint16_t evdev_fngmap[] = {
46305706Sgonzo	BTN_TOOL_FINGER,
47305706Sgonzo	BTN_TOOL_DOUBLETAP,
48305706Sgonzo	BTN_TOOL_TRIPLETAP,
49305706Sgonzo	BTN_TOOL_QUADTAP,
50305706Sgonzo	BTN_TOOL_QUINTTAP,
51305706Sgonzo};
52305706Sgonzo
53305706Sgonzostatic uint16_t evdev_mtstmap[][2] = {
54305706Sgonzo	{ ABS_MT_POSITION_X, ABS_X },
55305706Sgonzo	{ ABS_MT_POSITION_Y, ABS_Y },
56305706Sgonzo	{ ABS_MT_PRESSURE, ABS_PRESSURE },
57305706Sgonzo	{ ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH },
58305706Sgonzo};
59305706Sgonzo
60305706Sgonzostruct evdev_mt_slot {
61305706Sgonzo	uint64_t ev_report;
62305706Sgonzo	int32_t ev_mt_states[MT_CNT];
63305706Sgonzo};
64305706Sgonzo
65305706Sgonzostruct evdev_mt {
66305706Sgonzo	int32_t	ev_mt_last_reported_slot;
67305706Sgonzo	struct evdev_mt_slot ev_mt_slots[];
68305706Sgonzo};
69305706Sgonzo
70305706Sgonzovoid
71305706Sgonzoevdev_mt_init(struct evdev_dev *evdev)
72305706Sgonzo{
73305706Sgonzo	int32_t slot, slots;
74305706Sgonzo
75305706Sgonzo	slots = MAXIMAL_MT_SLOT(evdev) + 1;
76305706Sgonzo
77305706Sgonzo	evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) +
78305706Sgonzo	     sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
79305706Sgonzo
80305706Sgonzo	/* Initialize multitouch protocol type B states */
81305706Sgonzo	for (slot = 0; slot < slots; slot++) {
82305706Sgonzo		/*
83305706Sgonzo		 * .ev_report should not be initialized to initial value of
84305706Sgonzo		 * report counter (0) as it brokes free slot detection in
85305706Sgonzo		 * evdev_get_mt_slot_by_tracking_id. So initialize it to -1
86305706Sgonzo		 */
87305706Sgonzo		evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) {
88305706Sgonzo			.ev_report = 0xFFFFFFFFFFFFFFFFULL,
89305706Sgonzo			.ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1,
90305706Sgonzo		};
91305706Sgonzo	}
92305706Sgonzo
93305706Sgonzo	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
94305706Sgonzo		evdev_support_mt_compat(evdev);
95305706Sgonzo}
96305706Sgonzo
97305706Sgonzovoid
98305706Sgonzoevdev_mt_free(struct evdev_dev *evdev)
99305706Sgonzo{
100305706Sgonzo
101305706Sgonzo	free(evdev->ev_mt, M_EVDEV);
102305706Sgonzo}
103305706Sgonzo
104305706Sgonzoint32_t
105305706Sgonzoevdev_get_last_mt_slot(struct evdev_dev *evdev)
106305706Sgonzo{
107305706Sgonzo
108305706Sgonzo	return (evdev->ev_mt->ev_mt_last_reported_slot);
109305706Sgonzo}
110305706Sgonzo
111305706Sgonzovoid
112305706Sgonzoevdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot)
113305706Sgonzo{
114305706Sgonzo
115307777Sgonzo	evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count;
116305706Sgonzo	evdev->ev_mt->ev_mt_last_reported_slot = slot;
117305706Sgonzo}
118305706Sgonzo
119305706Sgonzoinline int32_t
120305706Sgonzoevdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code)
121305706Sgonzo{
122305706Sgonzo
123305706Sgonzo	return (evdev->ev_mt->
124305706Sgonzo	    ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]);
125305706Sgonzo}
126305706Sgonzo
127305706Sgonzoinline void
128305706Sgonzoevdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code,
129305706Sgonzo    int32_t value)
130305706Sgonzo{
131305706Sgonzo
132305706Sgonzo	evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] =
133305706Sgonzo	    value;
134305706Sgonzo}
135305706Sgonzo
136305706Sgonzoint32_t
137305706Sgonzoevdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
138305706Sgonzo{
139305706Sgonzo	int32_t tr_id, slot, free_slot = -1;
140305706Sgonzo
141305706Sgonzo	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
142305706Sgonzo		tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID);
143305706Sgonzo		if (tr_id == tracking_id)
144305706Sgonzo			return (slot);
145305706Sgonzo		/*
146305706Sgonzo		 * Its possible that slot will be reassigned in a place of just
147305706Sgonzo		 * released one within the same report. To avoid this compare
148305706Sgonzo		 * report counter with slot`s report number updated with each
149305706Sgonzo		 * ABS_MT_TRACKING_ID change.
150305706Sgonzo		 */
151305706Sgonzo		if (free_slot == -1 && tr_id == -1 &&
152305706Sgonzo		    evdev->ev_mt->ev_mt_slots[slot].ev_report !=
153305706Sgonzo		    evdev->ev_report_count)
154305706Sgonzo			free_slot = slot;
155305706Sgonzo	}
156305706Sgonzo
157305706Sgonzo	return (free_slot);
158305706Sgonzo}
159305706Sgonzo
160305706Sgonzovoid
161305706Sgonzoevdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers)
162305706Sgonzo{
163305706Sgonzo	int32_t i;
164305706Sgonzo
165305706Sgonzo	for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++)
166305706Sgonzo		evdev_support_key(evdev, evdev_fngmap[i]);
167305706Sgonzo}
168305706Sgonzo
169305706Sgonzovoid
170305706Sgonzoevdev_support_mt_compat(struct evdev_dev *evdev)
171305706Sgonzo{
172305706Sgonzo	int32_t i;
173305706Sgonzo
174305706Sgonzo	if (evdev->ev_absinfo == NULL)
175305706Sgonzo		return;
176305706Sgonzo
177305706Sgonzo	evdev_support_event(evdev, EV_KEY);
178305706Sgonzo	evdev_support_key(evdev, BTN_TOUCH);
179305706Sgonzo
180305706Sgonzo	/* Touchscreens should not advertise tap tool capabilities */
181305706Sgonzo	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
182305706Sgonzo		evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
183305706Sgonzo
184305706Sgonzo	/* Echo 0-th MT-slot as ST-slot */
185305706Sgonzo	for (i = 0; i < nitems(evdev_mtstmap); i++)
186305706Sgonzo		if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
187305706Sgonzo			evdev_support_abs(evdev, evdev_mtstmap[i][1],
188305706Sgonzo			    evdev->ev_absinfo[evdev_mtstmap[i][0]].value,
189305706Sgonzo			    evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum,
190305706Sgonzo			    evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum,
191305706Sgonzo			    evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz,
192305706Sgonzo			    evdev->ev_absinfo[evdev_mtstmap[i][0]].flat,
193305706Sgonzo			    evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution);
194305706Sgonzo}
195305706Sgonzo
196305706Sgonzostatic int32_t
197305706Sgonzoevdev_count_fingers(struct evdev_dev *evdev)
198305706Sgonzo{
199305706Sgonzo	int32_t nfingers = 0, i;
200305706Sgonzo
201305706Sgonzo	for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
202305706Sgonzo		if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
203305706Sgonzo			nfingers++;
204305706Sgonzo
205305706Sgonzo	return (nfingers);
206305706Sgonzo}
207305706Sgonzo
208305706Sgonzostatic void
209305706Sgonzoevdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers)
210305706Sgonzo{
211305706Sgonzo	int32_t i;
212305706Sgonzo
213305706Sgonzo	EVDEV_LOCK_ASSERT(evdev);
214305706Sgonzo
215305706Sgonzo	if (nfingers > nitems(evdev_fngmap))
216305706Sgonzo		nfingers = nitems(evdev_fngmap);
217305706Sgonzo
218305706Sgonzo	for (i = 0; i < nitems(evdev_fngmap); i++)
219305706Sgonzo		evdev_send_event(evdev, EV_KEY, evdev_fngmap[i],
220305706Sgonzo		    nfingers == i + 1);
221305706Sgonzo}
222305706Sgonzo
223305706Sgonzovoid
224305706Sgonzoevdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers)
225305706Sgonzo{
226305706Sgonzo
227324768Swulf	EVDEV_ENTER(evdev);
228305706Sgonzo	evdev_send_nfingers(evdev, nfingers);
229324768Swulf	EVDEV_EXIT(evdev);
230305706Sgonzo}
231305706Sgonzo
232305706Sgonzovoid
233305706Sgonzoevdev_send_mt_compat(struct evdev_dev *evdev)
234305706Sgonzo{
235305706Sgonzo	int32_t nfingers, i;
236305706Sgonzo
237305706Sgonzo	EVDEV_LOCK_ASSERT(evdev);
238305706Sgonzo
239305706Sgonzo	nfingers = evdev_count_fingers(evdev);
240305706Sgonzo	evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
241305706Sgonzo
242305706Sgonzo	if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
243305706Sgonzo		/* Echo 0-th MT-slot as ST-slot */
244305706Sgonzo		for (i = 0; i < nitems(evdev_mtstmap); i++)
245305706Sgonzo			if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
246305706Sgonzo				evdev_send_event(evdev, EV_ABS,
247305706Sgonzo				    evdev_mtstmap[i][1],
248305706Sgonzo				    evdev_get_mt_value(evdev, 0,
249305706Sgonzo				    evdev_mtstmap[i][0]));
250305706Sgonzo
251305706Sgonzo	/* Touchscreens should not report tool taps */
252305706Sgonzo	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
253305706Sgonzo		evdev_send_nfingers(evdev, nfingers);
254305706Sgonzo
255305706Sgonzo	if (nfingers == 0)
256305706Sgonzo		evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
257305706Sgonzo}
258305706Sgonzo
259305706Sgonzovoid
260305706Sgonzoevdev_push_mt_compat(struct evdev_dev *evdev)
261305706Sgonzo{
262305706Sgonzo
263324768Swulf	EVDEV_ENTER(evdev);
264305706Sgonzo	evdev_send_mt_compat(evdev);
265324768Swulf	EVDEV_EXIT(evdev);
266305706Sgonzo}
267307777Sgonzo
268307777Sgonzovoid
269307777Sgonzoevdev_send_mt_autorel(struct evdev_dev *evdev)
270307777Sgonzo{
271307777Sgonzo	int32_t slot;
272307777Sgonzo
273307777Sgonzo	EVDEV_LOCK_ASSERT(evdev);
274307777Sgonzo
275307777Sgonzo	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
276307777Sgonzo		if (evdev->ev_mt->ev_mt_slots[slot].ev_report !=
277307777Sgonzo		    evdev->ev_report_count &&
278307777Sgonzo		    evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){
279307777Sgonzo			evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
280307777Sgonzo			evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID,
281307777Sgonzo			    -1);
282307777Sgonzo		}
283307777Sgonzo	}
284307777Sgonzo}
285