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