File: galax-raw.c

package info (click to toggle)
tslib 1.22-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,016 kB
  • sloc: ansic: 18,859; sh: 4,167; makefile: 550
file content (339 lines) | stat: -rw-r--r-- 8,210 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/*
 * tslib/plugins/galax-raw.c
 *
 * Inspired from input-raw.c
 * 2009.05 Fred Salabartan
 *
 * Add support for version 0100 by Oskari Rauta <oskari.rauta@gmail.com> 2013
 * Modify by Jean-Baptiste Théou <jean-baptiste.theou@vodalys.com> (2013)
 *
 * This file is placed under the LGPL. Please see the file
 * COPYING for more details.
 *
 * SPDX-License-Identifier: LGPL-2.1
 *
 *
 * Plugin for "eGalax Inc. Touch" (using usbhid driver)
 * (Vendor=0eef Product=0001 Version=0112/210/0100)
 */

#include "config.h"

#include <errno.h>
#include <stdio.h>
#include <limits.h>
#include <stdint.h>

#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/time.h>
#include <sys/types.h>

#ifdef __FreeBSD__
#include <dev/evdev/input.h>
#else
#include <linux/input.h>
#endif
#ifndef EV_SYN /* 2.4 kernel headers */
# define EV_SYN 0x00
#endif
#ifndef EV_CNT
# define EV_CNT (EV_MAX+1)
#endif
#ifndef ABS_CNT
# define ABS_CNT (ABS_MAX+1)
#endif
#ifndef KEY_CNT
# define KEY_CNT (KEY_MAX+1)
#endif

#ifndef ABS_MT_DISTANCE /* < 2.6.38 kernel headers */
# define ABS_MT_DISTANCE         0x3b    /* Contact hover distance */
#endif

#include "tslib-private.h"

#define GRAB_EVENTS_WANTED  1
#define GRAB_EVENTS_ACTIVE  2

#define BITS_PER_BYTE	8
#define BITS_PER_LONG	(sizeof(long) * BITS_PER_BYTE)

#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG)

#define VERSION_0112 1
#define VERSION_210  2
#define VERSION_0100 3
/* VERSION_210 must use /dev/input/event1 */


struct tslib_galax {
	struct tslib_module_info module;

	int current_x;
	int current_y;
	int current_p;
	int model_version;
	int sane_fd;
	int grab_events;
};




static int ts_galax_check_fd(struct tslib_galax *i)
{
	struct tsdev *ts = i->module.dev;
	int version;
	long evbit[BITS_TO_LONGS(EV_CNT)];
	long absbit[BITS_TO_LONGS(ABS_CNT)];
	long keybit[BITS_TO_LONGS(KEY_CNT)];
	struct input_id infos;

	if (ioctl(ts->fd, EVIOCGVERSION, &version) < 0) {
		fprintf(stderr,
			"tslib: Selected device is not a Linux input event device\n");
		return -1;
	}

	if (version < EV_VERSION) {
		fprintf(stderr,
			"tslib: Selected device uses a different version of the event protocol than tslib was compiled for\n");
		return -1;
	}

	if ((ioctl(ts->fd, EVIOCGID, &infos) < 0)) {
		fprintf(stderr, "tslib: warning, can not read device identifier\n");
	} else if (infos.bustype != 3 || infos.vendor != 0x0EEF ||
		   (infos.product != 0x0001 && infos.product != 0x7200 && infos.product != 0x7201)) {
		fprintf(stderr, "tslib: this is not an eGalax touchscreen (3,0x0EEF,1/7200/7201,0x0112)\n"
			"Your device: bus=%d, vendor=0x%X, product=0x%X, version=0x%X\n",
			infos.bustype, infos.vendor, infos.product, infos.version);
		return -1;
	}
	if (infos.version == 0x0112) {
		i->model_version = VERSION_0112;
	} else if (infos.version == 0x210) {
		i->model_version = VERSION_210;
	} else if (infos.version == 0x0100) {
		i->model_version = VERSION_0100;
	} else {
		fprintf(stderr, "Unsupported model\n");
		return -1;
	}

	if ((ioctl(ts->fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
		!(evbit[BIT_WORD(EV_ABS)] & BIT_MASK(EV_ABS)) ||
		!(evbit[BIT_WORD(EV_KEY)] & BIT_MASK(EV_KEY))) {
		fprintf(stderr,
			"tslib: Selected device is not a touchscreen (must support ABS and KEY event types)\n");
		return -1;
	}

	if ((ioctl(ts->fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit)) < 0 ||
		!(absbit[BIT_WORD(ABS_X)] & BIT_MASK(ABS_X)) ||
		!(absbit[BIT_WORD(ABS_Y)] & BIT_MASK(ABS_Y))) {
		fprintf(stderr,
			"tslib: Selected device is not a touchscreen (must support ABS_X and ABS_Y events)\n");
		return -1;
	}

	/* Since some touchscreens (eg. infrared) physically can't measure pressure,
	 * the input system doesn't report it on those. Tslib relies on pressure, thus
	 * we set it to constant 255. It's still controlled by BTN_TOUCH - when not
	 * touched, the pressure is forced to 0.
	 */
	if (!(absbit[BIT_WORD(ABS_PRESSURE)] & BIT_MASK(ABS_PRESSURE))) {
		i->current_p = 255;

		if ((ioctl(ts->fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
			!(keybit[BIT_WORD(BTN_TOUCH)] & BIT_MASK(BTN_TOUCH) ||
			  keybit[BIT_WORD(BTN_LEFT)] & BIT_MASK(BTN_LEFT))) {
			fprintf(stderr,
				"tslib: Selected device is not a touchscreen (must support BTN_TOUCH or BTN_LEFT events)\n");
			return -1;
		}
	}

	if (!(evbit[BIT_WORD(EV_SYN)] & BIT_MASK(EV_SYN))) {
		fprintf(stderr, "tslib: device does not use EV_SYN\n");
		return -1;
	}

	if (i->grab_events == GRAB_EVENTS_WANTED) {
		if (ioctl(ts->fd, EVIOCGRAB, (void *)1)) {
			fprintf(stderr,
				"tslib: unable to grab selected input device\n");
			return -1;
		}
		i->grab_events = GRAB_EVENTS_ACTIVE;
	}

	return 0;
}

static int ts_galax_read(struct tslib_module_info *inf,
			 struct ts_sample *samp, int nr)
{
	struct tslib_galax *i = (struct tslib_galax *)inf;
	struct tsdev *ts = inf->dev;
	struct input_event ev;
	int ret = nr;
	int total = 0;

	if (i->sane_fd == 0)
		i->sane_fd = ts_galax_check_fd(i);

	if (i->sane_fd == -1)
		return 0;

	while (total < nr) {
		ret = read(ts->fd, &ev, sizeof(struct input_event));
		if (ret < (int)sizeof(struct input_event)) {
			total = -1;
			break;
		}

		switch (ev.type) {
		case EV_KEY:
			switch (ev.code) {
			case BTN_TOUCH:
				if (ev.value == 0) {
					/* pen up */
					i->current_x = 0;
					i->current_y = 0;
					i->current_p = 0;
				} else {
					i->current_p = 255;
				}
				break;
			}
			break;
		case EV_SYN:
			/* Fill out a new complete event */
			samp->x = i->current_x;
			samp->y = i->current_y;
			samp->pressure = i->current_p;
			samp->tv = ev.time;
			samp++;
			total++;
			break;

		case EV_ABS:
			if (i->model_version == VERSION_0112) {
				switch (ev.code) {
				case ABS_X+2: i->current_x = ev.value; break;
				case ABS_Y+2: i->current_y = ev.value; break;
				case ABS_PRESSURE: i->current_p = ev.value; break;
				}
			} else if (i->model_version == VERSION_210) {
				switch (ev.code) {
				case ABS_X: i->current_x = ev.value; break;
				case ABS_Y: i->current_y = ev.value; break;
				case ABS_PRESSURE: i->current_p = ev.value; break;
				case ABS_MT_DISTANCE:
					if (ev.value > 0)
						i->current_p = 0;
					else
						i->current_p = 255;

					break;
				}
			} else if (i->model_version == VERSION_0100) {
				switch (ev.code) {
				case ABS_X: i->current_x = ev.value; break;
				case ABS_Y: i->current_y = ev.value; break;
				case ABS_PRESSURE: i->current_p = ev.value; break;
				}
			}
			break;
		}
		ret = total;
	}
	return ret;
}

static int ts_galax_fini(struct tslib_module_info *inf)
{
	struct tslib_galax *i = (struct tslib_galax *)inf;
	struct tsdev *ts = inf->dev;

	if (i->grab_events == GRAB_EVENTS_ACTIVE) {
		if (ioctl(ts->fd, EVIOCGRAB, (void *)0)) {
			fprintf(stderr,
				"tslib: Unable to un-grab selected input device\n");
		}
	}

	free(inf);
	return 0;
}

static const struct tslib_ops __ts_galax_ops = {
	.read = ts_galax_read,
	.fini = ts_galax_fini,
};

static int parse_raw_grab(struct tslib_module_info *inf, char *str, void *data)
{
	struct tslib_galax *i = (struct tslib_galax *)inf;
	unsigned long v;
	int err = errno;

	v = strtoul(str, NULL, 0);

	if (v == ULONG_MAX && errno == ERANGE)
	return -1;

	errno = err;
	switch ((int)(intptr_t)data) {
	case 1:
		if (v)
			i->grab_events = GRAB_EVENTS_WANTED;
		break;
	default:
		return -1;
	}
	return 0;
}

static const struct tslib_vars raw_vars[] = {
	{ "grab_events", (void *)1, parse_raw_grab },
};

#define NR_VARS (sizeof(raw_vars) / sizeof(raw_vars[0]))


TSAPI struct tslib_module_info *galax_mod_init(__attribute__ ((unused)) struct tsdev *dev,
					       const char *params)
{
	struct tslib_galax *i;

	i = malloc(sizeof (struct tslib_galax));
	if (i == NULL)
		return NULL;

	i->module.ops = &__ts_galax_ops;
	i->current_x = 0;
	i->current_y = 0;
	i->current_p = 0;
	i->sane_fd = 0;
	i->grab_events = 0;

	if (tslib_parse_vars(&i->module, raw_vars, NR_VARS, params)) {
		free(i);
		return NULL;
	}

	return &(i->module);
}

#ifndef TSLIB_STATIC_GALAX_MODULE
	TSLIB_MODULE_INIT(galax_mod_init);
#endif