1c0abf9e6Sopenharmony_ci// SPDX-License-Identifier: MIT
2c0abf9e6Sopenharmony_ci/*
3c0abf9e6Sopenharmony_ci * Copyright © 2014 Red Hat, Inc.
4c0abf9e6Sopenharmony_ci */
5c0abf9e6Sopenharmony_ci
6c0abf9e6Sopenharmony_ci#include "config.h"
7c0abf9e6Sopenharmony_ci
8c0abf9e6Sopenharmony_ci#include <assert.h>
9c0abf9e6Sopenharmony_ci#include <errno.h>
10c0abf9e6Sopenharmony_ci#include <fcntl.h>
11c0abf9e6Sopenharmony_ci#include <getopt.h>
12c0abf9e6Sopenharmony_ci#include <libgen.h>
13c0abf9e6Sopenharmony_ci#include <limits.h>
14c0abf9e6Sopenharmony_ci#include <linux/input.h>
15c0abf9e6Sopenharmony_ci#include <stdbool.h>
16c0abf9e6Sopenharmony_ci#include <stdio.h>
17c0abf9e6Sopenharmony_ci#include <stdlib.h>
18c0abf9e6Sopenharmony_ci#include <string.h>
19c0abf9e6Sopenharmony_ci#include <sys/stat.h>
20c0abf9e6Sopenharmony_ci#include <sys/types.h>
21c0abf9e6Sopenharmony_ci#include <unistd.h>
22c0abf9e6Sopenharmony_ci
23c0abf9e6Sopenharmony_ci#include "libevdev/libevdev.h"
24c0abf9e6Sopenharmony_ci
25c0abf9e6Sopenharmony_cistatic void
26c0abf9e6Sopenharmony_ciusage(const char *progname)
27c0abf9e6Sopenharmony_ci{
28c0abf9e6Sopenharmony_ci	printf("%s --abs <axis> [--min min] [--max max] [--res res] [--fuzz fuzz] [--flat flat] /dev/input/eventXYZ\n"
29c0abf9e6Sopenharmony_ci	       "\tChange the absinfo struct for the named axis\n"
30c0abf9e6Sopenharmony_ci	       "%s --resolution res[,yres] /dev/input/eventXYZ\n"
31c0abf9e6Sopenharmony_ci	       "\tChange the x/y resolution on the given device\n"
32c0abf9e6Sopenharmony_ci	       "%s --led <led> --on|--off /dev/input/eventXYZ\n"
33c0abf9e6Sopenharmony_ci	       "\tEnable or disable the named LED\n",
34c0abf9e6Sopenharmony_ci	       progname,
35c0abf9e6Sopenharmony_ci	       progname,
36c0abf9e6Sopenharmony_ci	       progname);
37c0abf9e6Sopenharmony_ci}
38c0abf9e6Sopenharmony_ci
39c0abf9e6Sopenharmony_cienum mode {
40c0abf9e6Sopenharmony_ci	MODE_NONE = 0,
41c0abf9e6Sopenharmony_ci	MODE_ABS,
42c0abf9e6Sopenharmony_ci	MODE_LED,
43c0abf9e6Sopenharmony_ci	MODE_RESOLUTION,
44c0abf9e6Sopenharmony_ci	MODE_HELP,
45c0abf9e6Sopenharmony_ci};
46c0abf9e6Sopenharmony_ci
47c0abf9e6Sopenharmony_cienum opts {
48c0abf9e6Sopenharmony_ci	OPT_ABS = 1 << 0,
49c0abf9e6Sopenharmony_ci	OPT_MIN = 1 << 1,
50c0abf9e6Sopenharmony_ci	OPT_MAX = 1 << 2,
51c0abf9e6Sopenharmony_ci	OPT_FUZZ = 1 << 3,
52c0abf9e6Sopenharmony_ci	OPT_FLAT = 1 << 4,
53c0abf9e6Sopenharmony_ci	OPT_RES = 1 << 5,
54c0abf9e6Sopenharmony_ci	OPT_LED = 1 << 6,
55c0abf9e6Sopenharmony_ci	OPT_ON = 1 << 7,
56c0abf9e6Sopenharmony_ci	OPT_OFF = 1 << 8,
57c0abf9e6Sopenharmony_ci	OPT_RESOLUTION = 1 << 9,
58c0abf9e6Sopenharmony_ci	OPT_HELP = 1 << 10,
59c0abf9e6Sopenharmony_ci};
60c0abf9e6Sopenharmony_ci
61c0abf9e6Sopenharmony_cistatic bool
62c0abf9e6Sopenharmony_ciparse_resolution_argument(const char *arg, int *xres, int *yres)
63c0abf9e6Sopenharmony_ci{
64c0abf9e6Sopenharmony_ci	int matched;
65c0abf9e6Sopenharmony_ci
66c0abf9e6Sopenharmony_ci	matched = sscanf(arg, "%d,%d", xres, yres);
67c0abf9e6Sopenharmony_ci
68c0abf9e6Sopenharmony_ci	switch(matched) {
69c0abf9e6Sopenharmony_ci		case 2:
70c0abf9e6Sopenharmony_ci			break;
71c0abf9e6Sopenharmony_ci		case 1:
72c0abf9e6Sopenharmony_ci			*yres = *xres;
73c0abf9e6Sopenharmony_ci			break;
74c0abf9e6Sopenharmony_ci		default:
75c0abf9e6Sopenharmony_ci			return false;
76c0abf9e6Sopenharmony_ci	}
77c0abf9e6Sopenharmony_ci
78c0abf9e6Sopenharmony_ci	return true;
79c0abf9e6Sopenharmony_ci}
80c0abf9e6Sopenharmony_ci
81c0abf9e6Sopenharmony_cistatic inline bool
82c0abf9e6Sopenharmony_cisafe_atoi(const char *str, int *val)
83c0abf9e6Sopenharmony_ci{
84c0abf9e6Sopenharmony_ci        char *endptr;
85c0abf9e6Sopenharmony_ci        long v;
86c0abf9e6Sopenharmony_ci
87c0abf9e6Sopenharmony_ci        v = strtol(str, &endptr, 10);
88c0abf9e6Sopenharmony_ci        if (str == endptr)
89c0abf9e6Sopenharmony_ci                return false;
90c0abf9e6Sopenharmony_ci        if (*str != '\0' && *endptr != '\0')
91c0abf9e6Sopenharmony_ci                return false;
92c0abf9e6Sopenharmony_ci
93c0abf9e6Sopenharmony_ci        if (v > INT_MAX || v < INT_MIN)
94c0abf9e6Sopenharmony_ci                return false;
95c0abf9e6Sopenharmony_ci
96c0abf9e6Sopenharmony_ci        *val = v;
97c0abf9e6Sopenharmony_ci        return true;
98c0abf9e6Sopenharmony_ci}
99c0abf9e6Sopenharmony_ci
100c0abf9e6Sopenharmony_cistatic int
101c0abf9e6Sopenharmony_ciparse_event_code(int type, const char *str)
102c0abf9e6Sopenharmony_ci{
103c0abf9e6Sopenharmony_ci	int code;
104c0abf9e6Sopenharmony_ci
105c0abf9e6Sopenharmony_ci	code = libevdev_event_code_from_name(type, str);
106c0abf9e6Sopenharmony_ci	if (code != -1)
107c0abf9e6Sopenharmony_ci		return code;
108c0abf9e6Sopenharmony_ci
109c0abf9e6Sopenharmony_ci	if (safe_atoi(str, &code))
110c0abf9e6Sopenharmony_ci		return code;
111c0abf9e6Sopenharmony_ci
112c0abf9e6Sopenharmony_ci	return -1;
113c0abf9e6Sopenharmony_ci}
114c0abf9e6Sopenharmony_ci
115c0abf9e6Sopenharmony_cistatic int
116c0abf9e6Sopenharmony_ciparse_options_abs(int argc, char **argv, unsigned int *changes,
117c0abf9e6Sopenharmony_ci		  int *axis, struct input_absinfo *absinfo)
118c0abf9e6Sopenharmony_ci{
119c0abf9e6Sopenharmony_ci	int rc = 1;
120c0abf9e6Sopenharmony_ci	int c;
121c0abf9e6Sopenharmony_ci	int option_index = 0;
122c0abf9e6Sopenharmony_ci	static struct option opts[] = {
123c0abf9e6Sopenharmony_ci		{ "abs", 1, 0, OPT_ABS },
124c0abf9e6Sopenharmony_ci		{ "min", 1, 0, OPT_MIN },
125c0abf9e6Sopenharmony_ci		{ "max", 1, 0, OPT_MAX },
126c0abf9e6Sopenharmony_ci		{ "fuzz", 1, 0, OPT_FUZZ },
127c0abf9e6Sopenharmony_ci		{ "flat", 1, 0, OPT_FLAT },
128c0abf9e6Sopenharmony_ci		{ "res", 1, 0, OPT_RES },
129c0abf9e6Sopenharmony_ci		{ NULL, 0, 0, 0 },
130c0abf9e6Sopenharmony_ci	};
131c0abf9e6Sopenharmony_ci
132c0abf9e6Sopenharmony_ci	if (argc < 2)
133c0abf9e6Sopenharmony_ci		goto error;
134c0abf9e6Sopenharmony_ci
135c0abf9e6Sopenharmony_ci	optind = 1;
136c0abf9e6Sopenharmony_ci	while (1) {
137c0abf9e6Sopenharmony_ci		c = getopt_long(argc, argv, "h", opts, &option_index);
138c0abf9e6Sopenharmony_ci		if (c == -1)
139c0abf9e6Sopenharmony_ci			break;
140c0abf9e6Sopenharmony_ci
141c0abf9e6Sopenharmony_ci		switch (c) {
142c0abf9e6Sopenharmony_ci			case OPT_ABS:
143c0abf9e6Sopenharmony_ci				*axis = parse_event_code(EV_ABS, optarg);
144c0abf9e6Sopenharmony_ci				if (*axis == -1)
145c0abf9e6Sopenharmony_ci					goto error;
146c0abf9e6Sopenharmony_ci				break;
147c0abf9e6Sopenharmony_ci			case OPT_MIN:
148c0abf9e6Sopenharmony_ci				absinfo->minimum = atoi(optarg);
149c0abf9e6Sopenharmony_ci				break;
150c0abf9e6Sopenharmony_ci			case OPT_MAX:
151c0abf9e6Sopenharmony_ci				absinfo->maximum = atoi(optarg);
152c0abf9e6Sopenharmony_ci				break;
153c0abf9e6Sopenharmony_ci			case OPT_FUZZ:
154c0abf9e6Sopenharmony_ci				absinfo->fuzz = atoi(optarg);
155c0abf9e6Sopenharmony_ci				break;
156c0abf9e6Sopenharmony_ci			case OPT_FLAT:
157c0abf9e6Sopenharmony_ci				absinfo->flat = atoi(optarg);
158c0abf9e6Sopenharmony_ci				break;
159c0abf9e6Sopenharmony_ci			case OPT_RES:
160c0abf9e6Sopenharmony_ci				absinfo->resolution = atoi(optarg);
161c0abf9e6Sopenharmony_ci				break;
162c0abf9e6Sopenharmony_ci			default:
163c0abf9e6Sopenharmony_ci				goto error;
164c0abf9e6Sopenharmony_ci		}
165c0abf9e6Sopenharmony_ci		*changes |= c;
166c0abf9e6Sopenharmony_ci	}
167c0abf9e6Sopenharmony_ci	rc = 0;
168c0abf9e6Sopenharmony_cierror:
169c0abf9e6Sopenharmony_ci	return rc;
170c0abf9e6Sopenharmony_ci}
171c0abf9e6Sopenharmony_ci
172c0abf9e6Sopenharmony_cistatic int
173c0abf9e6Sopenharmony_ciparse_options_led(int argc, char **argv, int *led, int *led_state)
174c0abf9e6Sopenharmony_ci{
175c0abf9e6Sopenharmony_ci	int rc = 1;
176c0abf9e6Sopenharmony_ci	int c;
177c0abf9e6Sopenharmony_ci	int option_index = 0;
178c0abf9e6Sopenharmony_ci	static struct option opts[] = {
179c0abf9e6Sopenharmony_ci		{ "led", 1, 0, OPT_LED },
180c0abf9e6Sopenharmony_ci		{ "on", 0, 0, OPT_ON },
181c0abf9e6Sopenharmony_ci		{ "off", 0, 0, OPT_OFF },
182c0abf9e6Sopenharmony_ci		{ NULL, 0, 0, 0 },
183c0abf9e6Sopenharmony_ci	};
184c0abf9e6Sopenharmony_ci
185c0abf9e6Sopenharmony_ci	if (argc < 2)
186c0abf9e6Sopenharmony_ci		goto error;
187c0abf9e6Sopenharmony_ci
188c0abf9e6Sopenharmony_ci	optind = 1;
189c0abf9e6Sopenharmony_ci	while (1) {
190c0abf9e6Sopenharmony_ci		c = getopt_long(argc, argv, "h", opts, &option_index);
191c0abf9e6Sopenharmony_ci		if (c == -1)
192c0abf9e6Sopenharmony_ci			break;
193c0abf9e6Sopenharmony_ci
194c0abf9e6Sopenharmony_ci		switch (c) {
195c0abf9e6Sopenharmony_ci			case OPT_LED:
196c0abf9e6Sopenharmony_ci				*led = parse_event_code(EV_LED, optarg);
197c0abf9e6Sopenharmony_ci				if (*led == -1)
198c0abf9e6Sopenharmony_ci					goto error;
199c0abf9e6Sopenharmony_ci				break;
200c0abf9e6Sopenharmony_ci			case OPT_ON:
201c0abf9e6Sopenharmony_ci				if (*led_state != -1)
202c0abf9e6Sopenharmony_ci					goto error;
203c0abf9e6Sopenharmony_ci				*led_state = 1;
204c0abf9e6Sopenharmony_ci				break;
205c0abf9e6Sopenharmony_ci			case OPT_OFF:
206c0abf9e6Sopenharmony_ci				if (*led_state != -1)
207c0abf9e6Sopenharmony_ci					goto error;
208c0abf9e6Sopenharmony_ci				*led_state = 0;
209c0abf9e6Sopenharmony_ci				break;
210c0abf9e6Sopenharmony_ci			default:
211c0abf9e6Sopenharmony_ci				goto error;
212c0abf9e6Sopenharmony_ci		}
213c0abf9e6Sopenharmony_ci	}
214c0abf9e6Sopenharmony_ci
215c0abf9e6Sopenharmony_ci	rc = 0;
216c0abf9e6Sopenharmony_cierror:
217c0abf9e6Sopenharmony_ci	return rc;
218c0abf9e6Sopenharmony_ci}
219c0abf9e6Sopenharmony_ci
220c0abf9e6Sopenharmony_cistatic int
221c0abf9e6Sopenharmony_ciparse_options_resolution(int argc, char **argv, int *xres, int *yres)
222c0abf9e6Sopenharmony_ci{
223c0abf9e6Sopenharmony_ci	int rc = 1;
224c0abf9e6Sopenharmony_ci	int c;
225c0abf9e6Sopenharmony_ci	int option_index = 0;
226c0abf9e6Sopenharmony_ci	static struct option opts[] = {
227c0abf9e6Sopenharmony_ci		{ "resolution", 1, 0, OPT_RESOLUTION },
228c0abf9e6Sopenharmony_ci		{ NULL, 0, 0, 0 },
229c0abf9e6Sopenharmony_ci	};
230c0abf9e6Sopenharmony_ci
231c0abf9e6Sopenharmony_ci	if (argc < 2)
232c0abf9e6Sopenharmony_ci		goto error;
233c0abf9e6Sopenharmony_ci
234c0abf9e6Sopenharmony_ci	optind = 1;
235c0abf9e6Sopenharmony_ci	while (1) {
236c0abf9e6Sopenharmony_ci		c = getopt_long(argc, argv, "h", opts, &option_index);
237c0abf9e6Sopenharmony_ci		if (c == -1)
238c0abf9e6Sopenharmony_ci			break;
239c0abf9e6Sopenharmony_ci
240c0abf9e6Sopenharmony_ci		switch (c) {
241c0abf9e6Sopenharmony_ci			case OPT_RESOLUTION:
242c0abf9e6Sopenharmony_ci				if (!parse_resolution_argument(optarg,
243c0abf9e6Sopenharmony_ci							       xres, yres))
244c0abf9e6Sopenharmony_ci					goto error;
245c0abf9e6Sopenharmony_ci				break;
246c0abf9e6Sopenharmony_ci			default:
247c0abf9e6Sopenharmony_ci				goto error;
248c0abf9e6Sopenharmony_ci		}
249c0abf9e6Sopenharmony_ci	}
250c0abf9e6Sopenharmony_ci
251c0abf9e6Sopenharmony_ci	rc = 0;
252c0abf9e6Sopenharmony_cierror:
253c0abf9e6Sopenharmony_ci	return rc;
254c0abf9e6Sopenharmony_ci}
255c0abf9e6Sopenharmony_ci
256c0abf9e6Sopenharmony_cistatic enum mode
257c0abf9e6Sopenharmony_ciparse_options_mode(int argc, char **argv)
258c0abf9e6Sopenharmony_ci{
259c0abf9e6Sopenharmony_ci	int c;
260c0abf9e6Sopenharmony_ci	int option_index = 0;
261c0abf9e6Sopenharmony_ci	static const struct option opts[] = {
262c0abf9e6Sopenharmony_ci		{ "abs", 1, 0, OPT_ABS },
263c0abf9e6Sopenharmony_ci		{ "led", 1, 0, OPT_LED },
264c0abf9e6Sopenharmony_ci		{ "resolution", 1, 0, OPT_RESOLUTION },
265c0abf9e6Sopenharmony_ci		{ "help", 0, 0, OPT_HELP },
266c0abf9e6Sopenharmony_ci		{ NULL, 0, 0, 0 },
267c0abf9e6Sopenharmony_ci	};
268c0abf9e6Sopenharmony_ci	enum mode mode = MODE_NONE;
269c0abf9e6Sopenharmony_ci
270c0abf9e6Sopenharmony_ci	if (argc < 2)
271c0abf9e6Sopenharmony_ci		return mode;
272c0abf9e6Sopenharmony_ci
273c0abf9e6Sopenharmony_ci	while (mode == MODE_NONE) {
274c0abf9e6Sopenharmony_ci		c = getopt_long(argc, argv, "h", opts, &option_index);
275c0abf9e6Sopenharmony_ci		if (c == -1)
276c0abf9e6Sopenharmony_ci			break;
277c0abf9e6Sopenharmony_ci
278c0abf9e6Sopenharmony_ci		switch (c) {
279c0abf9e6Sopenharmony_ci			case 'h':
280c0abf9e6Sopenharmony_ci			case OPT_HELP:
281c0abf9e6Sopenharmony_ci				mode = MODE_HELP;
282c0abf9e6Sopenharmony_ci				break;
283c0abf9e6Sopenharmony_ci			case OPT_ABS:
284c0abf9e6Sopenharmony_ci				mode = MODE_ABS;
285c0abf9e6Sopenharmony_ci				break;
286c0abf9e6Sopenharmony_ci			case OPT_LED:
287c0abf9e6Sopenharmony_ci				mode = MODE_LED;
288c0abf9e6Sopenharmony_ci				break;
289c0abf9e6Sopenharmony_ci			case OPT_RESOLUTION:
290c0abf9e6Sopenharmony_ci				mode = MODE_RESOLUTION;
291c0abf9e6Sopenharmony_ci				break;
292c0abf9e6Sopenharmony_ci			default:
293c0abf9e6Sopenharmony_ci				break;
294c0abf9e6Sopenharmony_ci		}
295c0abf9e6Sopenharmony_ci	}
296c0abf9e6Sopenharmony_ci
297c0abf9e6Sopenharmony_ci	if (optind >= argc && mode != MODE_HELP)
298c0abf9e6Sopenharmony_ci		return MODE_NONE;
299c0abf9e6Sopenharmony_ci
300c0abf9e6Sopenharmony_ci	return mode;
301c0abf9e6Sopenharmony_ci}
302c0abf9e6Sopenharmony_ci
303c0abf9e6Sopenharmony_cistatic void
304c0abf9e6Sopenharmony_ciset_abs(struct libevdev *dev, unsigned int changes,
305c0abf9e6Sopenharmony_ci	unsigned int axis, struct input_absinfo *absinfo)
306c0abf9e6Sopenharmony_ci{
307c0abf9e6Sopenharmony_ci	int rc;
308c0abf9e6Sopenharmony_ci	struct input_absinfo abs;
309c0abf9e6Sopenharmony_ci	const struct input_absinfo *a;
310c0abf9e6Sopenharmony_ci
311c0abf9e6Sopenharmony_ci	if ((a = libevdev_get_abs_info(dev, axis)) == NULL) {
312c0abf9e6Sopenharmony_ci		fprintf(stderr,
313c0abf9e6Sopenharmony_ci			"Device '%s' doesn't have axis %s\n",
314c0abf9e6Sopenharmony_ci			libevdev_get_name(dev),
315c0abf9e6Sopenharmony_ci			libevdev_event_code_get_name(EV_ABS, axis));
316c0abf9e6Sopenharmony_ci		return;
317c0abf9e6Sopenharmony_ci	}
318c0abf9e6Sopenharmony_ci
319c0abf9e6Sopenharmony_ci	abs = *a;
320c0abf9e6Sopenharmony_ci	if (changes & OPT_MIN)
321c0abf9e6Sopenharmony_ci		abs.minimum = absinfo->minimum;
322c0abf9e6Sopenharmony_ci	if (changes & OPT_MAX)
323c0abf9e6Sopenharmony_ci		abs.maximum = absinfo->maximum;
324c0abf9e6Sopenharmony_ci	if (changes & OPT_FUZZ)
325c0abf9e6Sopenharmony_ci		abs.fuzz = absinfo->fuzz;
326c0abf9e6Sopenharmony_ci	if (changes & OPT_FLAT)
327c0abf9e6Sopenharmony_ci		abs.flat = absinfo->flat;
328c0abf9e6Sopenharmony_ci	if (changes & OPT_RES)
329c0abf9e6Sopenharmony_ci		abs.resolution = absinfo->resolution;
330c0abf9e6Sopenharmony_ci
331c0abf9e6Sopenharmony_ci	rc = libevdev_kernel_set_abs_info(dev, axis, &abs);
332c0abf9e6Sopenharmony_ci	if (rc != 0)
333c0abf9e6Sopenharmony_ci		fprintf(stderr,
334c0abf9e6Sopenharmony_ci			"Failed to set absinfo %s: %s",
335c0abf9e6Sopenharmony_ci			libevdev_event_code_get_name(EV_ABS, axis),
336c0abf9e6Sopenharmony_ci			strerror(-rc));
337c0abf9e6Sopenharmony_ci}
338c0abf9e6Sopenharmony_ci
339c0abf9e6Sopenharmony_cistatic void
340c0abf9e6Sopenharmony_ciset_led(struct libevdev *dev, unsigned int led, int led_state)
341c0abf9e6Sopenharmony_ci{
342c0abf9e6Sopenharmony_ci	int rc;
343c0abf9e6Sopenharmony_ci	enum libevdev_led_value state =
344c0abf9e6Sopenharmony_ci		led_state ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF;
345c0abf9e6Sopenharmony_ci
346c0abf9e6Sopenharmony_ci	if (!libevdev_has_event_code(dev, EV_LED, led)) {
347c0abf9e6Sopenharmony_ci		fprintf(stderr,
348c0abf9e6Sopenharmony_ci			"Device '%s' doesn't have %s\n",
349c0abf9e6Sopenharmony_ci			libevdev_get_name(dev),
350c0abf9e6Sopenharmony_ci			libevdev_event_code_get_name(EV_LED, led));
351c0abf9e6Sopenharmony_ci		return;
352c0abf9e6Sopenharmony_ci	}
353c0abf9e6Sopenharmony_ci
354c0abf9e6Sopenharmony_ci	rc = libevdev_kernel_set_led_value(dev, led, state);
355c0abf9e6Sopenharmony_ci	if (rc != 0)
356c0abf9e6Sopenharmony_ci		fprintf(stderr,
357c0abf9e6Sopenharmony_ci			"Failed to set LED %s: %s",
358c0abf9e6Sopenharmony_ci			libevdev_event_code_get_name(EV_LED, led),
359c0abf9e6Sopenharmony_ci			strerror(-rc));
360c0abf9e6Sopenharmony_ci}
361c0abf9e6Sopenharmony_ci
362c0abf9e6Sopenharmony_cistatic void
363c0abf9e6Sopenharmony_ciset_resolution(struct libevdev *dev, int xres, int yres)
364c0abf9e6Sopenharmony_ci{
365c0abf9e6Sopenharmony_ci	struct input_absinfo abs;
366c0abf9e6Sopenharmony_ci
367c0abf9e6Sopenharmony_ci	abs.resolution = xres;
368c0abf9e6Sopenharmony_ci	if (libevdev_has_event_code(dev, EV_ABS, ABS_X))
369c0abf9e6Sopenharmony_ci		set_abs(dev, OPT_RES, ABS_X, &abs);
370c0abf9e6Sopenharmony_ci	if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_X))
371c0abf9e6Sopenharmony_ci		set_abs(dev, OPT_RES, ABS_MT_POSITION_X, &abs);
372c0abf9e6Sopenharmony_ci
373c0abf9e6Sopenharmony_ci	abs.resolution = yres;
374c0abf9e6Sopenharmony_ci	if (libevdev_has_event_code(dev, EV_ABS, ABS_Y))
375c0abf9e6Sopenharmony_ci		set_abs(dev, OPT_RES, ABS_Y, &abs);
376c0abf9e6Sopenharmony_ci	if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_Y))
377c0abf9e6Sopenharmony_ci		set_abs(dev, OPT_RES, ABS_MT_POSITION_Y, &abs);
378c0abf9e6Sopenharmony_ci}
379c0abf9e6Sopenharmony_ci
380c0abf9e6Sopenharmony_ciint
381c0abf9e6Sopenharmony_cimain(int argc, char **argv)
382c0abf9e6Sopenharmony_ci{
383c0abf9e6Sopenharmony_ci	struct libevdev *dev = NULL;
384c0abf9e6Sopenharmony_ci	int fd = -1;
385c0abf9e6Sopenharmony_ci	int rc = EXIT_FAILURE;
386c0abf9e6Sopenharmony_ci	enum mode mode;
387c0abf9e6Sopenharmony_ci	const char *path;
388c0abf9e6Sopenharmony_ci	struct input_absinfo absinfo;
389c0abf9e6Sopenharmony_ci	int axis = -1;
390c0abf9e6Sopenharmony_ci	int led = -1;
391c0abf9e6Sopenharmony_ci	int led_state = -1;
392c0abf9e6Sopenharmony_ci	unsigned int changes = 0; /* bitmask of changes */
393c0abf9e6Sopenharmony_ci	int xres = 0,
394c0abf9e6Sopenharmony_ci	    yres = 0;
395c0abf9e6Sopenharmony_ci
396c0abf9e6Sopenharmony_ci	mode = parse_options_mode(argc, argv);
397c0abf9e6Sopenharmony_ci	switch (mode) {
398c0abf9e6Sopenharmony_ci		case MODE_HELP:
399c0abf9e6Sopenharmony_ci			rc = EXIT_SUCCESS;
400c0abf9e6Sopenharmony_ci			/* fallthrough */
401c0abf9e6Sopenharmony_ci		case MODE_NONE:
402c0abf9e6Sopenharmony_ci			usage(basename(argv[0]));
403c0abf9e6Sopenharmony_ci			goto out;
404c0abf9e6Sopenharmony_ci		case MODE_ABS:
405c0abf9e6Sopenharmony_ci			rc = parse_options_abs(argc, argv, &changes, &axis,
406c0abf9e6Sopenharmony_ci					       &absinfo);
407c0abf9e6Sopenharmony_ci			break;
408c0abf9e6Sopenharmony_ci		case MODE_LED:
409c0abf9e6Sopenharmony_ci			rc = parse_options_led(argc, argv, &led, &led_state);
410c0abf9e6Sopenharmony_ci			break;
411c0abf9e6Sopenharmony_ci		case MODE_RESOLUTION:
412c0abf9e6Sopenharmony_ci			rc = parse_options_resolution(argc, argv, &xres,
413c0abf9e6Sopenharmony_ci						      &yres);
414c0abf9e6Sopenharmony_ci			break;
415c0abf9e6Sopenharmony_ci		default:
416c0abf9e6Sopenharmony_ci			fprintf(stderr,
417c0abf9e6Sopenharmony_ci				"++?????++ Out of Cheese Error. Redo From Start.\n");
418c0abf9e6Sopenharmony_ci			goto out;
419c0abf9e6Sopenharmony_ci	}
420c0abf9e6Sopenharmony_ci
421c0abf9e6Sopenharmony_ci	if (rc != EXIT_SUCCESS)
422c0abf9e6Sopenharmony_ci		goto out;
423c0abf9e6Sopenharmony_ci
424c0abf9e6Sopenharmony_ci	if (optind >= argc) {
425c0abf9e6Sopenharmony_ci		rc = EXIT_FAILURE;
426c0abf9e6Sopenharmony_ci		usage(basename(argv[0]));
427c0abf9e6Sopenharmony_ci		goto out;
428c0abf9e6Sopenharmony_ci	}
429c0abf9e6Sopenharmony_ci
430c0abf9e6Sopenharmony_ci	path = argv[optind];
431c0abf9e6Sopenharmony_ci
432c0abf9e6Sopenharmony_ci	fd = open(path, O_RDWR);
433c0abf9e6Sopenharmony_ci	if (fd < 0) {
434c0abf9e6Sopenharmony_ci		rc = EXIT_FAILURE;
435c0abf9e6Sopenharmony_ci		perror("Failed to open device");
436c0abf9e6Sopenharmony_ci		goto out;
437c0abf9e6Sopenharmony_ci	}
438c0abf9e6Sopenharmony_ci
439c0abf9e6Sopenharmony_ci	rc = libevdev_new_from_fd(fd, &dev);
440c0abf9e6Sopenharmony_ci	if (rc < 0) {
441c0abf9e6Sopenharmony_ci		fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc));
442c0abf9e6Sopenharmony_ci		goto out;
443c0abf9e6Sopenharmony_ci	}
444c0abf9e6Sopenharmony_ci
445c0abf9e6Sopenharmony_ci	switch (mode) {
446c0abf9e6Sopenharmony_ci		case MODE_ABS:
447c0abf9e6Sopenharmony_ci			set_abs(dev, changes, axis, &absinfo);
448c0abf9e6Sopenharmony_ci			break;
449c0abf9e6Sopenharmony_ci		case MODE_LED:
450c0abf9e6Sopenharmony_ci			set_led(dev, led, led_state);
451c0abf9e6Sopenharmony_ci			break;
452c0abf9e6Sopenharmony_ci		case MODE_RESOLUTION:
453c0abf9e6Sopenharmony_ci			set_resolution(dev, xres, yres);
454c0abf9e6Sopenharmony_ci			break;
455c0abf9e6Sopenharmony_ci		default:
456c0abf9e6Sopenharmony_ci			break;
457c0abf9e6Sopenharmony_ci	}
458c0abf9e6Sopenharmony_ci
459c0abf9e6Sopenharmony_ciout:
460c0abf9e6Sopenharmony_ci	libevdev_free(dev);
461c0abf9e6Sopenharmony_ci	if (fd != -1)
462c0abf9e6Sopenharmony_ci		close(fd);
463c0abf9e6Sopenharmony_ci
464c0abf9e6Sopenharmony_ci	return rc;
465c0abf9e6Sopenharmony_ci}
466