• 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 
41 char *TCID = "input06";
42 
main(int ac,char ** av)43 int main(int ac, char **av)
44 {
45 	int lc;
46 	int pid;
47 
48 	tst_parse_opts(ac, av, NULL, NULL);
49 
50 	setup();
51 
52 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
53 		pid = tst_fork();
54 
55 		switch (pid) {
56 		case 0:
57 			send_events();
58 			exit(0);
59 		case -1:
60 			tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
61 		default:
62 			if (!check_events())
63 				tst_resm(TFAIL,
64 					"Wrong data received in eventX");
65 			else
66 				tst_resm(TPASS, "Data received in eventX");
67 		break;
68 		}
69 
70 		SAFE_WAITPID(NULL, pid, NULL, 0);
71 	}
72 
73 	cleanup();
74 	tst_exit();
75 }
76 
setup(void)77 static void setup(void)
78 {
79 	tst_require_root();
80 
81 	fd = open_uinput();
82 
83 	SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_KEY);
84 	SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_REP);
85 	SAFE_IOCTL(NULL, fd, UI_SET_KEYBIT, KEY_X);
86 
87 	create_device(fd);
88 
89 	fd2 = open_device();
90 	SAFE_IOCTL(NULL, fd2, EVIOCGRAB, 1);
91 }
92 
send_events(void)93 static void send_events(void)
94 {
95 	send_event(fd, EV_KEY, KEY_X, 1);
96 	send_event(fd, EV_SYN, 0, 0);
97 
98 	/* sleep to keep the key pressed for some time (auto-repeat) */
99 	usleep(1000);
100 
101 	send_event(fd, EV_KEY, KEY_X, 0);
102 	send_event(fd, EV_SYN, 0, 0);
103 }
104 
check_event(struct input_event * iev,int event,int code,int value)105 static int check_event(struct input_event *iev, int event, int code, int value)
106 {
107 	return iev->type == event && iev->code == code && iev->value == value;
108 }
109 
check_bound(unsigned int i,unsigned int rd)110 static int check_bound(unsigned int i, unsigned int rd)
111 {
112 	return i <= rd / sizeof(struct input_event);
113 }
114 
check_size(int rd)115 static void check_size(int rd)
116 {
117 	if (rd < 0)
118 		tst_brkm(TBROK | TERRNO, cleanup, "read() failed");
119 
120 	if (rd % sizeof(struct input_event) != 0) {
121 		tst_brkm(TBROK, cleanup, "read size %i not multiple of %zu",
122 		         rd, sizeof(struct input_event));
123 	}
124 }
125 
check_events(void)126 static int check_events(void)
127 {
128 	struct input_event iev[64];
129 	unsigned int i;
130 	int nb;
131 	int rd;
132 
133 	i = 0;
134 	nb = 0;
135 
136 	rd = read(fd2, iev, sizeof(iev));
137 
138 	check_size(rd);
139 
140 	if (rd > 0 && check_event(&iev[i], EV_KEY, KEY_X, 1))
141 		i++;
142 
143 	while (check_bound(i, rd) && !check_event(&iev[i], EV_KEY, KEY_X, 0)) {
144 
145 		if (iev[i].type != EV_SYN
146 			&& !check_event(&iev[i], EV_KEY, KEY_X, 2)) {
147 			tst_resm(TINFO,
148 				"Didn't receive EV_KEY KEY_X with value 2");
149 			break;
150 		}
151 		i++;
152 		nb++;
153 
154 		if (i == rd / sizeof(struct input_event)) {
155 			i = 0;
156 			rd = read(fd2, iev, sizeof(iev));
157 			check_size(rd);
158 		}
159 	}
160 
161 	return (nb > 0 && check_bound(i, rd)
162 		&& check_event(&iev[i], EV_KEY, KEY_X, 0));
163 }
164 
cleanup(void)165 static void cleanup(void)
166 {
167 	if (fd2 > 0 && close(fd2))
168 		tst_resm(TWARN | TERRNO, "close(fd2) failed");
169 
170 	destroy_device(fd);
171 }
172