blob: 532c101c723f7755292a2c0e709ddc34bb117a43 [file] [log] [blame]
Etienne Gemsa4f750b92015-02-20 17:14:10 +01001/*
2 * Copyright (c) 2015 Etienne Gemsa <etienne.gemsa@lse.epita.fr>
3 * Copyright (c) 2015 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
Etienne Gemsa4f750b92015-02-20 17:14:10 +010032
Dmitry V. Levin8d85c232016-05-27 00:39:33 +000033# include <linux/ioctl.h>
34# include <linux/input.h>
35# include "xlat/evdev_abs.h"
36# include "xlat/evdev_autorepeat.h"
37# include "xlat/evdev_ff_status.h"
38# include "xlat/evdev_ff_types.h"
39# include "xlat/evdev_keycode.h"
40# include "xlat/evdev_leds.h"
41# include "xlat/evdev_misc.h"
42# include "xlat/evdev_mtslots.h"
43# include "xlat/evdev_prop.h"
44# include "xlat/evdev_relative_axes.h"
45# include "xlat/evdev_snd.h"
46# include "xlat/evdev_switch.h"
47# include "xlat/evdev_sync.h"
48
49# ifndef SYN_MAX
50# define SYN_MAX 0xf
51# endif
Dmitry V. Levin19dadf92015-02-22 02:50:33 +030052
Etienne Gemsa4f750b92015-02-20 17:14:10 +010053static void
Dmitry V. Levinc758ed02016-05-27 00:40:53 +000054decode_envelope(const struct ff_envelope *envelope)
Etienne Gemsa4f750b92015-02-20 17:14:10 +010055{
Dmitry V. Levinc758ed02016-05-27 00:40:53 +000056 tprintf(", envelope={attack_length=%" PRIu16
57 ", attack_level=%" PRIu16
58 ", fade_length=%" PRIu16
59 ", fade_level=%#x}",
Etienne Gemsa4f750b92015-02-20 17:14:10 +010060 envelope->attack_length,
61 envelope->attack_level,
62 envelope->fade_length,
63 envelope->fade_level);
64}
65
66static int
67ff_effect_ioctl(struct tcb *tcp, long arg)
68{
69 struct ff_effect ffe;
70
71 if (!verbose(tcp) || umove(tcp, arg, &ffe) < 0)
72 return 0;
73
74 tprints(", {type=");
75 printxval(evdev_ff_types, ffe.type, "FF_???");
76 tprintf(", id=%" PRIu16 ", direction=%" PRIu16,
77 ffe.id, ffe.direction);
78
79 if (!abbrev(tcp)) {
80 tprintf(", trigger={button=%" PRIu16 ", interval=%" PRIu16 "}",
81 ffe.trigger.button, ffe.trigger.interval);
82 tprintf(", replay={lenght=%" PRIu16 ", delay=%" PRIu16 "}",
83 ffe.replay.length, ffe.replay.delay);
84 switch (ffe.type) {
85 case FF_CONSTANT:
86 tprintf(", constant_ef={%" PRIi16,
87 ffe.u.constant.level);
88 decode_envelope(&ffe.u.constant.envelope);
89 tprints("}");
90 return 1;
91 case FF_RAMP:
92 tprintf(", ramp={start_level=%" PRIi16
93 ", end_level=%" PRIi16,
94 ffe.u.ramp.start_level,
95 ffe.u.ramp.end_level);
96 decode_envelope(&ffe.u.ramp.envelope);
97 tprints("}");
98 return 1;
99 case FF_PERIODIC:
100 tprintf(", periodic_ef={waveform=%" PRIu16
101 ", period=%" PRIu16
102 ", magnitude=%" PRIi16
103 ", offset=%" PRIi16
104 ", phase=%" PRIu16,
105 ffe.u.periodic.waveform,
106 ffe.u.periodic.period,
107 ffe.u.periodic.magnitude,
108 ffe.u.periodic.offset,
109 ffe.u.periodic.phase);
110 decode_envelope(&ffe.u.periodic.envelope);
111 tprintf(", custom_len=%" PRIu32
112 ", *custom_data=%#lx}",
113 ffe.u.periodic.custom_len,
114 (unsigned long)ffe.u.periodic.custom_data);
115 return 1;
116 case FF_RUMBLE:
117 tprintf(", rumble={strong_magnitude=%" PRIu16
118 ", weak_magnitude=%" PRIu16 "}",
119 ffe.u.rumble.strong_magnitude,
120 ffe.u.rumble.weak_magnitude);
121 return 1;
122 case FF_SPRING:
123 case FF_FRICTION:
124 case FF_DAMPER:
125 case FF_INERTIA:
126 case FF_CUSTOM:
127 break;
128 default :
129 break;
130 }
131 }
132
133 tprints(", ...}");
134 return 1;
135}
136
137static int
138abs_ioctl(struct tcb *tcp, long arg)
139{
140 struct input_absinfo absinfo;
141
142 if (!verbose(tcp) || umove(tcp, arg, &absinfo) < 0)
143 return 0;
144
145 tprintf(", {value=%" PRIu32 ", minimum=%" PRIu32,
146 absinfo.value, absinfo.minimum);
147 if (!abbrev(tcp)) {
148 tprintf(", maximum=%" PRIu32 ", fuzz=%" PRIu32,
149 absinfo.maximum, absinfo.fuzz);
Dmitry V. Levin19dadf92015-02-22 02:50:33 +0300150 tprintf(", flat=%" PRIu32, absinfo.flat);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000151# ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
Dmitry V. Levin19dadf92015-02-22 02:50:33 +0300152 tprintf(", resolution=%" PRIu32, absinfo.resolution);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000153# endif
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100154 tprints("}");
155 } else {
156 tprints(", ...}");
157 }
158 return 1;
159}
160
161static int
162keycode_ioctl(struct tcb *tcp, long arg)
163{
164 unsigned int keycode[2];
165
166 if (!arg) {
167 tprints(", NULL");
168 return 1;
169 }
170
171 if (!verbose(tcp) || umove(tcp, arg, &keycode) < 0)
172 return 0;
173
174 tprintf(", [%u, ", keycode[0]);
175 printxval(evdev_keycode, keycode[1], "KEY_???");
176 tprints("]");
177 return 1;
178}
179
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000180# ifdef EVIOCGKEYCODE_V2
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100181static int
182keycode_V2_ioctl(struct tcb *tcp, long arg)
183{
184 struct input_keymap_entry ike;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100185
186 if (!arg) {
187 tprints(", NULL");
188 return 1;
189 }
190
191 if (!verbose(tcp) || umove(tcp, arg, &ike) < 0)
192 return 0;
193
Dmitry V. Levin7d8b41a2015-02-21 23:05:26 +0000194 tprintf(", {flags=%" PRIu8 ", len=%" PRIu8, ike.flags, ike.len);
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100195 if (!abbrev(tcp)) {
Dmitry V. Levin7d8b41a2015-02-21 23:05:26 +0000196 unsigned int i;
197
198 tprintf(", index=%" PRIu16 ", keycode=", ike.index);
199 printxval(evdev_keycode, ike.keycode, "KEY_???");
200 tprints(", scancode=[");
201 for (i = 0; i < ARRAY_SIZE(ike.scancode); i++) {
202 if (i > 0)
203 tprints(", ");
204 tprintf("%" PRIx8, ike.scancode[i]);
205 }
206 tprints("]}");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100207 } else {
208 tprints(", ...}");
209 }
210 return 1;
211}
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000212# endif /* EVIOCGKEYCODE_V2 */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100213
214static int
215getid_ioctl(struct tcb *tcp, long arg)
216{
217 struct input_id id;
218
219 if (!verbose(tcp) || umove(tcp, arg, &id) < 0)
220 return 0;
221
222 tprintf(", {ID_BUS=%" PRIu16 ", ID_VENDOR=%" PRIu16,
223 id.bustype, id.vendor);
224 if (!abbrev(tcp)) {
225 tprintf(", ID_PRODUCT=%" PRIu16 ", ID_VERSION=%" PRIu16 "}",
226 id.product, id.version);
227 } else {
228 tprints(", ...}");
229 }
230 return 1;
231}
232
233static int
234decode_bitset(struct tcb *tcp, long arg, const struct xlat decode_nr[],
235 const unsigned int max_nr, const char *dflt)
236{
237 if (!verbose(tcp))
238 return 0;
239
240 unsigned int size;
241 if ((unsigned long) tcp->u_rval > max_nr)
242 size = max_nr;
243 else
244 size = tcp->u_rval;
245 char decoded_arg[size];
246
247 if (umoven(tcp, arg, size, decoded_arg) < 0)
248 return 0;
249
250 tprints(", [");
251
252 int bit_displayed = 0;
253 int i = next_set_bit(decoded_arg, 0, size);
254 if (i < 0) {
255 tprints(" 0 ");
256 } else {
257 printxval(decode_nr, i, dflt);
258
259 while ((i = next_set_bit(decoded_arg, i + 1, size)) > 0) {
260 if (abbrev(tcp) && bit_displayed >= 3) {
261 tprints(", ...");
262 break;
263 }
264 tprints(", ");
265 printxval(decode_nr, i, dflt);
266 bit_displayed++;
267 }
268 }
269
270 tprints("]");
271
272 return 1;
273}
274
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000275# ifdef EVIOCGMTSLOTS
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100276static int
277mtslots_ioctl(struct tcb *tcp, const unsigned int code, long arg)
278{
279 const size_t size = _IOC_SIZE(code) / sizeof(int32_t);
280 if (!size)
281 return 0;
282
283 int32_t buffer[size];
284
285 if (!verbose(tcp) || umove(tcp, arg, &buffer) < 0)
286 return 0;
287
288 tprints(", {code=");
289 printxval(evdev_mtslots, buffer[0], "ABS_MT_???");
290
291 unsigned int i;
292 tprints(", values=[");
293
294 for (i = 1; i < ARRAY_SIZE(buffer); i++)
295 tprintf("%s%d", i > 1 ? ", " : "", buffer[i]);
296
297 tprints("]}");
298 return 1;
299}
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000300# endif /* EVIOCGMTSLOTS */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100301
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000302# if defined EVIOCGREP || defined EVIOCSREP
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100303static int
304repeat_ioctl(struct tcb *tcp, long arg)
305{
Dmitry V. Levinb6795082015-07-06 22:33:39 +0000306 tprints(", ");
307 printpair_int(tcp, arg, "%u");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100308 return 1;
309}
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000310# endif /* EVIOCGREP || EVIOCSREP */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100311
312static int
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000313bit_ioctl(struct tcb *tcp, const unsigned int ev_nr, const long arg)
314{
315 switch (ev_nr) {
316 case EV_SYN:
317 return decode_bitset(tcp, arg, evdev_sync,
318 SYN_MAX, "SYN_???");
319 case EV_KEY:
320 return decode_bitset(tcp, arg, evdev_keycode,
321 KEY_MAX, "KEY_???");
322 case EV_REL:
323 return decode_bitset(tcp, arg, evdev_relative_axes,
324 REL_MAX, "REL_???");
325 case EV_ABS:
326 return decode_bitset(tcp, arg,
327 evdev_abs, ABS_MAX, "ABS_???");
328 case EV_MSC:
329 return decode_bitset(tcp, arg,
330 evdev_misc, MSC_MAX, "MSC_???");
331# ifdef EV_SW
332 case EV_SW:
333 return decode_bitset(tcp, arg,
334 evdev_switch, SW_MAX, "SW_???");
335# endif
336 case EV_LED:
337 return decode_bitset(tcp, arg,
338 evdev_leds, LED_MAX, "LED_???");
339 case EV_SND:
340 return decode_bitset(tcp, arg,
341 evdev_snd, SND_MAX, "SND_???");
342 case EV_REP:
343 return decode_bitset(tcp, arg, evdev_autorepeat,
344 REP_MAX, "REP_???");
345 case EV_FF:
346 return decode_bitset(tcp, arg, evdev_ff_types,
347 FF_MAX, "FF_???");
348 case EV_PWR:
349 printnum_int(tcp, arg, "%d");
350 return 1;
351 case EV_FF_STATUS:
352 return decode_bitset(tcp, arg, evdev_ff_status,
353 FF_STATUS_MAX, "FF_STATUS_???");
354 default:
355 return 0;
356 }
357}
358
359static int
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000360evdev_read_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100361{
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100362 if (syserror(tcp))
363 return 0;
364
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000365 /* fixed-number fixed-length commands */
366 switch (code) {
367 case EVIOCGVERSION:
368 tprints(", ");
369 printnum_int(tcp, arg, "%" PRIx32);
370 return 1;
371 case EVIOCGEFFECTS:
372 tprints(", ");
373 printnum_int(tcp, arg, "%" PRIu32);
374 return 1;
375 case EVIOCGID:
376 return getid_ioctl(tcp, arg);
377# ifdef EVIOCGREP
378 case EVIOCGREP:
379 return repeat_ioctl(tcp, arg);;
380# endif
381 case EVIOCGKEYCODE:
382 return keycode_ioctl(tcp, arg);
383# ifdef EVIOCGKEYCODE_V2
384 case EVIOCGKEYCODE_V2:
385 return keycode_V2_ioctl(tcp, arg);
386# endif
387 }
388
389 /* fixed-number variable-length commands */
390 switch (_IOC_NR(code)) {
391# ifdef EVIOCGMTSLOTS
392 case _IOC_NR(EVIOCGMTSLOTS(0)):
393 return mtslots_ioctl(tcp, code, arg);
394# endif
395 case _IOC_NR(EVIOCGNAME(0)):
396 case _IOC_NR(EVIOCGPHYS(0)):
397 case _IOC_NR(EVIOCGUNIQ(0)):
398 tprints(", ");
399 printstr(tcp, arg, tcp->u_rval - 1);
400 return 1;
401# ifdef EVIOCGPROP
402 case _IOC_NR(EVIOCGPROP(0)):
403 return decode_bitset(tcp, arg,
404 evdev_prop, INPUT_PROP_MAX, "PROP_???");
405# endif
406 case _IOC_NR(EVIOCGSND(0)):
407 return decode_bitset(tcp, arg,
408 evdev_snd, SND_MAX, "SND_???");
409# ifdef EVIOCGSW
410 case _IOC_NR(EVIOCGSW(0)):
411 return decode_bitset(tcp, arg,
412 evdev_switch, SW_MAX, "SW_???");
413# endif
414 case _IOC_NR(EVIOCGKEY(0)):
415 return decode_bitset(tcp, arg,
416 evdev_keycode, KEY_MAX, "KEY_???");
417 case _IOC_NR(EVIOCGLED(0)):
418 return decode_bitset(tcp, arg,
419 evdev_leds, LED_MAX, "LED_???");
420 }
421
422 /* multi-number fixed-length commands */
423 if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0)))
424 return abs_ioctl(tcp, arg);
425
426 /* multi-number variable-length commands */
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000427 if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
428 return bit_ioctl(tcp, _IOC_NR(code) & EV_MAX, arg);
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100429
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000430 return 0;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100431}
432
433static int
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000434evdev_write_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100435{
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000436 /* fixed-number fixed-length commands */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100437 switch (code) {
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000438# ifdef EVIOCSREP
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100439 case EVIOCSREP:
440 return repeat_ioctl(tcp, arg);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000441# endif
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100442 case EVIOCSKEYCODE:
443 return keycode_ioctl(tcp, arg);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000444# ifdef EVIOCSKEYCODE_V2
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100445 case EVIOCSKEYCODE_V2:
446 return keycode_V2_ioctl(tcp, arg);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000447# endif
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100448 case EVIOCSFF:
449 return ff_effect_ioctl(tcp, arg);
450 case EVIOCRMFF:
Dmitry V. Levin00394242016-05-27 00:40:27 +0000451 tprintf(", %d", (int) arg);
452 return 1;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100453 case EVIOCGRAB:
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000454# ifdef EVIOCREVOKE
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100455 case EVIOCREVOKE:
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000456# endif
Dmitry V. Levin9635df42016-05-27 00:40:45 +0000457 tprintf(", %lu", arg);
458 return 1;
459# ifdef EVIOCSCLOCKID
460 case EVIOCSCLOCKID:
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100461 tprints(", ");
462 printnum_int(tcp, arg, "%u");
463 return 1;
Dmitry V. Levin9635df42016-05-27 00:40:45 +0000464# endif
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100465 }
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000466
467 /* multi-number fixed-length commands */
468 if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0)))
469 return abs_ioctl(tcp, arg);
470
471 return 0;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100472}
473
474int
475evdev_ioctl(struct tcb *tcp, const unsigned int code, long arg)
476{
477 switch(_IOC_DIR(code)) {
478 case _IOC_READ:
Dmitry V. Levin2114e082016-05-27 00:40:02 +0000479 if (entering(tcp))
480 return 0;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100481 return evdev_read_ioctl(tcp, code, arg);
482 case _IOC_WRITE:
Dmitry V. Levin2114e082016-05-27 00:40:02 +0000483 return evdev_write_ioctl(tcp, code, arg) | RVAL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100484 default:
Dmitry V. Levin2114e082016-05-27 00:40:02 +0000485 return RVAL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100486 }
487}
488
489#endif /* HAVE_LINUX_INPUT_H */