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