xref: /freebsd-13.1/sys/dev/evdev/evdev_mt.c (revision a437dfa5)
1 /*-
2  * Copyright (c) 2016 Vladimir Kondratyev <[email protected]>
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_mtstmap[][2] = {
46 	{ ABS_MT_POSITION_X, ABS_X },
47 	{ ABS_MT_POSITION_Y, ABS_Y },
48 	{ ABS_MT_PRESSURE, ABS_PRESSURE },
49 	{ ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH },
50 };
51 
52 struct evdev_mt_slot {
53 	uint64_t	ev_report;
54 	int32_t		val[MT_CNT];
55 };
56 
57 struct evdev_mt {
58 	int			last_reported_slot;
59 	struct evdev_mt_slot	slots[];
60 };
61 
62 static void	evdev_mt_send_st_compat(struct evdev_dev *);
63 static void	evdev_mt_send_autorel(struct evdev_dev *);
64 
65 void
66 evdev_mt_init(struct evdev_dev *evdev)
67 {
68 	int slot, slots;
69 
70 	slots = MAXIMAL_MT_SLOT(evdev) + 1;
71 
72 	evdev->ev_mt = malloc(offsetof(struct evdev_mt, slots) +
73 	     sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
74 
75 	/* Initialize multitouch protocol type B states */
76 	for (slot = 0; slot < slots; slot++) {
77 		/*
78 		 * .ev_report should not be initialized to initial value of
79 		 * report counter (0) as it brokes free slot detection in
80 		 * evdev_get_mt_slot_by_tracking_id. So initialize it to -1
81 		 */
82 		evdev->ev_mt->slots[slot] = (struct evdev_mt_slot) {
83 			.ev_report = 0xFFFFFFFFFFFFFFFFULL,
84 			.val[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1,
85 		};
86 	}
87 
88 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
89 		evdev_support_mt_compat(evdev);
90 }
91 
92 void
93 evdev_mt_free(struct evdev_dev *evdev)
94 {
95 	free(evdev->ev_mt, M_EVDEV);
96 }
97 
98 void
99 evdev_mt_sync_frame(struct evdev_dev *evdev)
100 {
101 	if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
102 		evdev_mt_send_autorel(evdev);
103 	if (evdev->ev_report_opened &&
104 	    bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
105 		evdev_mt_send_st_compat(evdev);
106 }
107 
108 int
109 evdev_mt_get_last_slot(struct evdev_dev *evdev)
110 {
111 	return (evdev->ev_mt->last_reported_slot);
112 }
113 
114 void
115 evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot)
116 {
117 	struct evdev_mt *mt = evdev->ev_mt;
118 
119 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
120 
121 	mt->slots[slot].ev_report = evdev->ev_report_count;
122 	mt->last_reported_slot = slot;
123 }
124 
125 int32_t
126 evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code)
127 {
128 	struct evdev_mt *mt = evdev->ev_mt;
129 
130 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
131 
132 	return (mt->slots[slot].val[ABS_MT_INDEX(code)]);
133 }
134 
135 void
136 evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code,
137     int32_t value)
138 {
139 	struct evdev_mt *mt = evdev->ev_mt;
140 
141 	MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
142 
143 	mt->slots[slot].val[ABS_MT_INDEX(code)] = value;
144 }
145 
146 int
147 evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
148 {
149 	struct evdev_mt *mt = evdev->ev_mt;
150 	int32_t tr_id;
151 	int slot, free_slot = -1;
152 
153 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
154 		tr_id = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID);
155 		if (tr_id == tracking_id)
156 			return (slot);
157 		/*
158 		 * Its possible that slot will be reassigned in a place of just
159 		 * released one within the same report. To avoid this compare
160 		 * report counter with slot`s report number updated with each
161 		 * ABS_MT_TRACKING_ID change.
162 		 */
163 		if (free_slot == -1 && tr_id == -1 &&
164 		    mt->slots[slot].ev_report != evdev->ev_report_count)
165 			free_slot = slot;
166 	}
167 
168 	return (free_slot);
169 }
170 
171 void
172 evdev_support_mt_compat(struct evdev_dev *evdev)
173 {
174 	int i;
175 
176 	if (evdev->ev_absinfo == NULL)
177 		return;
178 
179 	evdev_support_event(evdev, EV_KEY);
180 	evdev_support_key(evdev, BTN_TOUCH);
181 
182 	/* Touchscreens should not advertise tap tool capabilities */
183 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
184 		evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
185 
186 	/* Echo 0-th MT-slot as ST-slot */
187 	for (i = 0; i < nitems(evdev_mtstmap); i++)
188 		if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
189 			evdev_support_abs(evdev, evdev_mtstmap[i][1],
190 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum,
191 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum,
192 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz,
193 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].flat,
194 			    evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution);
195 }
196 
197 static int32_t
198 evdev_count_fingers(struct evdev_dev *evdev)
199 {
200 	int nfingers = 0, i;
201 
202 	for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
203 		if (evdev_mt_get_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
204 			nfingers++;
205 
206 	return (nfingers);
207 }
208 
209 static void
210 evdev_mt_send_st_compat(struct evdev_dev *evdev)
211 {
212 	int nfingers, i;
213 
214 	EVDEV_LOCK_ASSERT(evdev);
215 
216 	nfingers = evdev_count_fingers(evdev);
217 	evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
218 
219 	if (evdev_mt_get_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
220 		/* Echo 0-th MT-slot as ST-slot */
221 		for (i = 0; i < nitems(evdev_mtstmap); i++)
222 			if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
223 				evdev_send_event(evdev, EV_ABS,
224 				    evdev_mtstmap[i][1],
225 				    evdev_mt_get_value(evdev, 0,
226 				    evdev_mtstmap[i][0]));
227 
228 	/* Touchscreens should not report tool taps */
229 	if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
230 		evdev_send_nfingers(evdev, nfingers);
231 
232 	if (nfingers == 0)
233 		evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
234 }
235 
236 void
237 evdev_push_mt_compat(struct evdev_dev *evdev)
238 {
239 
240 	EVDEV_ENTER(evdev);
241 	evdev_mt_send_st_compat(evdev);
242 	EVDEV_EXIT(evdev);
243 }
244 
245 static void
246 evdev_mt_send_autorel(struct evdev_dev *evdev)
247 {
248 	struct evdev_mt *mt = evdev->ev_mt;
249 	int slot;
250 
251 	EVDEV_LOCK_ASSERT(evdev);
252 
253 	for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
254 		if (mt->slots[slot].ev_report != evdev->ev_report_count &&
255 		    evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){
256 			evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
257 			evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID,
258 			    -1);
259 		}
260 	}
261 }
262 
263 void
264 evdev_mt_push_autorel(struct evdev_dev *evdev)
265 {
266 	EVDEV_ENTER(evdev);
267 	evdev_mt_send_autorel(evdev);
268 	EVDEV_EXIT(evdev);
269 }
270