xref: /freebsd/sys/dev/evdev/evdev_mt.c (revision f6a3b357e9be4c6423c85eff9a847163a0d307c8)
1 /*-
2  * Copyright (c) 2016 Vladimir Kondratyev <wulf@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/param.h>
30 #include <sys/lock.h>
31 #include <sys/malloc.h>
32 #include <sys/mutex.h>
33 #include <sys/systm.h>
34 
35 #include <dev/evdev/evdev.h>
36 #include <dev/evdev/evdev_private.h>
37 #include <dev/evdev/input.h>
38 
39 #ifdef DEBUG
40 #define	debugf(fmt, args...)	printf("evdev: " fmt "\n", ##args)
41 #else
42 #define	debugf(fmt, args...)
43 #endif
44 
45 static uint16_t evdev_fngmap[] = {
46 	BTN_TOOL_FINGER,
47 	BTN_TOOL_DOUBLETAP,
48 	BTN_TOOL_TRIPLETAP,
49 	BTN_TOOL_QUADTAP,
50 	BTN_TOOL_QUINTTAP,
51 };
52 
53 static uint16_t evdev_mtstmap[][2] = {
54 	{ ABS_MT_POSITION_X, ABS_X },
55 	{ ABS_MT_POSITION_Y, ABS_Y },
56 	{ ABS_MT_PRESSURE, ABS_PRESSURE },
57 	{ ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH },
58 };
59 
60 struct evdev_mt_slot {
61 	uint64_t ev_report;
62 	int32_t ev_mt_states[MT_CNT];
63 };
64 
65 struct evdev_mt {
66 	int32_t	ev_mt_last_reported_slot;
67 	struct evdev_mt_slot ev_mt_slots[];
68 };
69 
70 void
71 evdev_mt_init(struct evdev_dev *evdev)
72 {
73 	int32_t slot, slots;
74 
75 	slots = MAXIMAL_MT_SLOT(evdev) + 1;
76 
77 	evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) +
78 	     sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
79 
80 	/* Initialize multitouch protocol type B states */
81 	for (slot = 0; slot < slots; slot++) {
82 		/*
83 		 * .ev_report should not be initialized to initial value of
84 		 * report counter (0) as it brokes free slot detection in
85 		 * evdev_get_mt_slot_by_tracking_id. So initialize it to -1
86 		 */
87 		evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) {
88 			.ev_report = 0xFFFFFFFFFFFFFFFFULL,
89 			.ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1,
90 		};
91 	}
92 
93 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
94 		evdev_support_mt_compat(evdev);
95 }
96 
97 void
98 evdev_mt_free(struct evdev_dev *evdev)
99 {
100 
101 	free(evdev->ev_mt, M_EVDEV);
102 }
103 
104 int32_t
105 evdev_get_last_mt_slot(struct evdev_dev *evdev)
106 {
107 
108 	return (evdev->ev_mt->ev_mt_last_reported_slot);
109 }
110 
111 void
112 evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot)
113 {
114 
115 	evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count;
116 	evdev->ev_mt->ev_mt_last_reported_slot = slot;
117 }
118 
119 inline int32_t
120 evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code)
121 {
122 
123 	return (evdev->ev_mt->
124 	    ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]);
125 }
126 
127 inline void
128 evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code,
129     int32_t value)
130 {
131 
132 	evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] =
133 	    value;
134 }
135 
136 int32_t
137 evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
138 {
139 	int32_t tr_id, slot, free_slot = -1;
140 
141 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
142 		tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID);
143 		if (tr_id == tracking_id)
144 			return (slot);
145 		/*
146 		 * Its possible that slot will be reassigned in a place of just
147 		 * released one within the same report. To avoid this compare
148 		 * report counter with slot`s report number updated with each
149 		 * ABS_MT_TRACKING_ID change.
150 		 */
151 		if (free_slot == -1 && tr_id == -1 &&
152 		    evdev->ev_mt->ev_mt_slots[slot].ev_report !=
153 		    evdev->ev_report_count)
154 			free_slot = slot;
155 	}
156 
157 	return (free_slot);
158 }
159 
160 void
161 evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers)
162 {
163 	int32_t i;
164 
165 	for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++)
166 		evdev_support_key(evdev, evdev_fngmap[i]);
167 }
168 
169 void
170 evdev_support_mt_compat(struct evdev_dev *evdev)
171 {
172 	int32_t i;
173 
174 	if (evdev->ev_absinfo == NULL)
175 		return;
176 
177 	evdev_support_event(evdev, EV_KEY);
178 	evdev_support_key(evdev, BTN_TOUCH);
179 
180 	/* Touchscreens should not advertise tap tool capabilities */
181 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
182 		evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
183 
184 	/* Echo 0-th MT-slot as ST-slot */
185 	for (i = 0; i < nitems(evdev_mtstmap); i++)
186 		if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
187 			evdev_support_abs(evdev, evdev_mtstmap[i][1],
188 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].value,
189 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum,
190 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum,
191 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz,
192 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].flat,
193 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution);
194 }
195 
196 static int32_t
197 evdev_count_fingers(struct evdev_dev *evdev)
198 {
199 	int32_t nfingers = 0, i;
200 
201 	for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
202 		if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
203 			nfingers++;
204 
205 	return (nfingers);
206 }
207 
208 static void
209 evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers)
210 {
211 	int32_t i;
212 
213 	EVDEV_LOCK_ASSERT(evdev);
214 
215 	if (nfingers > nitems(evdev_fngmap))
216 		nfingers = nitems(evdev_fngmap);
217 
218 	for (i = 0; i < nitems(evdev_fngmap); i++)
219 		evdev_send_event(evdev, EV_KEY, evdev_fngmap[i],
220 		    nfingers == i + 1);
221 }
222 
223 void
224 evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers)
225 {
226 
227 	EVDEV_ENTER(evdev);
228 	evdev_send_nfingers(evdev, nfingers);
229 	EVDEV_EXIT(evdev);
230 }
231 
232 void
233 evdev_send_mt_compat(struct evdev_dev *evdev)
234 {
235 	int32_t nfingers, i;
236 
237 	EVDEV_LOCK_ASSERT(evdev);
238 
239 	nfingers = evdev_count_fingers(evdev);
240 	evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
241 
242 	if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
243 		/* Echo 0-th MT-slot as ST-slot */
244 		for (i = 0; i < nitems(evdev_mtstmap); i++)
245 			if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
246 				evdev_send_event(evdev, EV_ABS,
247 				    evdev_mtstmap[i][1],
248 				    evdev_get_mt_value(evdev, 0,
249 				    evdev_mtstmap[i][0]));
250 
251 	/* Touchscreens should not report tool taps */
252 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
253 		evdev_send_nfingers(evdev, nfingers);
254 
255 	if (nfingers == 0)
256 		evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
257 }
258 
259 void
260 evdev_push_mt_compat(struct evdev_dev *evdev)
261 {
262 
263 	EVDEV_ENTER(evdev);
264 	evdev_send_mt_compat(evdev);
265 	EVDEV_EXIT(evdev);
266 }
267 
268 void
269 evdev_send_mt_autorel(struct evdev_dev *evdev)
270 {
271 	int32_t slot;
272 
273 	EVDEV_LOCK_ASSERT(evdev);
274 
275 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
276 		if (evdev->ev_mt->ev_mt_slots[slot].ev_report !=
277 		    evdev->ev_report_count &&
278 		    evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){
279 			evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
280 			evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID,
281 			    -1);
282 		}
283 	}
284 }
285