• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*****************************************************************************
2  *
3  * mtdev - Multitouch Protocol Translation Library (MIT license)
4  *
5  * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
6  * Copyright (C) 2010 Canonical Ltd.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  *
27  ****************************************************************************/
28 
29 #include "state.h"
30 
31 static const int SN_COORD = 250;	/* coordinate signal-to-noise ratio */
32 static const int SN_WIDTH = 100;	/* width signal-to-noise ratio */
33 static const int SN_ORIENT = 10;	/* orientation signal-to-noise ratio */
34 
35 #define LONG_BITS (sizeof(long) * 8)
36 #define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
37 
getbit(const unsigned long * map,int key)38 static inline int getbit(const unsigned long *map, int key)
39 {
40 	return (map[key / LONG_BITS] >> (key % LONG_BITS)) & 0x01;
41 }
42 
getabs(struct input_absinfo * abs,int key,int fd)43 static int getabs(struct input_absinfo *abs, int key, int fd)
44 {
45 	int rc;
46 	SYSCALL(rc = ioctl(fd, EVIOCGABS(key), abs));
47 	return rc >= 0;
48 }
49 
get_info(struct mtdev * dev,int code)50 static struct input_absinfo *get_info(struct mtdev *dev, int code)
51 {
52 	int ix;
53 
54 	if (code == ABS_MT_SLOT)
55 		return &dev->slot;
56 	if (!mtdev_is_absmt(code))
57 		return NULL;
58 
59 	ix = mtdev_abs2mt(code);
60 	if (ix < LEGACY_API_NUM_MT_AXES)
61 		return &dev->abs[ix];
62 	else
63 		return &dev->state->ext_abs[ix - LEGACY_API_NUM_MT_AXES];
64 }
65 
set_info(struct mtdev * dev,int code,const unsigned long * bits,int fd)66 static void set_info(struct mtdev *dev, int code,
67 		     const unsigned long *bits, int fd)
68 {
69 	int has = getbit(bits, code) && getabs(get_info(dev, code), code, fd);
70 	mtdev_set_mt_event(dev, code, has);
71 }
72 
default_fuzz(struct mtdev * dev,int code,int sn)73 static void default_fuzz(struct mtdev *dev, int code, int sn)
74 {
75 	struct input_absinfo *abs = get_info(dev, code);
76 	if (!mtdev_has_mt_event(dev, code) || abs->fuzz)
77 		return;
78 	abs->fuzz = (abs->maximum - abs->minimum) / sn;
79 }
80 
mtdev_set_slots(struct mtdev * dev,int fd)81 static int mtdev_set_slots(struct mtdev *dev, int fd)
82 {
83 	struct { unsigned code; int values[DIM_FINGER]; } req;
84 	struct mtdev_state *state = dev->state;
85 	int rc, i, s, nslot;
86 
87 	nslot = mtdev_get_abs_maximum(dev, ABS_MT_SLOT) + 1;
88 
89 	for (i = 0; i < MT_ABS_SIZE; i++) {
90 		req.code = mtdev_mt2abs(i);
91 		if (!mtdev_has_mt_event(dev, req.code))
92 			continue;
93 		SYSCALL(rc = ioctl(fd, EVIOCGMTSLOTS(sizeof(req)), &req));
94 		if (rc < 0)
95 			return rc;
96 		for (s = 0; s < DIM_FINGER && s < nslot; s++)
97 			set_sval(&state->data[s], i, req.values[s]);
98 	}
99 
100 	return 0;
101 }
102 
mtdev_configure(struct mtdev * dev,int fd)103 int mtdev_configure(struct mtdev *dev, int fd)
104 {
105 	unsigned long absbits[NLONGS(ABS_MAX)];
106 	int rc, i;
107 
108 	SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
109 	if (rc < 0)
110 		return rc;
111 
112 	set_info(dev, ABS_MT_SLOT, absbits, fd);
113 	for (i = 0; i < MT_ABS_SIZE; i++)
114 		set_info(dev, mtdev_mt2abs(i), absbits, fd);
115 
116 	dev->has_mtdata = mtdev_has_mt_event(dev, ABS_MT_POSITION_X) &&
117 		mtdev_has_mt_event(dev, ABS_MT_POSITION_Y);
118 
119 	if (!mtdev_has_mt_event(dev, ABS_MT_POSITION_X))
120 		getabs(get_info(dev, ABS_MT_POSITION_X), ABS_X, fd);
121 	if (!mtdev_has_mt_event(dev, ABS_MT_POSITION_Y))
122 		getabs(get_info(dev, ABS_MT_POSITION_Y), ABS_Y, fd);
123 	if (!mtdev_has_mt_event(dev, ABS_MT_PRESSURE))
124 		getabs(get_info(dev, ABS_MT_PRESSURE), ABS_PRESSURE, fd);
125 
126 	if (!mtdev_has_mt_event(dev, ABS_MT_TRACKING_ID)) {
127 		mtdev_set_abs_minimum(dev, ABS_MT_TRACKING_ID, MT_ID_MIN);
128 		mtdev_set_abs_maximum(dev, ABS_MT_TRACKING_ID, MT_ID_MAX);
129 	}
130 
131 	default_fuzz(dev, ABS_MT_POSITION_X, SN_COORD);
132 	default_fuzz(dev, ABS_MT_POSITION_Y, SN_COORD);
133 	default_fuzz(dev, ABS_MT_TOUCH_MAJOR, SN_WIDTH);
134 	default_fuzz(dev, ABS_MT_TOUCH_MINOR, SN_WIDTH);
135 	default_fuzz(dev, ABS_MT_WIDTH_MAJOR, SN_WIDTH);
136 	default_fuzz(dev, ABS_MT_WIDTH_MINOR, SN_WIDTH);
137 	default_fuzz(dev, ABS_MT_ORIENTATION, SN_ORIENT);
138 
139 	if (dev->has_slot)
140 		mtdev_set_slots(dev, fd);
141 
142 	return 0;
143 }
144 
mtdev_has_mt_event(const struct mtdev * dev,int code)145 int mtdev_has_mt_event(const struct mtdev *dev, int code)
146 {
147 	int ix;
148 
149 	if (code == ABS_MT_SLOT)
150 		return dev->has_slot;
151 	if (!mtdev_is_absmt(code))
152 		return 0;
153 
154 	ix = mtdev_abs2mt(code);
155 	if (ix < LEGACY_API_NUM_MT_AXES)
156 		return dev->has_abs[ix];
157 	else
158 		return dev->state->has_ext_abs[ix - LEGACY_API_NUM_MT_AXES];
159 }
160 
mtdev_get_abs_minimum(const struct mtdev * dev,int code)161 int mtdev_get_abs_minimum(const struct mtdev *dev, int code)
162 {
163 	const struct input_absinfo *abs = get_info((struct mtdev *)dev, code);
164 	return abs ? abs->minimum : 0;
165 }
166 
mtdev_get_abs_maximum(const struct mtdev * dev,int code)167 int mtdev_get_abs_maximum(const struct mtdev *dev, int code)
168 {
169 	const struct input_absinfo *abs = get_info((struct mtdev *)dev, code);
170 	return abs ? abs->maximum : 0;
171 }
172 
mtdev_get_abs_fuzz(const struct mtdev * dev,int code)173 int mtdev_get_abs_fuzz(const struct mtdev *dev, int code)
174 {
175 	const struct input_absinfo *abs = get_info((struct mtdev *)dev, code);
176 	return abs ? abs->fuzz : 0;
177 }
178 
mtdev_get_abs_resolution(const struct mtdev * dev,int code)179 int mtdev_get_abs_resolution(const struct mtdev *dev, int code)
180 {
181 	const struct input_absinfo *abs = get_info((struct mtdev *)dev, code);
182 	return abs ? abs->resolution : 0;
183 }
184 
mtdev_set_abs_minimum(struct mtdev * dev,int code,int value)185 void mtdev_set_abs_minimum(struct mtdev *dev, int code, int value)
186 {
187 	struct input_absinfo *abs = get_info(dev, code);
188 	if (abs)
189 		abs->minimum = value;
190 }
191 
mtdev_set_mt_event(struct mtdev * dev,int code,int value)192 void mtdev_set_mt_event(struct mtdev *dev, int code, int value)
193 {
194 	int ix;
195 
196 	if (code == ABS_MT_SLOT)
197 		dev->has_slot = value;
198 	if (!mtdev_is_absmt(code))
199 		return;
200 
201 	ix = mtdev_abs2mt(code);
202 	if (ix < LEGACY_API_NUM_MT_AXES)
203 		dev->has_abs[ix] = value;
204 	else
205 		dev->state->has_ext_abs[ix - LEGACY_API_NUM_MT_AXES] = value;
206 }
207 
mtdev_set_abs_maximum(struct mtdev * dev,int code,int value)208 void mtdev_set_abs_maximum(struct mtdev *dev, int code, int value)
209 {
210 	struct input_absinfo *abs = get_info(dev, code);
211 	if (abs)
212 		abs->maximum = value;
213 }
214 
mtdev_set_abs_fuzz(struct mtdev * dev,int code,int value)215 void mtdev_set_abs_fuzz(struct mtdev *dev, int code, int value)
216 {
217 	struct input_absinfo *abs = get_info(dev, code);
218 	if (abs)
219 		abs->fuzz = value;
220 }
221 
mtdev_set_abs_resolution(struct mtdev * dev,int code,int value)222 void mtdev_set_abs_resolution(struct mtdev *dev, int code, int value)
223 {
224 	struct input_absinfo *abs = get_info(dev, code);
225 	if (abs)
226 		abs->resolution = value;
227 }
228 
229