Branch data Line data Source code
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
64 : 15 : decode_envelope(void *const data)
65 : : {
66 : 15 : const struct ff_envelope *const envelope = data;
67 : :
68 : 15 : tprintf(", envelope={attack_length=%" PRIu16
69 : : ", attack_level=%" PRIu16
70 : : ", fade_length=%" PRIu16
71 : : ", fade_level=%#x}",
72 : 15 : envelope->attack_length,
73 : 15 : envelope->attack_level,
74 : 15 : envelope->fade_length,
75 : 15 : envelope->fade_level);
76 : 15 : }
77 : :
78 : : static int
79 : 40 : ff_effect_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
80 : : {
81 : 40 : tprints(", ");
82 : :
83 : : struct_ff_effect ffe;
84 : :
85 [ + + ]: 40 : if (umove_or_printaddr(tcp, arg, &ffe))
86 : 10 : return 1;
87 : :
88 : 30 : tprints("{type=");
89 : 30 : printxval(evdev_ff_types, ffe.type, "FF_???");
90 : 30 : tprintf(", id=%" PRIu16
91 : : ", direction=%" PRIu16 ", ",
92 : 30 : ffe.id,
93 : 30 : ffe.direction);
94 : :
95 [ + + ]: 30 : if (abbrev(tcp)) {
96 : 5 : tprints("...}");
97 : 5 : return 1;
98 : : }
99 : :
100 : 25 : tprintf("trigger={button=%" PRIu16
101 : : ", interval=%" PRIu16 "}"
102 : : ", replay={length=%" PRIu16
103 : : ", delay=%" PRIu16 "}",
104 : 25 : ffe.trigger.button,
105 : 25 : ffe.trigger.interval,
106 : 25 : ffe.replay.length,
107 : 25 : ffe.replay.delay);
108 : :
109 [ + + + + : 25 : switch (ffe.type) {
+ ]
110 : : case FF_CONSTANT:
111 : 5 : tprintf(", constant={level=%" PRId16,
112 : 5 : ffe.u.constant.level);
113 : 5 : decode_envelope(&ffe.u.constant.envelope);
114 : 5 : tprints("}");
115 : 5 : break;
116 : : case FF_RAMP:
117 : 5 : tprintf(", ramp={start_level=%" PRId16
118 : : ", end_level=%" PRId16,
119 : 5 : ffe.u.ramp.start_level,
120 : 5 : ffe.u.ramp.end_level);
121 : 5 : decode_envelope(&ffe.u.ramp.envelope);
122 : 5 : tprints("}");
123 : 5 : break;
124 : : case FF_PERIODIC:
125 : 5 : tprintf(", periodic={waveform=%" PRIu16
126 : : ", period=%" PRIu16
127 : : ", magnitude=%" PRId16
128 : : ", offset=%" PRId16
129 : : ", phase=%" PRIu16,
130 : 5 : ffe.u.periodic.waveform,
131 : 5 : ffe.u.periodic.period,
132 : 5 : ffe.u.periodic.magnitude,
133 : 5 : ffe.u.periodic.offset,
134 : 5 : ffe.u.periodic.phase);
135 : 5 : decode_envelope(&ffe.u.periodic.envelope);
136 : 5 : tprintf(", custom_len=%u, custom_data=",
137 : : ffe.u.periodic.custom_len);
138 : 5 : printaddr(ptr_to_kulong(ffe.u.periodic.custom_data));
139 : 5 : tprints("}");
140 : 5 : break;
141 : : case FF_RUMBLE:
142 : 5 : tprintf(", rumble={strong_magnitude=%" PRIu16
143 : : ", weak_magnitude=%" PRIu16 "}",
144 : 5 : ffe.u.rumble.strong_magnitude,
145 : 5 : ffe.u.rumble.weak_magnitude);
146 : 5 : break;
147 : : default:
148 : 5 : break;
149 : : }
150 : :
151 : 25 : tprints("}");
152 : :
153 : 40 : return 1;
154 : : }
155 : :
156 : : static int
157 : 20 : abs_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
158 : : {
159 : 20 : tprints(", ");
160 : :
161 : : struct input_absinfo absinfo;
162 : :
163 [ - + ]: 20 : if (!umove_or_printaddr(tcp, arg, &absinfo)) {
164 : 0 : tprintf("{value=%u"
165 : : ", minimum=%u, ",
166 : : absinfo.value,
167 : : absinfo.minimum);
168 : :
169 [ # # ]: 0 : if (!abbrev(tcp)) {
170 : 0 : 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 : 0 : tprintf(", resolution=%u",
178 : : absinfo.resolution);
179 : : # endif
180 : : } else {
181 : 0 : tprints("...");
182 : : }
183 : :
184 : 0 : tprints("}");
185 : : }
186 : :
187 : 20 : return 1;
188 : : }
189 : :
190 : : static int
191 : 30 : keycode_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
192 : : {
193 : 30 : tprints(", ");
194 : :
195 : : unsigned int keycode[2];
196 : :
197 [ + + ]: 30 : if (!umove_or_printaddr(tcp, arg, &keycode)) {
198 : 10 : tprintf("[%u, ", keycode[0]);
199 : 10 : printxval(evdev_keycode, keycode[1], "KEY_???");
200 : 10 : tprints("]");
201 : : }
202 : :
203 : 30 : return 1;
204 : : }
205 : :
206 : : # ifdef EVIOCGKEYCODE_V2
207 : : static int
208 : 30 : keycode_V2_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
209 : : {
210 : 30 : tprints(", ");
211 : :
212 : : struct input_keymap_entry ike;
213 : :
214 [ + + ]: 30 : if (umove_or_printaddr(tcp, arg, &ike))
215 : 20 : return 1;
216 : :
217 : 10 : tprintf("{flags=%" PRIu8
218 : : ", len=%" PRIu8 ", ",
219 : 10 : ike.flags,
220 : 10 : ike.len);
221 : :
222 [ + + ]: 10 : if (!abbrev(tcp)) {
223 : : unsigned int i;
224 : :
225 : 5 : tprintf("index=%" PRIu16 ", keycode=", ike.index);
226 : 5 : printxval(evdev_keycode, ike.keycode, "KEY_???");
227 : 5 : tprints(", scancode=[");
228 [ + + ]: 165 : for (i = 0; i < ARRAY_SIZE(ike.scancode); i++) {
229 [ + + ]: 160 : if (i > 0)
230 : 155 : tprints(", ");
231 : 160 : tprintf("%" PRIx8, ike.scancode[i]);
232 : : }
233 : 5 : tprints("]");
234 : : } else {
235 : 5 : tprints("...");
236 : : }
237 : :
238 : 10 : tprints("}");
239 : :
240 : 30 : return 1;
241 : : }
242 : : # endif /* EVIOCGKEYCODE_V2 */
243 : :
244 : : static int
245 : 10 : getid_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
246 : : {
247 : 10 : tprints(", ");
248 : :
249 : : struct input_id id;
250 : :
251 [ - + ]: 10 : if (!umove_or_printaddr(tcp, arg, &id))
252 : 0 : tprintf("{ID_BUS=%" PRIu16
253 : : ", ID_VENDOR=%" PRIu16
254 : : ", ID_PRODUCT=%" PRIu16
255 : : ", ID_VERSION=%" PRIu16 "}",
256 : 0 : id.bustype,
257 : 0 : id.vendor,
258 : 0 : id.product,
259 : 0 : id.version);
260 : :
261 : 10 : return 1;
262 : : }
263 : :
264 : : static int
265 : 165 : 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 : 165 : {
269 : 165 : tprints(", ");
270 : :
271 : : unsigned int size;
272 [ + - ]: 165 : if ((kernel_ulong_t) tcp->u_rval > max_nr)
273 : 165 : size = max_nr;
274 : : else
275 : 0 : size = tcp->u_rval;
276 : 165 : char decoded_arg[size];
277 : :
278 [ + - ]: 165 : if (umove_or_printaddr(tcp, arg, &decoded_arg))
279 : 165 : return 1;
280 : :
281 : 0 : tprints("[");
282 : :
283 : 0 : int bit_displayed = 0;
284 : 0 : int i = next_set_bit(decoded_arg, 0, size);
285 [ # # ]: 0 : if (i < 0) {
286 : 0 : tprints(" 0 ");
287 : : } else {
288 : 0 : printxval(decode_nr, i, dflt);
289 : :
290 [ # # ]: 0 : while ((i = next_set_bit(decoded_arg, i + 1, size)) > 0) {
291 [ # # ][ # # ]: 0 : if (abbrev(tcp) && bit_displayed >= 3) {
292 : 0 : tprints(", ...");
293 : 0 : break;
294 : : }
295 : 0 : tprints(", ");
296 : 0 : printxval(decode_nr, i, dflt);
297 : 0 : bit_displayed++;
298 : : }
299 : : }
300 : :
301 : 0 : tprints("]");
302 : :
303 : 165 : return 1;
304 : : }
305 : :
306 : : # ifdef EVIOCGMTSLOTS
307 : : static int
308 : 10 : mtslots_ioctl(struct tcb *const tcp, const unsigned int code,
309 : : const kernel_ulong_t arg)
310 : 10 : {
311 : 10 : tprints(", ");
312 : :
313 : 10 : const size_t size = _IOC_SIZE(code) / sizeof(int);
314 [ + - ]: 10 : if (!size) {
315 : 10 : printaddr(arg);
316 : 10 : return 1;
317 : : }
318 : :
319 : 0 : int buffer[size];
320 : :
321 [ # # ]: 0 : if (umove_or_printaddr(tcp, arg, &buffer))
322 : 0 : return 1;
323 : :
324 : 0 : tprints("{code=");
325 : 0 : printxval(evdev_mtslots, buffer[0], "ABS_MT_???");
326 : :
327 : 0 : tprints(", values=[");
328 : :
329 : : unsigned int i;
330 [ # # ]: 0 : for (i = 1; i < ARRAY_SIZE(buffer); i++)
331 [ # # ]: 0 : tprintf("%s%d", i > 1 ? ", " : "", buffer[i]);
332 : :
333 : 0 : tprints("]}");
334 : :
335 : 10 : return 1;
336 : : }
337 : : # endif /* EVIOCGMTSLOTS */
338 : :
339 : : # if defined EVIOCGREP || defined EVIOCSREP
340 : : static int
341 : 20 : repeat_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
342 : : {
343 : 20 : tprints(", ");
344 : 20 : printpair_int(tcp, arg, "%u");
345 : 20 : return 1;
346 : : }
347 : : # endif /* EVIOCGREP || EVIOCSREP */
348 : :
349 : : static int
350 : 135 : bit_ioctl(struct tcb *const tcp, const unsigned int ev_nr,
351 : : const kernel_ulong_t arg)
352 : : {
353 [ + + + + : 135 : switch (ev_nr) {
+ + + + +
+ + + + ]
354 : : case EV_SYN:
355 : 10 : return decode_bitset(tcp, arg, evdev_sync,
356 : : SYN_MAX, "SYN_???");
357 : : case EV_KEY:
358 : 15 : return decode_bitset(tcp, arg, evdev_keycode,
359 : : KEY_MAX, "KEY_???");
360 : : case EV_REL:
361 : 10 : return decode_bitset(tcp, arg, evdev_relative_axes,
362 : : REL_MAX, "REL_???");
363 : : case EV_ABS:
364 : 10 : return decode_bitset(tcp, arg, evdev_abs,
365 : : ABS_MAX, "ABS_???");
366 : : case EV_MSC:
367 : 10 : return decode_bitset(tcp, arg, evdev_misc,
368 : : MSC_MAX, "MSC_???");
369 : : # ifdef EV_SW
370 : : case EV_SW:
371 : 10 : return decode_bitset(tcp, arg, evdev_switch,
372 : : SW_MAX, "SW_???");
373 : : # endif
374 : : case EV_LED:
375 : 10 : return decode_bitset(tcp, arg, evdev_leds,
376 : : LED_MAX, "LED_???");
377 : : case EV_SND:
378 : 10 : return decode_bitset(tcp, arg, evdev_snd,
379 : : SND_MAX, "SND_???");
380 : : case EV_REP:
381 : 10 : return decode_bitset(tcp, arg, evdev_autorepeat,
382 : : REP_MAX, "REP_???");
383 : : case EV_FF:
384 : 10 : return decode_bitset(tcp, arg, evdev_ff_types,
385 : : FF_MAX, "FF_???");
386 : : case EV_PWR:
387 : 10 : tprints(", ");
388 : 10 : printnum_int(tcp, arg, "%d");
389 : 10 : return 1;
390 : : case EV_FF_STATUS:
391 : 10 : return decode_bitset(tcp, arg, evdev_ff_status,
392 : : FF_STATUS_MAX, "FF_STATUS_???");
393 : : default:
394 : 10 : tprints(", ");
395 : 10 : printaddr(arg);
396 : 10 : return 1;
397 : : }
398 : : }
399 : :
400 : : static int
401 : 305 : 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 [ + + + + : 305 : switch (code) {
+ + + ]
406 : : case EVIOCGVERSION:
407 : 10 : tprints(", ");
408 : 10 : printnum_int(tcp, arg, "%#x");
409 : 10 : return 1;
410 : : case EVIOCGEFFECTS:
411 : 10 : tprints(", ");
412 : 10 : printnum_int(tcp, arg, "%u");
413 : 10 : return 1;
414 : : case EVIOCGID:
415 : 10 : return getid_ioctl(tcp, arg);
416 : : # ifdef EVIOCGREP
417 : : case EVIOCGREP:
418 : 10 : return repeat_ioctl(tcp, arg);
419 : : # endif
420 : : case EVIOCGKEYCODE:
421 : 10 : return keycode_ioctl(tcp, arg);
422 : : # ifdef EVIOCGKEYCODE_V2
423 : : case EVIOCGKEYCODE_V2:
424 : 10 : return keycode_V2_ioctl(tcp, arg);
425 : : # endif
426 : : }
427 : :
428 : : /* fixed-number variable-length commands */
429 [ + + + + : 245 : switch (_IOC_NR(code)) {
+ + + + ]
430 : : # ifdef EVIOCGMTSLOTS
431 : : case _IOC_NR(EVIOCGMTSLOTS(0)):
432 : 10 : 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 : 30 : tprints(", ");
438 [ + - ]: 30 : if (syserror(tcp))
439 : 30 : printaddr(arg);
440 : : else
441 : 0 : printstrn(tcp, arg, tcp->u_rval);
442 : 30 : return 1;
443 : : # ifdef EVIOCGPROP
444 : : case _IOC_NR(EVIOCGPROP(0)):
445 : 10 : return decode_bitset(tcp, arg, evdev_prop,
446 : : INPUT_PROP_MAX, "PROP_???");
447 : : # endif
448 : : case _IOC_NR(EVIOCGSND(0)):
449 : 10 : return decode_bitset(tcp, arg, evdev_snd,
450 : : SND_MAX, "SND_???");
451 : : # ifdef EVIOCGSW
452 : : case _IOC_NR(EVIOCGSW(0)):
453 : 10 : return decode_bitset(tcp, arg, evdev_switch,
454 : : SW_MAX, "SW_???");
455 : : # endif
456 : : case _IOC_NR(EVIOCGKEY(0)):
457 : 10 : return decode_bitset(tcp, arg, evdev_keycode,
458 : : KEY_MAX, "KEY_???");
459 : : case _IOC_NR(EVIOCGLED(0)):
460 : 10 : return decode_bitset(tcp, arg, evdev_leds,
461 : : LED_MAX, "LED_???");
462 : : }
463 : :
464 : : /* multi-number fixed-length commands */
465 [ + + ]: 155 : if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0)))
466 : 10 : return abs_ioctl(tcp, arg);
467 : :
468 : : /* multi-number variable-length commands */
469 [ + + ]: 145 : if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
470 : 135 : return bit_ioctl(tcp, _IOC_NR(code) & EV_MAX, arg);
471 : :
472 : 10 : return 0;
473 : : }
474 : :
475 : : static int
476 : 160 : 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 [ + + + + : 160 : switch (code) {
+ + + + ]
481 : : # ifdef EVIOCSREP
482 : : case EVIOCSREP:
483 : 10 : return repeat_ioctl(tcp, arg);
484 : : # endif
485 : : case EVIOCSKEYCODE:
486 : 20 : return keycode_ioctl(tcp, arg);
487 : : # ifdef EVIOCSKEYCODE_V2
488 : : case EVIOCSKEYCODE_V2:
489 : 20 : return keycode_V2_ioctl(tcp, arg);
490 : : # endif
491 : : case EVIOCSFF:
492 : 40 : return ff_effect_ioctl(tcp, arg);
493 : : case EVIOCRMFF:
494 : 10 : tprintf(", %d", (int) arg);
495 : 10 : return 1;
496 : : case EVIOCGRAB:
497 : : # ifdef EVIOCREVOKE
498 : : case EVIOCREVOKE:
499 : : # endif
500 : 20 : tprintf(", %" PRI_klu, arg);
501 : 20 : return 1;
502 : : # ifdef EVIOCSCLOCKID
503 : : case EVIOCSCLOCKID:
504 : 20 : tprints(", ");
505 : 20 : printnum_int(tcp, arg, "%u");
506 : 20 : return 1;
507 : : # endif
508 : : }
509 : :
510 : : /* multi-number fixed-length commands */
511 [ + + ]: 20 : if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0)))
512 : 10 : return abs_ioctl(tcp, arg);
513 : :
514 : 10 : return 0;
515 : : }
516 : :
517 : 790 : MPERS_PRINTER_DECL(int, evdev_ioctl, struct tcb *const tcp,
518 : : const unsigned int code, const kernel_ulong_t arg)
519 : : {
520 [ + + + ]: 790 : switch(_IOC_DIR(code)) {
521 : : case _IOC_READ:
522 [ + + ]: 610 : if (entering(tcp))
523 : 305 : return 0;
524 : 305 : return evdev_read_ioctl(tcp, code, arg);
525 : : case _IOC_WRITE:
526 : 160 : return evdev_write_ioctl(tcp, code, arg) | RVAL_DECODED;
527 : : default:
528 : 20 : return RVAL_DECODED;
529 : : }
530 : : }
531 : :
532 : : #endif /* HAVE_LINUX_INPUT_H */
|