summaryrefslogtreecommitdiff
path: root/src/evdev_mpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/evdev_mpers.c')
-rw-r--r--src/evdev_mpers.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/evdev_mpers.c b/src/evdev_mpers.c
new file mode 100644
index 000000000..a91e38749
--- /dev/null
+++ b/src/evdev_mpers.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2015 Etienne Gemsa <etienne.gemsa@lse.epita.fr>
+ * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
+ * Copyright (c) 2015-2020 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#ifdef HAVE_LINUX_INPUT_H
+
+# include DEF_MPERS_TYPE(struct_ff_effect)
+
+# include <linux/ioctl.h>
+# include <linux/input.h>
+
+typedef struct ff_effect struct_ff_effect;
+
+#endif /* HAVE_LINUX_INPUT_H */
+
+#include MPERS_DEFS
+
+#ifdef HAVE_LINUX_INPUT_H
+
+static void
+print_ff_envelope(const MPERS_PTR_ARG(struct ff_envelope *) const arg)
+{
+ const struct ff_envelope *const p = arg;
+ tprint_struct_begin();
+ PRINT_FIELD_U(*p, attack_length);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, attack_level);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, fade_length);
+ tprint_struct_next();
+ PRINT_FIELD_X(*p, fade_level);
+ tprint_struct_end();
+}
+
+#define DECL_print_ff(name_) \
+ print_ff_ ## name_(const typeof_field(struct_ff_effect, name_) *const p)
+
+static void
+DECL_print_ff(trigger)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_U(*p, button);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, interval);
+ tprint_struct_end();
+}
+
+static void
+DECL_print_ff(replay)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_U(*p, length);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, delay);
+ tprint_struct_end();
+}
+
+# define PRINT_FIELD_FF_EFFECT(where_, field_) \
+ do { \
+ tprints_field_name(#field_); \
+ print_ff_ ## field_(&((where_).field_)); \
+ } while (0)
+
+#define DECL_print_ff_effect(name_) \
+ print_ff_ ## name_ ## _effect(const typeof_field(struct_ff_effect, u.name_) *const p)
+
+static void
+DECL_print_ff_effect(constant)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_D(*p, level);
+ tprint_struct_next();
+ PRINT_FIELD_OBJ_PTR(*p, envelope, print_ff_envelope);
+ tprint_struct_end();
+}
+
+static void
+DECL_print_ff_effect(ramp)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_D(*p, start_level);
+ tprint_struct_next();
+ PRINT_FIELD_D(*p, end_level);
+ tprint_struct_next();
+ PRINT_FIELD_OBJ_PTR(*p, envelope, print_ff_envelope);
+ tprint_struct_end();
+}
+
+static void
+DECL_print_ff_effect(periodic)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_U(*p, waveform);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, period);
+ tprint_struct_next();
+ PRINT_FIELD_D(*p, magnitude);
+ tprint_struct_next();
+ PRINT_FIELD_D(*p, offset);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, phase);
+ tprint_struct_next();
+ PRINT_FIELD_OBJ_PTR(*p, envelope, print_ff_envelope);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, custom_len);
+ tprint_struct_next();
+ PRINT_FIELD_PTR(*p, custom_data);
+ tprint_struct_end();
+}
+
+static void
+DECL_print_ff_effect(rumble)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_U(*p, strong_magnitude);
+ tprint_struct_next();
+ PRINT_FIELD_U(*p, weak_magnitude);
+ tprint_struct_end();
+}
+
+# define PRINT_FIELD_FF_TYPE_EFFECT(where_, field_) \
+ do { \
+ tprints_field_name(#field_); \
+ print_ff_ ## field_ ## _effect(&((where_).field_)); \
+ } while (0)
+
+static int
+ff_effect_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ tprints(", ");
+
+ struct_ff_effect ffe;
+
+ if (umove_or_printaddr(tcp, arg, &ffe))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_struct_begin();
+ PRINT_FIELD_OBJ_VAL(ffe, type, print_evdev_ff_type);
+ tprint_struct_next();
+ PRINT_FIELD_D(ffe, id);
+ tprint_struct_next();
+ PRINT_FIELD_U(ffe, direction);
+ tprint_struct_next();
+
+ if (abbrev(tcp)) {
+ tprint_more_data_follows();
+ tprint_struct_end();
+ return RVAL_IOCTL_DECODED;
+ }
+
+ PRINT_FIELD_FF_EFFECT(ffe, trigger);
+ tprint_struct_next();
+ PRINT_FIELD_FF_EFFECT(ffe, replay);
+
+ switch (ffe.type) {
+ case FF_CONSTANT:
+ tprint_struct_next();
+ PRINT_FIELD_FF_TYPE_EFFECT(ffe.u, constant);
+ break;
+ case FF_RAMP:
+ tprint_struct_next();
+ PRINT_FIELD_FF_TYPE_EFFECT(ffe.u, ramp);
+ break;
+ case FF_PERIODIC:
+ tprint_struct_next();
+ PRINT_FIELD_FF_TYPE_EFFECT(ffe.u, periodic);
+ break;
+ case FF_RUMBLE:
+ tprint_struct_next();
+ PRINT_FIELD_FF_TYPE_EFFECT(ffe.u, rumble);
+ break;
+ default:
+ break;
+ }
+
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+MPERS_PRINTER_DECL(int, evdev_write_ioctl_mpers, struct tcb *const tcp,
+ const unsigned int code, const kernel_ulong_t arg)
+{
+ switch (code) {
+ case EVIOCSFF:
+ return ff_effect_ioctl(tcp, arg);
+ default:
+ return RVAL_DECODED;
+ }
+}
+
+#endif /* HAVE_LINUX_INPUT_H */