1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com>
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or
5f08c3bdfSopenharmony_ci * modify it under the terms of the GNU General Public License as
6f08c3bdfSopenharmony_ci * published by the Free Software Foundation; either version 2 of
7f08c3bdfSopenharmony_ci * the License, or (at your option) any later version.
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful,
10f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12f08c3bdfSopenharmony_ci * GNU General Public License for more details.
13f08c3bdfSopenharmony_ci *
14f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License
15f08c3bdfSopenharmony_ci * along with this program; if not, write the Free Software Foundation,
16f08c3bdfSopenharmony_ci * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17f08c3bdfSopenharmony_ci */
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ci /*
20f08c3bdfSopenharmony_ci  *  Create a virtual device, activate auto-repeat and
21f08c3bdfSopenharmony_ci  *  and check that auto repeat is working
22f08c3bdfSopenharmony_ci  */
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_ci#include <linux/input.h>
25f08c3bdfSopenharmony_ci#include <linux/uinput.h>
26f08c3bdfSopenharmony_ci#include <linux/kd.h>
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_ci#include "test.h"
29f08c3bdfSopenharmony_ci#include "safe_macros.h"
30f08c3bdfSopenharmony_ci#include "lapi/fcntl.h"
31f08c3bdfSopenharmony_ci#include "input_helper.h"
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic void setup(void);
34f08c3bdfSopenharmony_cistatic void send_events(void);
35f08c3bdfSopenharmony_cistatic int check_events(void);
36f08c3bdfSopenharmony_cistatic void cleanup(void);
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_cistatic int fd;
39f08c3bdfSopenharmony_cistatic int fd2;
40f08c3bdfSopenharmony_cistruct input_event events[64];
41f08c3bdfSopenharmony_cistatic int num_events;
42f08c3bdfSopenharmony_cistatic int ev_iter;
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_cichar *TCID = "input06";
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ciint main(int ac, char **av)
47f08c3bdfSopenharmony_ci{
48f08c3bdfSopenharmony_ci	int lc;
49f08c3bdfSopenharmony_ci	int pid;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	tst_parse_opts(ac, av, NULL, NULL);
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	setup();
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	for (lc = 0; TEST_LOOPING(lc); ++lc) {
56f08c3bdfSopenharmony_ci		pid = tst_fork();
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ci		switch (pid) {
59f08c3bdfSopenharmony_ci		case 0:
60f08c3bdfSopenharmony_ci			send_events();
61f08c3bdfSopenharmony_ci			exit(0);
62f08c3bdfSopenharmony_ci		case -1:
63f08c3bdfSopenharmony_ci			tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
64f08c3bdfSopenharmony_ci		default:
65f08c3bdfSopenharmony_ci			if (!check_events())
66f08c3bdfSopenharmony_ci				tst_resm(TFAIL,
67f08c3bdfSopenharmony_ci					"Wrong data received in eventX");
68f08c3bdfSopenharmony_ci			else
69f08c3bdfSopenharmony_ci				tst_resm(TPASS, "Data received in eventX");
70f08c3bdfSopenharmony_ci		break;
71f08c3bdfSopenharmony_ci		}
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci		SAFE_WAITPID(NULL, pid, NULL, 0);
74f08c3bdfSopenharmony_ci	}
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	cleanup();
77f08c3bdfSopenharmony_ci	tst_exit();
78f08c3bdfSopenharmony_ci}
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_cistatic void setup(void)
81f08c3bdfSopenharmony_ci{
82f08c3bdfSopenharmony_ci	tst_require_root();
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	fd = open_uinput();
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_KEY);
87f08c3bdfSopenharmony_ci	SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_REP);
88f08c3bdfSopenharmony_ci	SAFE_IOCTL(NULL, fd, UI_SET_KEYBIT, KEY_X);
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_ci	create_device(fd);
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci	fd2 = open_device();
93f08c3bdfSopenharmony_ci	SAFE_IOCTL(NULL, fd2, EVIOCGRAB, 1);
94f08c3bdfSopenharmony_ci}
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_cistatic void send_events(void)
97f08c3bdfSopenharmony_ci{
98f08c3bdfSopenharmony_ci	send_event(fd, EV_KEY, KEY_X, 1);
99f08c3bdfSopenharmony_ci	send_event(fd, EV_SYN, 0, 0);
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	/*
102f08c3bdfSopenharmony_ci	 * Sleep long enough to keep the key pressed for some time
103f08c3bdfSopenharmony_ci	 * (auto-repeat).  Default kernel delay to start auto-repeat is 250ms
104f08c3bdfSopenharmony_ci	 * and the period is 33ms. So, we wait for a generous 500ms to make
105f08c3bdfSopenharmony_ci	 * sure we get the auto-repeated keys
106f08c3bdfSopenharmony_ci	 */
107f08c3bdfSopenharmony_ci	usleep(500000);
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci	send_event(fd, EV_KEY, KEY_X, 0);
110f08c3bdfSopenharmony_ci	send_event(fd, EV_SYN, 0, 0);
111f08c3bdfSopenharmony_ci}
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_cistatic int check_event(struct input_event *iev, int event, int code, int value)
114f08c3bdfSopenharmony_ci{
115f08c3bdfSopenharmony_ci	return iev->type == event && iev->code == code && iev->value == value;
116f08c3bdfSopenharmony_ci}
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_cistatic void read_events(void)
119f08c3bdfSopenharmony_ci{
120f08c3bdfSopenharmony_ci	int rd = read(fd2, events, sizeof(events));
121f08c3bdfSopenharmony_ci	if (rd < 0)
122f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "read() failed");
123f08c3bdfSopenharmony_ci
124f08c3bdfSopenharmony_ci	if (rd == 0)
125f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "Failed to read events");
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	if (rd % sizeof(struct input_event) != 0) {
128f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "read size %i not multiple of %zu",
129f08c3bdfSopenharmony_ci		         rd, sizeof(struct input_event));
130f08c3bdfSopenharmony_ci	}
131f08c3bdfSopenharmony_ci
132f08c3bdfSopenharmony_ci	ev_iter = 0;
133f08c3bdfSopenharmony_ci	num_events = rd / sizeof(struct input_event);
134f08c3bdfSopenharmony_ci}
135f08c3bdfSopenharmony_ci
136f08c3bdfSopenharmony_cistatic int have_events(void)
137f08c3bdfSopenharmony_ci{
138f08c3bdfSopenharmony_ci	return num_events && ev_iter < num_events;
139f08c3bdfSopenharmony_ci}
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_cistatic struct input_event *next_event(void)
142f08c3bdfSopenharmony_ci{
143f08c3bdfSopenharmony_ci	if (!have_events())
144f08c3bdfSopenharmony_ci		read_events();
145f08c3bdfSopenharmony_ci
146f08c3bdfSopenharmony_ci	return &events[ev_iter++];
147f08c3bdfSopenharmony_ci}
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_cistatic int parse_autorepeat_config(struct input_event *iev)
150f08c3bdfSopenharmony_ci{
151f08c3bdfSopenharmony_ci	if (!check_event_code(iev, EV_REP, REP_DELAY)) {
152f08c3bdfSopenharmony_ci		tst_resm(TFAIL,
153f08c3bdfSopenharmony_ci			 "Didn't get EV_REP configuration with code REP_DELAY");
154f08c3bdfSopenharmony_ci		return 0;
155f08c3bdfSopenharmony_ci	}
156f08c3bdfSopenharmony_ci
157f08c3bdfSopenharmony_ci	if (!check_event_code(next_event(), EV_REP, REP_PERIOD)) {
158f08c3bdfSopenharmony_ci		tst_resm(TFAIL,
159f08c3bdfSopenharmony_ci			 "Didn't get EV_REP configuration with code REP_PERIOD");
160f08c3bdfSopenharmony_ci		return 0;
161f08c3bdfSopenharmony_ci	}
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci	return 1;
164f08c3bdfSopenharmony_ci}
165f08c3bdfSopenharmony_ci
166f08c3bdfSopenharmony_cistatic int parse_key(struct input_event *iev)
167f08c3bdfSopenharmony_ci{
168f08c3bdfSopenharmony_ci	int autorep_count = 0;
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_ci	if (!check_event(iev, EV_KEY, KEY_X, 1) || !check_sync_event(next_event())) {
171f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "Didn't get expected key press for KEY_X");
172f08c3bdfSopenharmony_ci		return 0;
173f08c3bdfSopenharmony_ci	}
174f08c3bdfSopenharmony_ci
175f08c3bdfSopenharmony_ci	iev = next_event();
176f08c3bdfSopenharmony_ci	while (check_event(iev, EV_KEY, KEY_X, 2) && check_sync_event(next_event())) {
177f08c3bdfSopenharmony_ci		autorep_count++;
178f08c3bdfSopenharmony_ci		iev = next_event();
179f08c3bdfSopenharmony_ci	}
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_ci	/* make sure we have at least one auto-repeated key event */
182f08c3bdfSopenharmony_ci	if (!autorep_count) {
183f08c3bdfSopenharmony_ci		tst_resm(TFAIL,
184f08c3bdfSopenharmony_ci			 "Didn't get autorepeat events for the key - KEY_X");
185f08c3bdfSopenharmony_ci		return 0;
186f08c3bdfSopenharmony_ci	}
187f08c3bdfSopenharmony_ci
188f08c3bdfSopenharmony_ci	if (!check_event(iev, EV_KEY, KEY_X, 0) || !check_sync_event(next_event())) {
189f08c3bdfSopenharmony_ci		tst_resm(TFAIL,
190f08c3bdfSopenharmony_ci			 "Didn't get expected key release for KEY_X");
191f08c3bdfSopenharmony_ci		return 0;
192f08c3bdfSopenharmony_ci	}
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_ci	tst_resm(TINFO,
195f08c3bdfSopenharmony_ci		 "Received %d repititions for KEY_X", autorep_count);
196f08c3bdfSopenharmony_ci
197f08c3bdfSopenharmony_ci	return 1;
198f08c3bdfSopenharmony_ci}
199f08c3bdfSopenharmony_ci
200f08c3bdfSopenharmony_cistatic int check_events(void)
201f08c3bdfSopenharmony_ci{
202f08c3bdfSopenharmony_ci	struct input_event *iev;
203f08c3bdfSopenharmony_ci	int ret = 0;
204f08c3bdfSopenharmony_ci	int rep_config_done = 0;
205f08c3bdfSopenharmony_ci	int rep_keys_done = 0;
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_ci	read_events();
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_ci	while (have_events()) {
210f08c3bdfSopenharmony_ci		iev = next_event();
211f08c3bdfSopenharmony_ci		switch (iev->type) {
212f08c3bdfSopenharmony_ci		case EV_REP:
213f08c3bdfSopenharmony_ci			ret = parse_autorepeat_config(iev);
214f08c3bdfSopenharmony_ci			rep_config_done = 1;
215f08c3bdfSopenharmony_ci			break;
216f08c3bdfSopenharmony_ci		case EV_KEY:
217f08c3bdfSopenharmony_ci			ret = parse_key(iev);
218f08c3bdfSopenharmony_ci			rep_keys_done = 1;
219f08c3bdfSopenharmony_ci			break;
220f08c3bdfSopenharmony_ci		default:
221f08c3bdfSopenharmony_ci			tst_resm(TFAIL,
222f08c3bdfSopenharmony_ci				 "Unexpected event type '0x%04x' received",
223f08c3bdfSopenharmony_ci				iev->type);
224f08c3bdfSopenharmony_ci			ret = 0;
225f08c3bdfSopenharmony_ci			break;
226f08c3bdfSopenharmony_ci		}
227f08c3bdfSopenharmony_ci
228f08c3bdfSopenharmony_ci		if (!ret || (rep_config_done && rep_keys_done))
229f08c3bdfSopenharmony_ci			break;
230f08c3bdfSopenharmony_ci	}
231f08c3bdfSopenharmony_ci
232f08c3bdfSopenharmony_ci	return ret;
233f08c3bdfSopenharmony_ci}
234f08c3bdfSopenharmony_ci
235f08c3bdfSopenharmony_cistatic void cleanup(void)
236f08c3bdfSopenharmony_ci{
237f08c3bdfSopenharmony_ci	if (fd2 > 0 && close(fd2))
238f08c3bdfSopenharmony_ci		tst_resm(TWARN | TERRNO, "close(fd2) failed");
239f08c3bdfSopenharmony_ci
240f08c3bdfSopenharmony_ci	destroy_device(fd);
241f08c3bdfSopenharmony_ci}
242