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