| #include "tests.h" |
| |
| #ifdef HAVE_LINUX_INPUT_H |
| |
| # include <inttypes.h> |
| # include <stdio.h> |
| # include <stdlib.h> |
| # include <sys/ioctl.h> |
| # include <linux/input.h> |
| # include "print_fields.h" |
| |
| static const char *errstr; |
| |
| struct evdev_check { |
| unsigned long cmd; |
| const char *cmd_str; |
| void *arg_ptr; |
| void (*print_arg)(long rc, void *ptr, void *arg); |
| }; |
| |
| static long |
| invoke_test_syscall(unsigned long cmd, void *p) |
| { |
| long rc = ioctl(-1, cmd, p); |
| errstr = sprintrc(rc); |
| static char inj_errstr[4096]; |
| |
| snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr); |
| errstr = inj_errstr; |
| return rc; |
| } |
| |
| static void |
| test_evdev(struct evdev_check *check, void *arg) |
| { |
| long rc = invoke_test_syscall(check->cmd, check->arg_ptr); |
| printf("ioctl(-1, %s, ", check->cmd_str); |
| if (check->print_arg) |
| check->print_arg(rc, check->arg_ptr, arg); |
| else |
| printf("%p", check->arg_ptr); |
| printf(") = %s\n", errstr); |
| } |
| |
| static void |
| print_input_absinfo(long rc, void *ptr, void *arg) |
| { |
| struct input_absinfo *absinfo = ptr; |
| |
| if (rc < 0) { |
| printf("%p", absinfo); |
| return; |
| } |
| PRINT_FIELD_U("{", *absinfo, value); |
| PRINT_FIELD_U(", ", *absinfo, minimum); |
| # if VERBOSE |
| PRINT_FIELD_U(", ", *absinfo, maximum); |
| PRINT_FIELD_U(", ", *absinfo, fuzz); |
| PRINT_FIELD_U(", ", *absinfo, flat); |
| # ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION |
| PRINT_FIELD_U(", ", *absinfo, resolution); |
| # endif |
| # else |
| printf(", ..."); |
| # endif |
| printf("}"); |
| } |
| |
| static void |
| print_input_id(long rc, void *ptr, void *arg) |
| { |
| struct input_id *id = ptr; |
| |
| if (rc < 0) { |
| printf("%p", id); |
| return; |
| } |
| printf("{ID_BUS=%" PRIu16 |
| ", ID_VENDOR=%" PRIu16 |
| ", ID_PRODUCT=%" PRIu16 |
| ", ID_VERSION=%" PRIu16 "}", |
| id->bustype, id->vendor, id->product, id->version); |
| } |
| |
| # ifdef EVIOCGMTSLOTS |
| static void |
| print_mtslots(long rc, void *ptr, void *arg) |
| { |
| int *buffer = ptr; |
| const char **str = arg; |
| int num = atoi(*(str + 1)); |
| |
| if (rc < 0) { |
| printf("%p", buffer); |
| return; |
| } |
| |
| printf("{code=%s", *str); |
| printf(", values=["); |
| for (unsigned int i = 1; i <= (unsigned) num; i++) |
| printf("%s%s", i > 1 ? ", " : "", *(str + i + 1)); |
| printf("]}"); |
| } |
| # endif |
| |
| static void |
| print_getbit(long rc, void *ptr, void *arg) |
| { |
| const char **str = arg; |
| int num = atoi(*str); |
| |
| if (rc < 0) { |
| printf("%p", ptr); |
| return; |
| } |
| |
| printf("["); |
| printf("%s", *(str + 1)); |
| for (unsigned int i = 2; i <= (unsigned) num; i++) { |
| # if ! VERBOSE |
| if (i > 4) { |
| printf(", ..."); |
| break; |
| } |
| # endif |
| printf(", "); |
| printf("%s", *(str + i)); |
| } |
| printf("]"); |
| } |
| |
| int |
| main(int argc, char **argv) |
| { |
| unsigned long num_skip; |
| long inject_retval; |
| bool locked = false; |
| |
| if (argc == 1) |
| return 0; |
| |
| if (argc < 3) |
| error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]); |
| |
| num_skip = strtoul(argv[1], NULL, 0); |
| inject_retval = strtol(argv[2], NULL, 0); |
| |
| if (inject_retval < 0) |
| error_msg_and_fail("Expected non-negative INJECT_RETVAL, " |
| "but got %ld", inject_retval); |
| |
| for (unsigned int i = 0; i < num_skip; i++) { |
| long rc = ioctl(-1, EVIOCGID, NULL); |
| printf("ioctl(-1, EVIOCGID, NULL) = %s%s\n", |
| sprintrc(rc), |
| rc == inject_retval ? " (INJECTED)" : ""); |
| |
| if (rc != inject_retval) |
| continue; |
| |
| locked = true; |
| break; |
| } |
| |
| if (!locked) |
| error_msg_and_fail("Hasn't locked on ioctl(-1" |
| ", EVIOCGID, NULL) returning %lu", |
| inject_retval); |
| |
| TAIL_ALLOC_OBJECT_CONST_PTR(struct input_id, id); |
| TAIL_ALLOC_OBJECT_CONST_PTR(struct input_absinfo, absinfo); |
| TAIL_ALLOC_OBJECT_CONST_PTR(int, bad_addr_slot); |
| # ifdef EVIOCGMTSLOTS |
| int mtslots[] = { ABS_MT_SLOT, 1, 3 }; |
| /* we use the second element to indicate the number of values */ |
| /* mtslots_str[1] is "2" so the number of values is 2 */ |
| const char *mtslots_str[] = { "ABS_MT_SLOT", "2", "1", "3" }; |
| |
| /* invalid flag */ |
| int invalid_mtslot[] = { -1, 1 }; |
| char invalid_str[4096]; |
| snprintf(invalid_str, sizeof(invalid_str), "%#x /* ABS_MT_??? */", invalid_mtslot[0]); |
| const char *invalid_mtslot_str[] = { invalid_str, "1", "1" }; |
| # endif |
| |
| /* set more than 4 bits */ |
| unsigned long ev_more[] = { 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED | 1 << EV_SND | 1 << EV_PWR }; |
| /* we use the first element to indicate the number of set bits */ |
| /* ev_more_str[0] is "5" so the number of set bits is 5 */ |
| const char *ev_more_str[] = { "5", "EV_ABS", "EV_MSC", "EV_LED", "EV_SND", "EV_PWR" }; |
| |
| /* set less than 4 bits */ |
| unsigned long ev_less[] = { 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED }; |
| const char *ev_less_str[] = { "3", "EV_ABS", "EV_MSC", "EV_LED" }; |
| |
| /* set zero bit */ |
| unsigned long ev_zero[] = { 0x0 }; |
| const char *ev_zero_str[] = { "0", " 0 " }; |
| |
| /* KEY_MAX is 0x2ff which is greater than retval * 8 */ |
| unsigned long key[] = { 1 << KEY_1 | 1 << KEY_2, 0 }; |
| const char *key_str[] = { "2", "KEY_1", "KEY_2" }; |
| |
| struct { |
| struct evdev_check check; |
| void *ptr; |
| } a[] = { |
| { { ARG_STR(EVIOCGID), id, print_input_id }, NULL }, |
| { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, NULL }, |
| { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, |
| { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, |
| { { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit }, &ev_more_str }, |
| { { ARG_STR(EVIOCGBIT(0, 0)), ev_less, print_getbit }, &ev_less_str }, |
| { { ARG_STR(EVIOCGBIT(0, 0)), ev_zero, print_getbit }, &ev_zero_str }, |
| { { ARG_STR(EVIOCGBIT(EV_KEY, 0)), key, print_getbit }, &key_str}, |
| # ifdef EVIOCGMTSLOTS |
| { { ARG_STR(EVIOCGMTSLOTS(12)), mtslots, print_mtslots }, &mtslots_str }, |
| { { ARG_STR(EVIOCGMTSLOTS(8)), invalid_mtslot, print_mtslots }, &invalid_mtslot_str } |
| # endif |
| }; |
| for (unsigned int i = 0; i < ARRAY_SIZE(a); i++) { |
| test_evdev(&a[i].check, a[i].ptr); |
| } |
| |
| puts("+++ exited with 0 +++"); |
| return 0; |
| } |
| #else |
| |
| SKIP_MAIN_UNDEFINED("HAVE_LINUX_INPUT_H") |
| |
| #endif |