kernel - Bring in evdev from FreeBSD
[dragonfly.git] / sys / dev / misc / evdev / evdev_mt.c
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 #include "opt_evdev.h"
29
30 #include <sys/param.h>
31 #include <sys/lock.h>
32 #include <sys/malloc.h>
33 #include <sys/mutex.h>
34 #include <sys/systm.h>
35
36 #include <dev/misc/evdev/evdev.h>
37 #include <dev/misc/evdev/evdev_private.h>
38 #include <dev/misc/evdev/input.h>
39
40 #ifdef DEBUG
41 #define debugf(fmt, args...)    kprintf("evdev: " fmt "\n", ##args)
42 #else
43 #define debugf(fmt, args...)
44 #endif
45
46 static uint16_t evdev_fngmap[] = {
47         BTN_TOOL_FINGER,
48         BTN_TOOL_DOUBLETAP,
49         BTN_TOOL_TRIPLETAP,
50         BTN_TOOL_QUADTAP,
51         BTN_TOOL_QUINTTAP,
52 };
53
54 static uint16_t evdev_mtstmap[][2] = {
55         { ABS_MT_POSITION_X, ABS_X },
56         { ABS_MT_POSITION_Y, ABS_Y },
57         { ABS_MT_PRESSURE, ABS_PRESSURE },
58         { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH },
59 };
60
61 struct evdev_mt_slot {
62         uint64_t ev_report;
63         int32_t ev_mt_states[MT_CNT];
64 };
65
66 struct evdev_mt {
67         int32_t ev_mt_last_reported_slot;
68         struct evdev_mt_slot ev_mt_slots[];
69 };
70
71 void
72 evdev_mt_init(struct evdev_dev *evdev)
73 {
74         int32_t slot, slots;
75
76         slots = MAXIMAL_MT_SLOT(evdev) + 1;
77
78         evdev->ev_mt = kmalloc(offsetof(struct evdev_mt, ev_mt_slots) +
79              sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
80
81         /* Initialize multitouch protocol type B states */
82         for (slot = 0; slot < slots; slot++) {
83                 /*
84                  * .ev_report should not be initialized to initial value of
85                  * report counter (0) as it brokes free slot detection in
86                  * evdev_get_mt_slot_by_tracking_id. So initialize it to -1
87                  */
88                 evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) {
89                         .ev_report = 0xFFFFFFFFFFFFFFFFULL,
90                         .ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1,
91                 };
92         }
93
94         if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
95                 evdev_support_mt_compat(evdev);
96 }
97
98 void
99 evdev_mt_free(struct evdev_dev *evdev)
100 {
101
102         kfree(evdev->ev_mt, M_EVDEV);
103 }
104
105 int32_t
106 evdev_get_last_mt_slot(struct evdev_dev *evdev)
107 {
108
109         return (evdev->ev_mt->ev_mt_last_reported_slot);
110 }
111
112 void
113 evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot)
114 {
115
116         evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count;
117         evdev->ev_mt->ev_mt_last_reported_slot = slot;
118 }
119
120 inline int32_t
121 evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code)
122 {
123
124         return (evdev->ev_mt->
125             ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]);
126 }
127
128 inline void
129 evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code,
130     int32_t value)
131 {
132
133         evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] =
134             value;
135 }
136
137 int32_t
138 evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
139 {
140         int32_t tr_id, slot, free_slot = -1;
141
142         for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
143                 tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID);
144                 if (tr_id == tracking_id)
145                         return (slot);
146                 /*
147                  * Its possible that slot will be reassigned in a place of just
148                  * released one within the same report. To avoid this compare
149                  * report counter with slot`s report number updated with each
150                  * ABS_MT_TRACKING_ID change.
151                  */
152                 if (free_slot == -1 && tr_id == -1 &&
153                     evdev->ev_mt->ev_mt_slots[slot].ev_report !=
154                     evdev->ev_report_count)
155                         free_slot = slot;
156         }
157
158         return (free_slot);
159 }
160
161 void
162 evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers)
163 {
164         int32_t i;
165
166         for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++)
167                 evdev_support_key(evdev, evdev_fngmap[i]);
168 }
169
170 void
171 evdev_support_mt_compat(struct evdev_dev *evdev)
172 {
173         int32_t i;
174
175         if (evdev->ev_absinfo == NULL)
176                 return;
177
178         evdev_support_event(evdev, EV_KEY);
179         evdev_support_key(evdev, BTN_TOUCH);
180
181         /* Touchscreens should not advertise tap tool capabilities */
182         if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
183                 evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
184
185         /* Echo 0-th MT-slot as ST-slot */
186         for (i = 0; i < nitems(evdev_mtstmap); i++)
187                 if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
188                         evdev_support_abs(evdev, evdev_mtstmap[i][1],
189                             evdev->ev_absinfo[evdev_mtstmap[i][0]].value,
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         int32_t nfingers = 0, i;
201
202         for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
203                 if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
204                         nfingers++;
205
206         return (nfingers);
207 }
208
209 static void
210 evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers)
211 {
212         int32_t i;
213
214         EVDEV_LOCK_ASSERT(evdev);
215
216         if (nfingers > nitems(evdev_fngmap))
217                 nfingers = nitems(evdev_fngmap);
218
219         for (i = 0; i < nitems(evdev_fngmap); i++)
220                 evdev_send_event(evdev, EV_KEY, evdev_fngmap[i],
221                     nfingers == i + 1);
222 }
223
224 void
225 evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers)
226 {
227
228         EVDEV_ENTER(evdev);
229         evdev_send_nfingers(evdev, nfingers);
230         EVDEV_EXIT(evdev);
231 }
232
233 void
234 evdev_send_mt_compat(struct evdev_dev *evdev)
235 {
236         int32_t nfingers, i;
237
238         EVDEV_LOCK_ASSERT(evdev);
239
240         nfingers = evdev_count_fingers(evdev);
241         evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
242
243         if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
244                 /* Echo 0-th MT-slot as ST-slot */
245                 for (i = 0; i < nitems(evdev_mtstmap); i++)
246                         if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
247                                 evdev_send_event(evdev, EV_ABS,
248                                     evdev_mtstmap[i][1],
249                                     evdev_get_mt_value(evdev, 0,
250                                     evdev_mtstmap[i][0]));
251
252         /* Touchscreens should not report tool taps */
253         if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
254                 evdev_send_nfingers(evdev, nfingers);
255
256         if (nfingers == 0)
257                 evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
258 }
259
260 void
261 evdev_push_mt_compat(struct evdev_dev *evdev)
262 {
263
264         EVDEV_ENTER(evdev);
265         evdev_send_mt_compat(evdev);
266         EVDEV_EXIT(evdev);
267 }
268
269 void
270 evdev_send_mt_autorel(struct evdev_dev *evdev)
271 {
272         int32_t slot;
273
274         EVDEV_LOCK_ASSERT(evdev);
275
276         for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
277                 if (evdev->ev_mt->ev_mt_slots[slot].ev_report !=
278                     evdev->ev_report_count &&
279                     evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){
280                         evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
281                         evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID,
282                             -1);
283                 }
284         }
285 }