1 /*
2 * Copyright (c) 2015 Etienne Gemsa <etienne.gemsa@lse.epita.fr>
3 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "defs.h"
30
31 #ifdef HAVE_LINUX_INPUT_H
32
33 #include DEF_MPERS_TYPE(struct_ff_effect)
34
35 # include <linux/ioctl.h>
36 # include <linux/input.h>
37
38 typedef struct ff_effect struct_ff_effect;
39
40 #endif /* HAVE_LINUX_INPUT_H */
41
42 #include MPERS_DEFS
43
44 #ifdef HAVE_LINUX_INPUT_H
45
46 # include "xlat/evdev_autorepeat.h"
47 # include "xlat/evdev_ff_status.h"
48 # include "xlat/evdev_ff_types.h"
49 # include "xlat/evdev_keycode.h"
50 # include "xlat/evdev_leds.h"
51 # include "xlat/evdev_misc.h"
52 # include "xlat/evdev_mtslots.h"
53 # include "xlat/evdev_prop.h"
54 # include "xlat/evdev_relative_axes.h"
55 # include "xlat/evdev_snd.h"
56 # include "xlat/evdev_switch.h"
57 # include "xlat/evdev_sync.h"
58
59 # ifndef SYN_MAX
60 # define SYN_MAX 0xf
61 # endif
62
63 static void
decode_envelope(void * const data)64 decode_envelope(void *const data)
65 {
66 const struct ff_envelope *const envelope = data;
67
68 tprintf(", envelope={attack_length=%" PRIu16
69 ", attack_level=%" PRIu16
70 ", fade_length=%" PRIu16
71 ", fade_level=%#x}",
72 envelope->attack_length,
73 envelope->attack_level,
74 envelope->fade_length,
75 envelope->fade_level);
76 }
77
78 static int
ff_effect_ioctl(struct tcb * const tcp,const kernel_ulong_t arg)79 ff_effect_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
80 {
81 tprints(", ");
82
83 struct_ff_effect ffe;
84
85 if (umove_or_printaddr(tcp, arg, &ffe))
86 return 1;
87
88 tprints("{type=");
89 printxval(evdev_ff_types, ffe.type, "FF_???");
90 tprintf(", id=%" PRIu16
91 ", direction=%" PRIu16 ", ",
92 ffe.id,
93 ffe.direction);
94
95 if (abbrev(tcp)) {
96 tprints("...}");
97 return 1;
98 }
99
100 tprintf("trigger={button=%" PRIu16
101 ", interval=%" PRIu16 "}"
102 ", replay={length=%" PRIu16
103 ", delay=%" PRIu16 "}",
104 ffe.trigger.button,
105 ffe.trigger.interval,
106 ffe.replay.length,
107 ffe.replay.delay);
108
109 switch (ffe.type) {
110 case FF_CONSTANT:
111 tprintf(", constant={level=%" PRId16,
112 ffe.u.constant.level);
113 decode_envelope(&ffe.u.constant.envelope);
114 tprints("}");
115 break;
116 case FF_RAMP:
117 tprintf(", ramp={start_level=%" PRId16
118 ", end_level=%" PRId16,
119 ffe.u.ramp.start_level,
120 ffe.u.ramp.end_level);
121 decode_envelope(&ffe.u.ramp.envelope);
122 tprints("}");
123 break;
124 case FF_PERIODIC:
125 tprintf(", periodic={waveform=%" PRIu16
126 ", period=%" PRIu16
127 ", magnitude=%" PRId16
128 ", offset=%" PRId16
129 ", phase=%" PRIu16,
130 ffe.u.periodic.waveform,
131 ffe.u.periodic.period,
132 ffe.u.periodic.magnitude,
133 ffe.u.periodic.offset,
134 ffe.u.periodic.phase);
135 decode_envelope(&ffe.u.periodic.envelope);
136 tprintf(", custom_len=%u, custom_data=",
137 ffe.u.periodic.custom_len);
138 printaddr(ptr_to_kulong(ffe.u.periodic.custom_data));
139 tprints("}");
140 break;
141 case FF_RUMBLE:
142 tprintf(", rumble={strong_magnitude=%" PRIu16
143 ", weak_magnitude=%" PRIu16 "}",
144 ffe.u.rumble.strong_magnitude,
145 ffe.u.rumble.weak_magnitude);
146 break;
147 default:
148 break;
149 }
150
151 tprints("}");
152
153 return 1;
154 }
155
156 static int
abs_ioctl(struct tcb * const tcp,const kernel_ulong_t arg)157 abs_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
158 {
159 tprints(", ");
160
161 struct input_absinfo absinfo;
162
163 if (!umove_or_printaddr(tcp, arg, &absinfo)) {
164 tprintf("{value=%u"
165 ", minimum=%u, ",
166 absinfo.value,
167 absinfo.minimum);
168
169 if (!abbrev(tcp)) {
170 tprintf("maximum=%u"
171 ", fuzz=%u"
172 ", flat=%u",
173 absinfo.maximum,
174 absinfo.fuzz,
175 absinfo.flat);
176 # ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
177 tprintf(", resolution=%u",
178 absinfo.resolution);
179 # endif
180 } else {
181 tprints("...");
182 }
183
184 tprints("}");
185 }
186
187 return 1;
188 }
189
190 static int
keycode_ioctl(struct tcb * const tcp,const kernel_ulong_t arg)191 keycode_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
192 {
193 tprints(", ");
194
195 unsigned int keycode[2];
196
197 if (!umove_or_printaddr(tcp, arg, &keycode)) {
198 tprintf("[%u, ", keycode[0]);
199 printxval(evdev_keycode, keycode[1], "KEY_???");
200 tprints("]");
201 }
202
203 return 1;
204 }
205
206 # ifdef EVIOCGKEYCODE_V2
207 static int
keycode_V2_ioctl(struct tcb * const tcp,const kernel_ulong_t arg)208 keycode_V2_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
209 {
210 tprints(", ");
211
212 struct input_keymap_entry ike;
213
214 if (umove_or_printaddr(tcp, arg, &ike))
215 return 1;
216
217 tprintf("{flags=%" PRIu8
218 ", len=%" PRIu8 ", ",
219 ike.flags,
220 ike.len);
221
222 if (!abbrev(tcp)) {
223 unsigned int i;
224
225 tprintf("index=%" PRIu16 ", keycode=", ike.index);
226 printxval(evdev_keycode, ike.keycode, "KEY_???");
227 tprints(", scancode=[");
228 for (i = 0; i < ARRAY_SIZE(ike.scancode); i++) {
229 if (i > 0)
230 tprints(", ");
231 tprintf("%" PRIx8, ike.scancode[i]);
232 }
233 tprints("]");
234 } else {
235 tprints("...");
236 }
237
238 tprints("}");
239
240 return 1;
241 }
242 # endif /* EVIOCGKEYCODE_V2 */
243
244 static int
getid_ioctl(struct tcb * const tcp,const kernel_ulong_t arg)245 getid_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
246 {
247 tprints(", ");
248
249 struct input_id id;
250
251 if (!umove_or_printaddr(tcp, arg, &id))
252 tprintf("{ID_BUS=%" PRIu16
253 ", ID_VENDOR=%" PRIu16
254 ", ID_PRODUCT=%" PRIu16
255 ", ID_VERSION=%" PRIu16 "}",
256 id.bustype,
257 id.vendor,
258 id.product,
259 id.version);
260
261 return 1;
262 }
263
264 static int
decode_bitset(struct tcb * const tcp,const kernel_ulong_t arg,const struct xlat decode_nr[],const unsigned int max_nr,const char * const dflt)265 decode_bitset(struct tcb *const tcp, const kernel_ulong_t arg,
266 const struct xlat decode_nr[], const unsigned int max_nr,
267 const char *const dflt)
268 {
269 tprints(", ");
270
271 unsigned int size;
272 if ((kernel_ulong_t) tcp->u_rval > max_nr)
273 size = max_nr;
274 else
275 size = tcp->u_rval;
276 char decoded_arg[size];
277
278 if (umove_or_printaddr(tcp, arg, &decoded_arg))
279 return 1;
280
281 tprints("[");
282
283 int bit_displayed = 0;
284 int i = next_set_bit(decoded_arg, 0, size);
285 if (i < 0) {
286 tprints(" 0 ");
287 } else {
288 printxval(decode_nr, i, dflt);
289
290 while ((i = next_set_bit(decoded_arg, i + 1, size)) > 0) {
291 if (abbrev(tcp) && bit_displayed >= 3) {
292 tprints(", ...");
293 break;
294 }
295 tprints(", ");
296 printxval(decode_nr, i, dflt);
297 bit_displayed++;
298 }
299 }
300
301 tprints("]");
302
303 return 1;
304 }
305
306 # ifdef EVIOCGMTSLOTS
307 static int
mtslots_ioctl(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)308 mtslots_ioctl(struct tcb *const tcp, const unsigned int code,
309 const kernel_ulong_t arg)
310 {
311 tprints(", ");
312
313 const size_t size = _IOC_SIZE(code) / sizeof(int);
314 if (!size) {
315 printaddr(arg);
316 return 1;
317 }
318
319 int buffer[size];
320
321 if (umove_or_printaddr(tcp, arg, &buffer))
322 return 1;
323
324 tprints("{code=");
325 printxval(evdev_mtslots, buffer[0], "ABS_MT_???");
326
327 tprints(", values=[");
328
329 unsigned int i;
330 for (i = 1; i < ARRAY_SIZE(buffer); i++)
331 tprintf("%s%d", i > 1 ? ", " : "", buffer[i]);
332
333 tprints("]}");
334
335 return 1;
336 }
337 # endif /* EVIOCGMTSLOTS */
338
339 # if defined EVIOCGREP || defined EVIOCSREP
340 static int
repeat_ioctl(struct tcb * const tcp,const kernel_ulong_t arg)341 repeat_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
342 {
343 tprints(", ");
344 printpair_int(tcp, arg, "%u");
345 return 1;
346 }
347 # endif /* EVIOCGREP || EVIOCSREP */
348
349 static int
bit_ioctl(struct tcb * const tcp,const unsigned int ev_nr,const kernel_ulong_t arg)350 bit_ioctl(struct tcb *const tcp, const unsigned int ev_nr,
351 const kernel_ulong_t arg)
352 {
353 switch (ev_nr) {
354 case EV_SYN:
355 return decode_bitset(tcp, arg, evdev_sync,
356 SYN_MAX, "SYN_???");
357 case EV_KEY:
358 return decode_bitset(tcp, arg, evdev_keycode,
359 KEY_MAX, "KEY_???");
360 case EV_REL:
361 return decode_bitset(tcp, arg, evdev_relative_axes,
362 REL_MAX, "REL_???");
363 case EV_ABS:
364 return decode_bitset(tcp, arg, evdev_abs,
365 ABS_MAX, "ABS_???");
366 case EV_MSC:
367 return decode_bitset(tcp, arg, evdev_misc,
368 MSC_MAX, "MSC_???");
369 # ifdef EV_SW
370 case EV_SW:
371 return decode_bitset(tcp, arg, evdev_switch,
372 SW_MAX, "SW_???");
373 # endif
374 case EV_LED:
375 return decode_bitset(tcp, arg, evdev_leds,
376 LED_MAX, "LED_???");
377 case EV_SND:
378 return decode_bitset(tcp, arg, evdev_snd,
379 SND_MAX, "SND_???");
380 case EV_REP:
381 return decode_bitset(tcp, arg, evdev_autorepeat,
382 REP_MAX, "REP_???");
383 case EV_FF:
384 return decode_bitset(tcp, arg, evdev_ff_types,
385 FF_MAX, "FF_???");
386 case EV_PWR:
387 tprints(", ");
388 printnum_int(tcp, arg, "%d");
389 return 1;
390 case EV_FF_STATUS:
391 return decode_bitset(tcp, arg, evdev_ff_status,
392 FF_STATUS_MAX, "FF_STATUS_???");
393 default:
394 tprints(", ");
395 printaddr(arg);
396 return 1;
397 }
398 }
399
400 static int
evdev_read_ioctl(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)401 evdev_read_ioctl(struct tcb *const tcp, const unsigned int code,
402 const kernel_ulong_t arg)
403 {
404 /* fixed-number fixed-length commands */
405 switch (code) {
406 case EVIOCGVERSION:
407 tprints(", ");
408 printnum_int(tcp, arg, "%#x");
409 return 1;
410 case EVIOCGEFFECTS:
411 tprints(", ");
412 printnum_int(tcp, arg, "%u");
413 return 1;
414 case EVIOCGID:
415 return getid_ioctl(tcp, arg);
416 # ifdef EVIOCGREP
417 case EVIOCGREP:
418 return repeat_ioctl(tcp, arg);
419 # endif
420 case EVIOCGKEYCODE:
421 return keycode_ioctl(tcp, arg);
422 # ifdef EVIOCGKEYCODE_V2
423 case EVIOCGKEYCODE_V2:
424 return keycode_V2_ioctl(tcp, arg);
425 # endif
426 }
427
428 /* fixed-number variable-length commands */
429 switch (_IOC_NR(code)) {
430 # ifdef EVIOCGMTSLOTS
431 case _IOC_NR(EVIOCGMTSLOTS(0)):
432 return mtslots_ioctl(tcp, code, arg);
433 # endif
434 case _IOC_NR(EVIOCGNAME(0)):
435 case _IOC_NR(EVIOCGPHYS(0)):
436 case _IOC_NR(EVIOCGUNIQ(0)):
437 tprints(", ");
438 if (syserror(tcp))
439 printaddr(arg);
440 else
441 printstrn(tcp, arg, tcp->u_rval);
442 return 1;
443 # ifdef EVIOCGPROP
444 case _IOC_NR(EVIOCGPROP(0)):
445 return decode_bitset(tcp, arg, evdev_prop,
446 INPUT_PROP_MAX, "PROP_???");
447 # endif
448 case _IOC_NR(EVIOCGSND(0)):
449 return decode_bitset(tcp, arg, evdev_snd,
450 SND_MAX, "SND_???");
451 # ifdef EVIOCGSW
452 case _IOC_NR(EVIOCGSW(0)):
453 return decode_bitset(tcp, arg, evdev_switch,
454 SW_MAX, "SW_???");
455 # endif
456 case _IOC_NR(EVIOCGKEY(0)):
457 return decode_bitset(tcp, arg, evdev_keycode,
458 KEY_MAX, "KEY_???");
459 case _IOC_NR(EVIOCGLED(0)):
460 return decode_bitset(tcp, arg, evdev_leds,
461 LED_MAX, "LED_???");
462 }
463
464 /* multi-number fixed-length commands */
465 if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0)))
466 return abs_ioctl(tcp, arg);
467
468 /* multi-number variable-length commands */
469 if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
470 return bit_ioctl(tcp, _IOC_NR(code) & EV_MAX, arg);
471
472 return 0;
473 }
474
475 static int
evdev_write_ioctl(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)476 evdev_write_ioctl(struct tcb *const tcp, const unsigned int code,
477 const kernel_ulong_t arg)
478 {
479 /* fixed-number fixed-length commands */
480 switch (code) {
481 # ifdef EVIOCSREP
482 case EVIOCSREP:
483 return repeat_ioctl(tcp, arg);
484 # endif
485 case EVIOCSKEYCODE:
486 return keycode_ioctl(tcp, arg);
487 # ifdef EVIOCSKEYCODE_V2
488 case EVIOCSKEYCODE_V2:
489 return keycode_V2_ioctl(tcp, arg);
490 # endif
491 case EVIOCSFF:
492 return ff_effect_ioctl(tcp, arg);
493 case EVIOCRMFF:
494 tprintf(", %d", (int) arg);
495 return 1;
496 case EVIOCGRAB:
497 # ifdef EVIOCREVOKE
498 case EVIOCREVOKE:
499 # endif
500 tprintf(", %" PRI_klu, arg);
501 return 1;
502 # ifdef EVIOCSCLOCKID
503 case EVIOCSCLOCKID:
504 tprints(", ");
505 printnum_int(tcp, arg, "%u");
506 return 1;
507 # endif
508 }
509
510 /* multi-number fixed-length commands */
511 if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0)))
512 return abs_ioctl(tcp, arg);
513
514 return 0;
515 }
516
MPERS_PRINTER_DECL(int,evdev_ioctl,struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)517 MPERS_PRINTER_DECL(int, evdev_ioctl, struct tcb *const tcp,
518 const unsigned int code, const kernel_ulong_t arg)
519 {
520 switch (_IOC_DIR(code)) {
521 case _IOC_READ:
522 if (entering(tcp))
523 return 0;
524 return evdev_read_ioctl(tcp, code, arg);
525 case _IOC_WRITE:
526 return evdev_write_ioctl(tcp, code, arg) | RVAL_DECODED;
527 default:
528 return RVAL_DECODED;
529 }
530 }
531
532 #endif /* HAVE_LINUX_INPUT_H */
533