]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/evdev/evdev_mt.c
Update the device tree source files to a Linux 4.7-RC.
[FreeBSD/FreeBSD.git] / sys / dev / evdev / evdev_mt.c
1 /*-
2  * Copyright (c) 2016 Vladimir Kondratyev <wulf@cicgroup.ru>
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/malloc.h>
31 #include <sys/lock.h>
32 #include <sys/mutex.h>
33 #include <sys/systm.h>
34
35 #include <dev/evdev/input.h>
36 #include <dev/evdev/evdev.h>
37 #include <dev/evdev/evdev_private.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_last_reported_slot = slot;
116 }
117
118 inline int32_t
119 evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code)
120 {
121
122         return (evdev->ev_mt->
123             ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]);
124 }
125
126 inline void
127 evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code,
128     int32_t value)
129 {
130
131         if (code == ABS_MT_TRACKING_ID && value == -1)
132                 evdev->ev_mt->ev_mt_slots[slot].ev_report =
133                     evdev->ev_report_count;
134
135         evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] =
136             value;
137 }
138
139 int32_t
140 evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
141 {
142         int32_t tr_id, slot, free_slot = -1;
143
144         for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
145                 tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID);
146                 if (tr_id == tracking_id)
147                         return (slot);
148                 /*
149                  * Its possible that slot will be reassigned in a place of just
150                  * released one within the same report. To avoid this compare
151                  * report counter with slot`s report number updated with each
152                  * ABS_MT_TRACKING_ID change.
153                  */
154                 if (free_slot == -1 && tr_id == -1 &&
155                     evdev->ev_mt->ev_mt_slots[slot].ev_report !=
156                     evdev->ev_report_count)
157                         free_slot = slot;
158         }
159
160         return (free_slot);
161 }
162
163 void
164 evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers)
165 {
166         int32_t i;
167
168         for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++)
169                 evdev_support_key(evdev, evdev_fngmap[i]);
170 }
171
172 void
173 evdev_support_mt_compat(struct evdev_dev *evdev)
174 {
175         int32_t i;
176
177         if (evdev->ev_absinfo == NULL)
178                 return;
179
180         evdev_support_event(evdev, EV_KEY);
181         evdev_support_key(evdev, BTN_TOUCH);
182
183         /* Touchscreens should not advertise tap tool capabilities */
184         if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
185                 evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
186
187         /* Echo 0-th MT-slot as ST-slot */
188         for (i = 0; i < nitems(evdev_mtstmap); i++)
189                 if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
190                         evdev_support_abs(evdev, evdev_mtstmap[i][1],
191                             evdev->ev_absinfo[evdev_mtstmap[i][0]].value,
192                             evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum,
193                             evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum,
194                             evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz,
195                             evdev->ev_absinfo[evdev_mtstmap[i][0]].flat,
196                             evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution);
197 }
198
199 static int32_t
200 evdev_count_fingers(struct evdev_dev *evdev)
201 {
202         int32_t nfingers = 0, i;
203
204         for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
205                 if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
206                         nfingers++;
207
208         return (nfingers);
209 }
210
211 static void
212 evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers)
213 {
214         int32_t i;
215
216         EVDEV_LOCK_ASSERT(evdev);
217
218         if (nfingers > nitems(evdev_fngmap))
219                 nfingers = nitems(evdev_fngmap);
220
221         for (i = 0; i < nitems(evdev_fngmap); i++)
222                 evdev_send_event(evdev, EV_KEY, evdev_fngmap[i],
223                     nfingers == i + 1);
224 }
225
226 void
227 evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers)
228 {
229
230         EVDEV_LOCK(evdev);
231         evdev_send_nfingers(evdev, nfingers);
232         EVDEV_UNLOCK(evdev);
233 }
234
235 void
236 evdev_send_mt_compat(struct evdev_dev *evdev)
237 {
238         int32_t nfingers, i;
239
240         EVDEV_LOCK_ASSERT(evdev);
241
242         nfingers = evdev_count_fingers(evdev);
243         evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
244
245         if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
246                 /* Echo 0-th MT-slot as ST-slot */
247                 for (i = 0; i < nitems(evdev_mtstmap); i++)
248                         if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
249                                 evdev_send_event(evdev, EV_ABS,
250                                     evdev_mtstmap[i][1],
251                                     evdev_get_mt_value(evdev, 0,
252                                     evdev_mtstmap[i][0]));
253
254         /* Touchscreens should not report tool taps */
255         if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
256                 evdev_send_nfingers(evdev, nfingers);
257
258         if (nfingers == 0)
259                 evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
260 }
261
262 void
263 evdev_push_mt_compat(struct evdev_dev *evdev)
264 {
265
266         EVDEV_LOCK(evdev);
267         evdev_send_mt_compat(evdev);
268         EVDEV_UNLOCK(evdev);
269 }