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 #include <linux/input.h>
     20 #include <linux/uinput.h>
     21 #include <fnmatch.h>
     22 #include <errno.h>
     23 #include <poll.h>
     24 
     25 #include "test.h"
     26 #include "safe_macros.h"
     27 #include "input_helper.h"
     28 
     29 #define VIRTUAL_DEVICE "virtual-device-ltp"
     30 
     31 #define VIRTUAL_DEVICE_REGEX "*virtual-device-ltp*"
     32 
     33 static int uinput_loaded;
     34 static int check_device(void);
     35 
     36 static int try_open_device(void)
     37 {
     38 	char path[256];
     39 	char name[256];
     40 	int ret, fd = -1;
     41 	unsigned int i;
     42 
     43 	for (i = 0; i < 100; i++) {
     44 		snprintf(path, sizeof(path), "/dev/input/event%i", i);
     45 
     46 		fd = open(path, O_RDONLY);
     47 
     48 		if (fd < 0 && errno == ENOENT)
     49 			continue;
     50 
     51 		if (fd < 0) {
     52 			tst_resm(TINFO | TERRNO, "failed to open %s", path);
     53 			break;
     54 		}
     55 
     56 		ret = ioctl(fd, EVIOCGNAME(sizeof(name)), name);
     57 		if (ret < 0) {
     58 			tst_resm(TINFO | TERRNO,
     59 				"ioctl(%s, EVIOCGNAME(256), ...) failed",
     60 				path);
     61 			break;
     62 		}
     63 
     64 		if (strcmp(name, VIRTUAL_DEVICE) == 0)
     65 			return fd;
     66 		close(fd);
     67 	}
     68 
     69 	return -1;
     70 }
     71 
     72 int open_device(void)
     73 {
     74 	int fd;
     75 	int retries = 10;
     76 
     77 	while (retries--) {
     78 		fd = try_open_device();
     79 		if (fd > 0)
     80 			return fd;
     81 		tst_resm(TINFO, "Device not found, retrying...");
     82 		usleep(10000);
     83 	}
     84 
     85 	tst_brkm(TBROK, NULL, "Unable to find the input device");
     86 }
     87 
     88 static int try_load_uinput(void)
     89 {
     90 	const char *argv[] = {"modprobe", "uinput", NULL};
     91 	int ret;
     92 
     93 	tst_resm(TINFO, "Trying to load uinput kernel module");
     94 
     95 	ret = tst_run_cmd(NULL, argv, NULL, NULL, 1);
     96 	if (ret) {
     97 		tst_resm(TINFO, "Failed to load the uinput module");
     98 		return 0;
     99 	}
    100 
    101 	return 1;
    102 }
    103 
    104 static void unload_uinput(void)
    105 {
    106 	const char *argv[] = {"modprobe", "-r", "uinput", NULL};
    107 	int ret;
    108 
    109 	tst_resm(TINFO, "Unloading uinput kernel module");
    110 
    111 	ret = tst_run_cmd(NULL, argv, NULL, NULL, 1);
    112 	if (ret)
    113 		tst_resm(TWARN, "Failed to unload uinput module");
    114 }
    115 
    116 static const char *uinput_paths[] = {
    117 	"/dev/input/uinput",
    118 	"/dev/uinput",
    119 };
    120 
    121 static int try_open_uinput(void)
    122 {
    123 	unsigned int i;
    124 	int fd;
    125 
    126 	for (i = 0; i < ARRAY_SIZE(uinput_paths); i++) {
    127 		fd = open(uinput_paths[i], O_WRONLY | O_NONBLOCK);
    128 
    129 		if (fd > 0) {
    130 			tst_resm(TINFO, "Found uinput dev at %s",
    131 			         uinput_paths[i]);
    132 			return fd;
    133 		}
    134 
    135 		if (fd < 0 && errno != ENOENT) {
    136 			tst_brkm(TBROK | TERRNO, NULL,
    137 			         "open(%s)", uinput_paths[i]);
    138 		}
    139 	}
    140 
    141 	return -1;
    142 }
    143 
    144 int open_uinput(void)
    145 {
    146 	int fd;
    147 	int retries = 10;
    148 
    149 	fd = try_open_uinput();
    150 	if (fd > 0)
    151 		return fd;
    152 
    153 	if (try_load_uinput()) {
    154 		while (retries--) {
    155 			fd = try_open_uinput();
    156 			if (fd > 0) {
    157 				uinput_loaded = 1;
    158 				return fd;
    159 			}
    160 			tst_resm(TINFO, "Uinput dev not found, retrying...");
    161 			usleep(10000);
    162 		}
    163 
    164 		unload_uinput();
    165 	}
    166 
    167 	tst_brkm(TCONF, NULL, "Unable to find and open uinput");
    168 }
    169 
    170 void send_event(int fd, int event, int code, int value)
    171 {
    172 	struct input_event ev = {
    173 		.type = event,
    174 		.code = code,
    175 		.value = value,
    176 	};
    177 
    178 	SAFE_WRITE(NULL, 1, fd, &ev, sizeof(ev));
    179 }
    180 
    181 void send_rel_move(int fd, int x, int y)
    182 {
    183 	send_event(fd, EV_REL, REL_X, x);
    184 	send_event(fd, EV_REL, REL_Y, y);
    185 	send_event(fd, EV_SYN, 0, 0);
    186 }
    187 
    188 void create_device(int fd)
    189 {
    190 	int nb;
    191 	struct uinput_user_dev uidev = {
    192 		.name = VIRTUAL_DEVICE,
    193 		.id = {
    194 			.bustype = BUS_USB,
    195 			.vendor = 0x1,
    196 			.product = 0x1,
    197 			.version = 1,
    198 		}
    199 	};
    200 
    201 	SAFE_WRITE(NULL, 1, fd, &uidev, sizeof(uidev));
    202 	SAFE_IOCTL(NULL, fd, UI_DEV_CREATE, NULL);
    203 
    204 	for (nb = 100; nb > 0; nb--) {
    205 		if (check_device())
    206 			return;
    207 		usleep(10000);
    208 	}
    209 
    210 	destroy_device(fd);
    211 	tst_brkm(TBROK, NULL, "Failed to create device");
    212 }
    213 
    214 void setup_mouse_events(int fd)
    215 {
    216 	SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_KEY);
    217 	SAFE_IOCTL(NULL, fd, UI_SET_KEYBIT, BTN_LEFT);
    218 	SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_REL);
    219 	SAFE_IOCTL(NULL, fd, UI_SET_RELBIT, REL_X);
    220 	SAFE_IOCTL(NULL, fd, UI_SET_RELBIT, REL_Y);
    221 }
    222 
    223 void destroy_device(int fd)
    224 {
    225 	SAFE_IOCTL(NULL, fd, UI_DEV_DESTROY, NULL);
    226 	SAFE_CLOSE(NULL, fd);
    227 
    228 	if (uinput_loaded)
    229 		unload_uinput();
    230 }
    231 
    232 int no_events_queued(int fd)
    233 {
    234 	struct pollfd fds = {.fd = fd, .events = POLLIN};
    235 	int ret, res;
    236 	struct input_event ev;
    237 
    238 	ret = poll(&fds, 1, 30);
    239 
    240 	if (ret > 0) {
    241 		res = read(fd, &ev, sizeof(ev));
    242 
    243 		if (res == sizeof(ev)) {
    244 			tst_resm(TINFO,
    245 			         "Unexpected ev type=%i code=%i value=%i",
    246 			         ev.type, ev.code, ev.value);
    247 		}
    248 	}
    249 
    250 	return ret == 0;
    251 }
    252 
    253 static int check_device(void)
    254 {
    255 	FILE *file;
    256 	char line[256];
    257 
    258 	file = fopen("/proc/bus/input/devices", "r");
    259 	if (!file)
    260 		return 0;
    261 
    262 	while (fgets(line, 256, file)) {
    263 		if (fnmatch(VIRTUAL_DEVICE_REGEX, line, 0) == 0)
    264 			return 1;
    265 	}
    266 
    267 	fclose(file);
    268 
    269 	return 0;
    270 }
    271