• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 static void setup(void);
34 static void send_events(void);
35 static int check_events(void);
36 static void cleanup(void);
37 
38 static int fd;
39 static int fd2;
40 struct input_event events[64];
41 static int num_events;
42 static int ev_iter;
43 
44 char *TCID = "input06";
45 
main(int ac,char ** av)46 int 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 
setup(void)80 static 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 
send_events(void)96 static 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 
check_event(struct input_event * iev,int event,int code,int value)113 static 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 
read_events(void)118 static 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 
have_events(void)136 static int have_events(void)
137 {
138 	return num_events && ev_iter < num_events;
139 }
140 
next_event(void)141 static struct input_event *next_event(void)
142 {
143 	if (!have_events())
144 		read_events();
145 
146 	return &events[ev_iter++];
147 }
148 
parse_autorepeat_config(struct input_event * iev)149 static 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 
parse_key(struct input_event * iev)166 static 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 atleast 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 
check_events(void)200 static 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 
cleanup(void)235 static 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