1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com> 3f08c3bdfSopenharmony_ci * 4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or 5f08c3bdfSopenharmony_ci * modify it under the terms of the GNU General Public License as 6f08c3bdfSopenharmony_ci * published by the Free Software Foundation; either version 2 of 7f08c3bdfSopenharmony_ci * the License, or (at your option) any later version. 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful, 10f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12f08c3bdfSopenharmony_ci * GNU General Public License for more details. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License 15f08c3bdfSopenharmony_ci * along with this program; if not, write the Free Software Foundation, 16f08c3bdfSopenharmony_ci * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci /* 20f08c3bdfSopenharmony_ci * Create a virtual device, activate auto-repeat and 21f08c3bdfSopenharmony_ci * and check that auto repeat is working 22f08c3bdfSopenharmony_ci */ 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#include <linux/input.h> 25f08c3bdfSopenharmony_ci#include <linux/uinput.h> 26f08c3bdfSopenharmony_ci#include <linux/kd.h> 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#include "test.h" 29f08c3bdfSopenharmony_ci#include "safe_macros.h" 30f08c3bdfSopenharmony_ci#include "lapi/fcntl.h" 31f08c3bdfSopenharmony_ci#include "input_helper.h" 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_cistatic void setup(void); 34f08c3bdfSopenharmony_cistatic void send_events(void); 35f08c3bdfSopenharmony_cistatic int check_events(void); 36f08c3bdfSopenharmony_cistatic void cleanup(void); 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic int fd; 39f08c3bdfSopenharmony_cistatic int fd2; 40f08c3bdfSopenharmony_cistruct input_event events[64]; 41f08c3bdfSopenharmony_cistatic int num_events; 42f08c3bdfSopenharmony_cistatic int ev_iter; 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_cichar *TCID = "input06"; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ciint main(int ac, char **av) 47f08c3bdfSopenharmony_ci{ 48f08c3bdfSopenharmony_ci int lc; 49f08c3bdfSopenharmony_ci int pid; 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci tst_parse_opts(ac, av, NULL, NULL); 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci setup(); 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_ci for (lc = 0; TEST_LOOPING(lc); ++lc) { 56f08c3bdfSopenharmony_ci pid = tst_fork(); 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci switch (pid) { 59f08c3bdfSopenharmony_ci case 0: 60f08c3bdfSopenharmony_ci send_events(); 61f08c3bdfSopenharmony_ci exit(0); 62f08c3bdfSopenharmony_ci case -1: 63f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "fork() failed"); 64f08c3bdfSopenharmony_ci default: 65f08c3bdfSopenharmony_ci if (!check_events()) 66f08c3bdfSopenharmony_ci tst_resm(TFAIL, 67f08c3bdfSopenharmony_ci "Wrong data received in eventX"); 68f08c3bdfSopenharmony_ci else 69f08c3bdfSopenharmony_ci tst_resm(TPASS, "Data received in eventX"); 70f08c3bdfSopenharmony_ci break; 71f08c3bdfSopenharmony_ci } 72f08c3bdfSopenharmony_ci 73f08c3bdfSopenharmony_ci SAFE_WAITPID(NULL, pid, NULL, 0); 74f08c3bdfSopenharmony_ci } 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci cleanup(); 77f08c3bdfSopenharmony_ci tst_exit(); 78f08c3bdfSopenharmony_ci} 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_cistatic void setup(void) 81f08c3bdfSopenharmony_ci{ 82f08c3bdfSopenharmony_ci tst_require_root(); 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci fd = open_uinput(); 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_KEY); 87f08c3bdfSopenharmony_ci SAFE_IOCTL(NULL, fd, UI_SET_EVBIT, EV_REP); 88f08c3bdfSopenharmony_ci SAFE_IOCTL(NULL, fd, UI_SET_KEYBIT, KEY_X); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci create_device(fd); 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci fd2 = open_device(); 93f08c3bdfSopenharmony_ci SAFE_IOCTL(NULL, fd2, EVIOCGRAB, 1); 94f08c3bdfSopenharmony_ci} 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_cistatic void send_events(void) 97f08c3bdfSopenharmony_ci{ 98f08c3bdfSopenharmony_ci send_event(fd, EV_KEY, KEY_X, 1); 99f08c3bdfSopenharmony_ci send_event(fd, EV_SYN, 0, 0); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci /* 102f08c3bdfSopenharmony_ci * Sleep long enough to keep the key pressed for some time 103f08c3bdfSopenharmony_ci * (auto-repeat). Default kernel delay to start auto-repeat is 250ms 104f08c3bdfSopenharmony_ci * and the period is 33ms. So, we wait for a generous 500ms to make 105f08c3bdfSopenharmony_ci * sure we get the auto-repeated keys 106f08c3bdfSopenharmony_ci */ 107f08c3bdfSopenharmony_ci usleep(500000); 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci send_event(fd, EV_KEY, KEY_X, 0); 110f08c3bdfSopenharmony_ci send_event(fd, EV_SYN, 0, 0); 111f08c3bdfSopenharmony_ci} 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_cistatic int check_event(struct input_event *iev, int event, int code, int value) 114f08c3bdfSopenharmony_ci{ 115f08c3bdfSopenharmony_ci return iev->type == event && iev->code == code && iev->value == value; 116f08c3bdfSopenharmony_ci} 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_cistatic void read_events(void) 119f08c3bdfSopenharmony_ci{ 120f08c3bdfSopenharmony_ci int rd = read(fd2, events, sizeof(events)); 121f08c3bdfSopenharmony_ci if (rd < 0) 122f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "read() failed"); 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci if (rd == 0) 125f08c3bdfSopenharmony_ci tst_brkm(TBROK, cleanup, "Failed to read events"); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci if (rd % sizeof(struct input_event) != 0) { 128f08c3bdfSopenharmony_ci tst_brkm(TBROK, cleanup, "read size %i not multiple of %zu", 129f08c3bdfSopenharmony_ci rd, sizeof(struct input_event)); 130f08c3bdfSopenharmony_ci } 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci ev_iter = 0; 133f08c3bdfSopenharmony_ci num_events = rd / sizeof(struct input_event); 134f08c3bdfSopenharmony_ci} 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_cistatic int have_events(void) 137f08c3bdfSopenharmony_ci{ 138f08c3bdfSopenharmony_ci return num_events && ev_iter < num_events; 139f08c3bdfSopenharmony_ci} 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_cistatic struct input_event *next_event(void) 142f08c3bdfSopenharmony_ci{ 143f08c3bdfSopenharmony_ci if (!have_events()) 144f08c3bdfSopenharmony_ci read_events(); 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_ci return &events[ev_iter++]; 147f08c3bdfSopenharmony_ci} 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_cistatic int parse_autorepeat_config(struct input_event *iev) 150f08c3bdfSopenharmony_ci{ 151f08c3bdfSopenharmony_ci if (!check_event_code(iev, EV_REP, REP_DELAY)) { 152f08c3bdfSopenharmony_ci tst_resm(TFAIL, 153f08c3bdfSopenharmony_ci "Didn't get EV_REP configuration with code REP_DELAY"); 154f08c3bdfSopenharmony_ci return 0; 155f08c3bdfSopenharmony_ci } 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_ci if (!check_event_code(next_event(), EV_REP, REP_PERIOD)) { 158f08c3bdfSopenharmony_ci tst_resm(TFAIL, 159f08c3bdfSopenharmony_ci "Didn't get EV_REP configuration with code REP_PERIOD"); 160f08c3bdfSopenharmony_ci return 0; 161f08c3bdfSopenharmony_ci } 162f08c3bdfSopenharmony_ci 163f08c3bdfSopenharmony_ci return 1; 164f08c3bdfSopenharmony_ci} 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_cistatic int parse_key(struct input_event *iev) 167f08c3bdfSopenharmony_ci{ 168f08c3bdfSopenharmony_ci int autorep_count = 0; 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci if (!check_event(iev, EV_KEY, KEY_X, 1) || !check_sync_event(next_event())) { 171f08c3bdfSopenharmony_ci tst_resm(TFAIL, "Didn't get expected key press for KEY_X"); 172f08c3bdfSopenharmony_ci return 0; 173f08c3bdfSopenharmony_ci } 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ci iev = next_event(); 176f08c3bdfSopenharmony_ci while (check_event(iev, EV_KEY, KEY_X, 2) && check_sync_event(next_event())) { 177f08c3bdfSopenharmony_ci autorep_count++; 178f08c3bdfSopenharmony_ci iev = next_event(); 179f08c3bdfSopenharmony_ci } 180f08c3bdfSopenharmony_ci 181f08c3bdfSopenharmony_ci /* make sure we have at least one auto-repeated key event */ 182f08c3bdfSopenharmony_ci if (!autorep_count) { 183f08c3bdfSopenharmony_ci tst_resm(TFAIL, 184f08c3bdfSopenharmony_ci "Didn't get autorepeat events for the key - KEY_X"); 185f08c3bdfSopenharmony_ci return 0; 186f08c3bdfSopenharmony_ci } 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_ci if (!check_event(iev, EV_KEY, KEY_X, 0) || !check_sync_event(next_event())) { 189f08c3bdfSopenharmony_ci tst_resm(TFAIL, 190f08c3bdfSopenharmony_ci "Didn't get expected key release for KEY_X"); 191f08c3bdfSopenharmony_ci return 0; 192f08c3bdfSopenharmony_ci } 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_ci tst_resm(TINFO, 195f08c3bdfSopenharmony_ci "Received %d repititions for KEY_X", autorep_count); 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_ci return 1; 198f08c3bdfSopenharmony_ci} 199f08c3bdfSopenharmony_ci 200f08c3bdfSopenharmony_cistatic int check_events(void) 201f08c3bdfSopenharmony_ci{ 202f08c3bdfSopenharmony_ci struct input_event *iev; 203f08c3bdfSopenharmony_ci int ret = 0; 204f08c3bdfSopenharmony_ci int rep_config_done = 0; 205f08c3bdfSopenharmony_ci int rep_keys_done = 0; 206f08c3bdfSopenharmony_ci 207f08c3bdfSopenharmony_ci read_events(); 208f08c3bdfSopenharmony_ci 209f08c3bdfSopenharmony_ci while (have_events()) { 210f08c3bdfSopenharmony_ci iev = next_event(); 211f08c3bdfSopenharmony_ci switch (iev->type) { 212f08c3bdfSopenharmony_ci case EV_REP: 213f08c3bdfSopenharmony_ci ret = parse_autorepeat_config(iev); 214f08c3bdfSopenharmony_ci rep_config_done = 1; 215f08c3bdfSopenharmony_ci break; 216f08c3bdfSopenharmony_ci case EV_KEY: 217f08c3bdfSopenharmony_ci ret = parse_key(iev); 218f08c3bdfSopenharmony_ci rep_keys_done = 1; 219f08c3bdfSopenharmony_ci break; 220f08c3bdfSopenharmony_ci default: 221f08c3bdfSopenharmony_ci tst_resm(TFAIL, 222f08c3bdfSopenharmony_ci "Unexpected event type '0x%04x' received", 223f08c3bdfSopenharmony_ci iev->type); 224f08c3bdfSopenharmony_ci ret = 0; 225f08c3bdfSopenharmony_ci break; 226f08c3bdfSopenharmony_ci } 227f08c3bdfSopenharmony_ci 228f08c3bdfSopenharmony_ci if (!ret || (rep_config_done && rep_keys_done)) 229f08c3bdfSopenharmony_ci break; 230f08c3bdfSopenharmony_ci } 231f08c3bdfSopenharmony_ci 232f08c3bdfSopenharmony_ci return ret; 233f08c3bdfSopenharmony_ci} 234f08c3bdfSopenharmony_ci 235f08c3bdfSopenharmony_cistatic void cleanup(void) 236f08c3bdfSopenharmony_ci{ 237f08c3bdfSopenharmony_ci if (fd2 > 0 && close(fd2)) 238f08c3bdfSopenharmony_ci tst_resm(TWARN | TERRNO, "close(fd2) failed"); 239f08c3bdfSopenharmony_ci 240f08c3bdfSopenharmony_ci destroy_device(fd); 241f08c3bdfSopenharmony_ci} 242