Home | History | Annotate | Download | only in input
      1 /*
      2  * Copyright (c) 2015 Cedric Hnyda <chnyda (at) 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 
     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 
     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 
     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 
    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 
    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 
    136 static int have_events(void)
    137 {
    138 	return num_events && ev_iter < num_events;
    139 }
    140 
    141 static struct input_event *next_event(void)
    142 {
    143 	if (!have_events())
    144 		read_events();
    145 
    146 	return &events[ev_iter++];
    147 }
    148 
    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 
    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 
    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 
    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