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