static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item) { #ifdef EVIOCGMTSLOTS int i, ret; struct input_absinfo abs_info; /* * struct input_mt_request_layout { * __u32 code; * __s32 values[num_slots]; * }; * * this is the structure we're trying to emulate */ __u32* mt_req_code; __s32* mt_req_values; size_t mt_req_size; /* TODO: sync devices other than touchscreen */ if (!item->is_touchscreen) return; mt_req_size = sizeof(*mt_req_code) + sizeof(*mt_req_values) * item->touchscreen_data->max_slots; mt_req_code = SDL_calloc(1, mt_req_size); if (mt_req_code == NULL) { return; } mt_req_values = (__s32*)mt_req_code + 1; *mt_req_code = ABS_MT_TRACKING_ID; ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); if (ret < 0) { SDL_free(mt_req_code); return; } for(i = 0; i < item->touchscreen_data->max_slots; i++) { /* * This doesn't account for the very edge case of the user removing their * finger and replacing it on the screen during the time we're out of sync, * which'll mean that we're not going from down -> up or up -> down, we're * going from down -> down but with a different tracking id, meaning we'd * have to tell SDL of the two events, but since we wait till SYN_REPORT in * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't * allow it. Lets just pray to God it doesn't happen. */ if (item->touchscreen_data->slots[i].tracking_id < 0 && mt_req_values[i] >= 0) { item->touchscreen_data->slots[i].tracking_id = mt_req_values[i]; item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN; } else if (item->touchscreen_data->slots[i].tracking_id >= 0 && mt_req_values[i] < 0) { item->touchscreen_data->slots[i].tracking_id = -1; item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP; } } *mt_req_code = ABS_MT_POSITION_X; ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); if (ret < 0) { SDL_free(mt_req_code); return; } for(i = 0; i < item->touchscreen_data->max_slots; i++) { if (item->touchscreen_data->slots[i].tracking_id >= 0 && item->touchscreen_data->slots[i].x != mt_req_values[i]) { item->touchscreen_data->slots[i].x = mt_req_values[i]; if (item->touchscreen_data->slots[i].delta == EVDEV_TOUCH_SLOTDELTA_NONE) { item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_MOVE; } } } *mt_req_code = ABS_MT_POSITION_Y; ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); if (ret < 0) { SDL_free(mt_req_code); return; } for(i = 0; i < item->touchscreen_data->max_slots; i++) { if (item->touchscreen_data->slots[i].tracking_id >= 0 && item->touchscreen_data->slots[i].y != mt_req_values[i]) { item->touchscreen_data->slots[i].y = mt_req_values[i]; if (item->touchscreen_data->slots[i].delta == EVDEV_TOUCH_SLOTDELTA_NONE) { item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_MOVE; } } } ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info); if (ret < 0) { SDL_free(mt_req_code); return; } item->touchscreen_data->current_slot = abs_info.value; SDL_free(mt_req_code); #endif /* EVIOCGMTSLOTS */ }
int main(void) { TEST_NULL_ARG(EVIOCGVERSION); TEST_NULL_ARG(EVIOCGEFFECTS); TEST_NULL_ARG(EVIOCGID); TEST_NULL_ARG(EVIOCGKEYCODE); TEST_NULL_ARG(EVIOCSKEYCODE); TEST_NULL_ARG(EVIOCSFF); # ifdef EVIOCGKEYCODE_V2 TEST_NULL_ARG(EVIOCGKEYCODE_V2); # endif # ifdef EVIOCSKEYCODE_V2 TEST_NULL_ARG(EVIOCSKEYCODE_V2); # endif # ifdef EVIOCGREP TEST_NULL_ARG(EVIOCGREP); # endif # ifdef EVIOCSREP TEST_NULL_ARG(EVIOCSREP); # endif # ifdef EVIOCSCLOCKID TEST_NULL_ARG(EVIOCSCLOCKID); # endif TEST_NULL_ARG(EVIOCGNAME(0)); TEST_NULL_ARG(EVIOCGPHYS(0)); TEST_NULL_ARG(EVIOCGUNIQ(0)); TEST_NULL_ARG(EVIOCGKEY(0)); TEST_NULL_ARG(EVIOCGLED(0)); # ifdef EVIOCGMTSLOTS TEST_NULL_ARG(EVIOCGMTSLOTS(0)); # endif # ifdef EVIOCGPROP TEST_NULL_ARG(EVIOCGPROP(0)); # endif TEST_NULL_ARG(EVIOCGSND(0)); # ifdef EVIOCGSW TEST_NULL_ARG(EVIOCGSW(0)); # endif TEST_NULL_ARG(EVIOCGABS(ABS_X)); TEST_NULL_ARG(EVIOCSABS(ABS_X)); TEST_NULL_ARG(EVIOCGBIT(EV_SYN, 0)); TEST_NULL_ARG(EVIOCGBIT(EV_KEY, 1)); TEST_NULL_ARG(EVIOCGBIT(EV_REL, 2)); TEST_NULL_ARG(EVIOCGBIT(EV_ABS, 3)); TEST_NULL_ARG(EVIOCGBIT(EV_MSC, 4)); # ifdef EV_SW TEST_NULL_ARG(EVIOCGBIT(EV_SW, 5)); # endif TEST_NULL_ARG(EVIOCGBIT(EV_LED, 6)); TEST_NULL_ARG(EVIOCGBIT(EV_SND, 7)); TEST_NULL_ARG(EVIOCGBIT(EV_REP, 8)); TEST_NULL_ARG(EVIOCGBIT(EV_FF, 9)); TEST_NULL_ARG(EVIOCGBIT(EV_PWR, 10)); TEST_NULL_ARG(EVIOCGBIT(EV_FF_STATUS, 11)); ioctl(-1, EVIOCGBIT(EV_MAX, 42), 0); printf("ioctl(-1, EVIOCGBIT(%#x /* EV_??? */, 42), NULL)" " = -1 EBADF (%m)\n", EV_MAX); ioctl(-1, EVIOCRMFF, lmagic); printf("ioctl(-1, EVIOCRMFF, %d) = -1 EBADF (%m)\n", (int) lmagic); ioctl(-1, EVIOCGRAB, lmagic); printf("ioctl(-1, EVIOCGRAB, %lu) = -1 EBADF (%m)\n", lmagic); # ifdef EVIOCREVOKE ioctl(-1, EVIOCREVOKE, lmagic); printf("ioctl(-1, EVIOCREVOKE, %lu) = -1 EBADF (%m)\n", lmagic); # endif const unsigned int size = get_page_size(); void *const page = tail_alloc(size); fill_memory(page, size); int *const val_int = tail_alloc(sizeof(*val_int)); *val_int = magic; # ifdef EVIOCSCLOCKID ioctl(-1, EVIOCSCLOCKID, val_int); printf("ioctl(-1, EVIOCSCLOCKID, [%u]) = -1 EBADF (%m)\n", *val_int); # endif int *pair_int = tail_alloc(sizeof(*pair_int) * 2); pair_int[0] = 0xdeadbeef; pair_int[1] = 0xbadc0ded; # ifdef EVIOSGREP ioctl(-1, EVIOCSREP, pair_int); printf("ioctl(-1, EVIOCSREP, [%u, %u]) = -1 EBADF (%m)\n", pair_int[0], pair_int[1]); # endif pair_int[1] = 1; ioctl(-1, EVIOCSKEYCODE, pair_int); printf("ioctl(-1, EVIOCSKEYCODE, [%u, %s]) = -1 EBADF (%m)\n", pair_int[0], "KEY_ESC"); # ifdef EVIOCSKEYCODE_V2 struct input_keymap_entry *const ike = tail_alloc(sizeof(*ike)); fill_memory(ike, sizeof(*ike)); ike->keycode = 2; ioctl(-1, EVIOCSKEYCODE_V2, ike); printf("ioctl(-1, EVIOCSKEYCODE_V2, {flags=%" PRIu8 ", len=%" PRIu8 ", ", ike->flags, ike->len); # if VERBOSE printf("index=%" PRIu16 ", keycode=%s, scancode=[", ike->index, "KEY_1"); unsigned int i; for (i = 0; i < ARRAY_SIZE(ike->scancode); ++i) { if (i > 0) printf(", "); printf("%" PRIx8, ike->scancode[i]); } printf("]"); # else printf("..."); # endif errno = EBADF; printf("}) = -1 EBADF (%m)\n"); # endif struct ff_effect *const ffe = tail_alloc(sizeof(*ffe)); fill_memory(ffe, sizeof(*ffe)); ffe->type = FF_CONSTANT; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_CONSTANT"); # if VERBOSE printf(", constant={level=%hd", ffe->u.constant.level); print_envelope(&ffe->u.constant.envelope); printf("}"); # else printf("..."); # endif errno = EBADF; printf("}) = -1 EBADF (%m)\n"); # if VERBOSE ffe->type = FF_RAMP; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_RAMP"); printf(", ramp={start_level=%hd, end_level=%hd", ffe->u.ramp.start_level, ffe->u.ramp.end_level); print_envelope(&ffe->u.ramp.envelope); errno = EBADF; printf("}}) = -1 EBADF (%m)\n"); ffe->type = FF_PERIODIC; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_PERIODIC"); printf(", periodic={waveform=%hu, period=%hu, magnitude=%hd" ", offset=%hd, phase=%hu", ffe->u.periodic.waveform, ffe->u.periodic.period, ffe->u.periodic.magnitude, ffe->u.periodic.offset, ffe->u.periodic.phase); print_envelope(&ffe->u.periodic.envelope); printf(", custom_len=%u, custom_data=%p}", ffe->u.periodic.custom_len, ffe->u.periodic.custom_data); errno = EBADF; printf("}) = -1 EBADF (%m)\n"); ffe->type = FF_RUMBLE; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_RUMBLE"); printf(", rumble={strong_magnitude=%hu, weak_magnitude=%hu}", ffe->u.rumble.strong_magnitude, ffe->u.rumble.weak_magnitude); errno = EBADF; printf("}) = -1 EBADF (%m)\n"); ffe->type = 0xff; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "0xff /* FF_??? */"); errno = EBADF; printf("}) = -1 EBADF (%m)\n"); # endif ioctl(-1, _IOC(_IOC_READ, 0x45, 0x1, 0xff), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_READ, 0x45, 0x1, 0xff)", lmagic); ioctl(-1, _IOC(_IOC_WRITE, 0x45, 0x1, 0xff), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_WRITE, 0x45, 0x1, 0xff)", lmagic); ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, 0x45, 0xfe, 0xff), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_READ|_IOC_WRITE, 0x45, 0xfe, 0xff)", lmagic); ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, 0x45, 0, 0), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_READ|_IOC_WRITE, 0x45, 0, 0)", lmagic); puts("+++ exited with 0 +++"); return 0; }
static void input_sanitise(const struct ioctl_group *grp, int childno) { unsigned int u, r; pick_random_ioctl(grp, childno); switch (shm->syscall[childno].a2) { case EVIOCGNAME(0): u = rand(); shm->syscall[childno].a2 = EVIOCGNAME(u); break; case EVIOCGPHYS(0): u = rand(); shm->syscall[childno].a2 = EVIOCGPHYS(u); break; case EVIOCGUNIQ(0): u = rand(); shm->syscall[childno].a2 = EVIOCGUNIQ(u); break; #ifdef EVIOCGPROP case EVIOCGPROP(0): u = rand(); shm->syscall[childno].a2 = EVIOCGPROP(u); break; #endif #ifdef EVIOCGMTSLOTS case EVIOCGMTSLOTS(0): u = rand(); shm->syscall[childno].a2 = EVIOCGMTSLOTS(u); break; #endif case EVIOCGKEY(0): u = rand(); shm->syscall[childno].a2 = EVIOCGKEY(u); break; case EVIOCGLED(0): u = rand(); shm->syscall[childno].a2 = EVIOCGLED(u); break; case EVIOCGSND(0): u = rand(); shm->syscall[childno].a2 = EVIOCGSND(u); break; case EVIOCGSW(0): u = rand(); shm->syscall[childno].a2 = EVIOCGSW(u); break; case EVIOCGBIT(0,0): u = rand(); r = rand(); if (u % 10) u %= EV_CNT; if (r % 10) r /= 4; shm->syscall[childno].a2 = EVIOCGBIT(u, r); break; case EVIOCGABS(0): u = rand(); if (u % 10) u %= ABS_CNT; shm->syscall[childno].a2 = EVIOCGABS(u); break; case EVIOCSABS(0): u = rand(); if (u % 10) u %= ABS_CNT; shm->syscall[childno].a2 = EVIOCSABS(u); break; default: break; } }
IOCTL(EVIOCGKEYCODE), #ifdef EVIOCGKEYCODE_V2 IOCTL(EVIOCGKEYCODE_V2), #endif IOCTL(EVIOCSKEYCODE), #ifdef EVIOCSKEYCODE_V2 IOCTL(EVIOCSKEYCODE_V2), #endif IOCTL(EVIOCGNAME(0)), IOCTL(EVIOCGPHYS(0)), IOCTL(EVIOCGUNIQ(0)), #ifdef EVIOCGPROP IOCTL(EVIOCGPROP(0)), #endif #ifdef EVIOCGMTSLOTS IOCTL(EVIOCGMTSLOTS(0)), #endif IOCTL(EVIOCGKEY(0)), IOCTL(EVIOCGLED(0)), IOCTL(EVIOCGSND(0)), IOCTL(EVIOCGSW(0)), IOCTL(EVIOCGBIT(0,0)), IOCTL(EVIOCGABS(0)), IOCTL(EVIOCSABS(0)), IOCTL(EVIOCSFF), IOCTL(EVIOCRMFF), IOCTL(EVIOCGEFFECTS), IOCTL(EVIOCGRAB), #ifdef EVIOCSCLOCKID IOCTL(EVIOCSCLOCKID), #endif
I_SIMPLE_STRUCT_IN(EVIOCGEFFECTS, 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGABS(0), "EVIOCGABS", ABS_MAX, ioctl_insertion_parent_stateless), /* we define these with len==32, but they apply to any len */ I_NAMED_SIMPLE_STRUCT_IN(EVIOCGBIT(0, 32), "EVIOCGBIT", EV_MAX, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGNAME(32), "EVIOCGNAME", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGPHYS(32), "EVIOCGPHYS", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGUNIQ(32), "EVIOCGUNIQ", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGPROP(32), "EVIOCGPROP", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGKEY(32), "EVIOCGKEY", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGLED(32), "EVIOCGLED", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGSND(32), "EVIOCGSND", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGSW(32), "EVIOCGSW", 0, ioctl_insertion_parent_stateless), /* this was introduced not too long ago */ #ifdef EVIOCGMTSLOTS I_NAMED_SIMPLE_STRUCT_IN(EVIOCGMTSLOTS(32), "EVIOCGMTSLOTS", 0, ioctl_insertion_parent_stateless), #endif /* terminator */ {0, 0, 0, "", NULL, NULL, NULL, NULL, NULL} }; const ioctl_type * ioctl_type_get_by_id(unsigned long id) { ioctl_type *cur; for (cur = ioctl_db; cur->name[0] != '\0'; ++cur) if (id_matches_type(id, cur)) return cur; return NULL; }
static int evdev_read_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg) { /* fixed-number fixed-length commands */ switch (code) { case EVIOCGVERSION: tprints(", "); printnum_int(tcp, arg, "%#x"); return 1; case EVIOCGEFFECTS: tprints(", "); printnum_int(tcp, arg, "%u"); return 1; case EVIOCGID: return getid_ioctl(tcp, arg); # ifdef EVIOCGREP case EVIOCGREP: return repeat_ioctl(tcp, arg); # endif case EVIOCGKEYCODE: return keycode_ioctl(tcp, arg); # ifdef EVIOCGKEYCODE_V2 case EVIOCGKEYCODE_V2: return keycode_V2_ioctl(tcp, arg); # endif } /* fixed-number variable-length commands */ switch (_IOC_NR(code)) { # ifdef EVIOCGMTSLOTS case _IOC_NR(EVIOCGMTSLOTS(0)): return mtslots_ioctl(tcp, code, arg); # endif case _IOC_NR(EVIOCGNAME(0)): case _IOC_NR(EVIOCGPHYS(0)): case _IOC_NR(EVIOCGUNIQ(0)): tprints(", "); if (syserror(tcp)) printaddr(arg); else printstrn(tcp, arg, tcp->u_rval); return 1; # ifdef EVIOCGPROP case _IOC_NR(EVIOCGPROP(0)): return decode_bitset(tcp, arg, evdev_prop, INPUT_PROP_MAX, "PROP_???"); # endif case _IOC_NR(EVIOCGSND(0)): return decode_bitset(tcp, arg, evdev_snd, SND_MAX, "SND_???"); # ifdef EVIOCGSW case _IOC_NR(EVIOCGSW(0)): return decode_bitset(tcp, arg, evdev_switch, SW_MAX, "SW_???"); # endif case _IOC_NR(EVIOCGKEY(0)): return decode_bitset(tcp, arg, evdev_keycode, KEY_MAX, "KEY_???"); case _IOC_NR(EVIOCGLED(0)): return decode_bitset(tcp, arg, evdev_leds, LED_MAX, "LED_???"); } /* multi-number fixed-length commands */ if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) return abs_ioctl(tcp, arg); /* multi-number variable-length commands */ if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) return bit_ioctl(tcp, _IOC_NR(code) & EV_MAX, arg); return 0; }