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