blob: 674c1c05d93d4f1805cd0662126b481e27e68ccf [file] [log] [blame]
Etienne Gemsa4f750b92015-02-20 17:14:10 +01001/*
2 * Copyright (c) 2015 Etienne Gemsa <etienne.gemsa@lse.epita.fr>
Dmitry V. Levin43c8a5d2016-05-27 00:49:08 +00003 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
Elliott Hughes28e98bc2018-06-14 16:59:04 -07004 * Copyright (c) 2015-2018 The strace developers.
Etienne Gemsa4f750b92015-02-20 17:14:10 +01005 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "defs.h"
31
32#ifdef HAVE_LINUX_INPUT_H
Etienne Gemsa4f750b92015-02-20 17:14:10 +010033
Dmitry V. Levin8d85c232016-05-27 00:39:33 +000034# include <linux/ioctl.h>
35# include <linux/input.h>
Dmitry V. Levin43c8a5d2016-05-27 00:49:08 +000036
Dmitry V. Levin8d85c232016-05-27 00:39:33 +000037# include "xlat/evdev_autorepeat.h"
38# include "xlat/evdev_ff_status.h"
39# include "xlat/evdev_ff_types.h"
40# include "xlat/evdev_keycode.h"
41# include "xlat/evdev_leds.h"
42# include "xlat/evdev_misc.h"
43# include "xlat/evdev_mtslots.h"
44# include "xlat/evdev_prop.h"
45# include "xlat/evdev_relative_axes.h"
46# include "xlat/evdev_snd.h"
47# include "xlat/evdev_switch.h"
48# include "xlat/evdev_sync.h"
49
50# ifndef SYN_MAX
51# define SYN_MAX 0xf
52# endif
Dmitry V. Levin19dadf92015-02-22 02:50:33 +030053
Etienne Gemsa4f750b92015-02-20 17:14:10 +010054static int
Elliott Hughesd35df492017-02-15 15:19:05 -080055abs_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +010056{
Dmitry V. Levine1670062016-05-27 00:41:14 +000057 tprints(", ");
58
Etienne Gemsa4f750b92015-02-20 17:14:10 +010059 struct input_absinfo absinfo;
60
Dmitry V. Levine1670062016-05-27 00:41:14 +000061 if (!umove_or_printaddr(tcp, arg, &absinfo)) {
62 tprintf("{value=%u"
63 ", minimum=%u, ",
64 absinfo.value,
65 absinfo.minimum);
Etienne Gemsa4f750b92015-02-20 17:14:10 +010066
Dmitry V. Levine1670062016-05-27 00:41:14 +000067 if (!abbrev(tcp)) {
68 tprintf("maximum=%u"
69 ", fuzz=%u"
70 ", flat=%u",
71 absinfo.maximum,
72 absinfo.fuzz,
73 absinfo.flat);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +000074# ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
Dmitry V. Levine1670062016-05-27 00:41:14 +000075 tprintf(", resolution=%u",
76 absinfo.resolution);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +000077# endif
Dmitry V. Levine1670062016-05-27 00:41:14 +000078 } else {
79 tprints("...");
80 }
81
Etienne Gemsa4f750b92015-02-20 17:14:10 +010082 tprints("}");
Etienne Gemsa4f750b92015-02-20 17:14:10 +010083 }
Dmitry V. Levine1670062016-05-27 00:41:14 +000084
Elliott Hughes77c3ff82017-09-08 17:11:00 -070085 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +010086}
87
88static int
Elliott Hughesd35df492017-02-15 15:19:05 -080089keycode_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +010090{
Dmitry V. Levin7954e2a2016-05-27 00:41:25 +000091 tprints(", ");
92
Etienne Gemsa4f750b92015-02-20 17:14:10 +010093 unsigned int keycode[2];
94
Dmitry V. Levin7954e2a2016-05-27 00:41:25 +000095 if (!umove_or_printaddr(tcp, arg, &keycode)) {
96 tprintf("[%u, ", keycode[0]);
97 printxval(evdev_keycode, keycode[1], "KEY_???");
98 tprints("]");
Etienne Gemsa4f750b92015-02-20 17:14:10 +010099 }
100
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700101 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100102}
103
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000104# ifdef EVIOCGKEYCODE_V2
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100105static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800106keycode_V2_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100107{
Dmitry V. Levin13f8e8f2016-05-27 00:41:34 +0000108 tprints(", ");
109
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100110 struct input_keymap_entry ike;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100111
Dmitry V. Levin13f8e8f2016-05-27 00:41:34 +0000112 if (umove_or_printaddr(tcp, arg, &ike))
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700113 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100114
Dmitry V. Levin13f8e8f2016-05-27 00:41:34 +0000115 tprintf("{flags=%" PRIu8
116 ", len=%" PRIu8 ", ",
117 ike.flags,
118 ike.len);
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100119
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100120 if (!abbrev(tcp)) {
Dmitry V. Levin7d8b41a2015-02-21 23:05:26 +0000121 unsigned int i;
122
Dmitry V. Levin13f8e8f2016-05-27 00:41:34 +0000123 tprintf("index=%" PRIu16 ", keycode=", ike.index);
Dmitry V. Levin7d8b41a2015-02-21 23:05:26 +0000124 printxval(evdev_keycode, ike.keycode, "KEY_???");
125 tprints(", scancode=[");
126 for (i = 0; i < ARRAY_SIZE(ike.scancode); i++) {
127 if (i > 0)
128 tprints(", ");
129 tprintf("%" PRIx8, ike.scancode[i]);
130 }
Dmitry V. Levin13f8e8f2016-05-27 00:41:34 +0000131 tprints("]");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100132 } else {
Dmitry V. Levin13f8e8f2016-05-27 00:41:34 +0000133 tprints("...");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100134 }
Dmitry V. Levin13f8e8f2016-05-27 00:41:34 +0000135
136 tprints("}");
137
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700138 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100139}
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000140# endif /* EVIOCGKEYCODE_V2 */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100141
142static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800143getid_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100144{
Dmitry V. Levine54f98a2016-05-27 00:41:43 +0000145 tprints(", ");
146
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100147 struct input_id id;
148
Dmitry V. Levine54f98a2016-05-27 00:41:43 +0000149 if (!umove_or_printaddr(tcp, arg, &id))
150 tprintf("{ID_BUS=%" PRIu16
151 ", ID_VENDOR=%" PRIu16
152 ", ID_PRODUCT=%" PRIu16
153 ", ID_VERSION=%" PRIu16 "}",
154 id.bustype,
155 id.vendor,
156 id.product,
157 id.version);
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100158
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700159 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100160}
161
162static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800163decode_bitset(struct tcb *const tcp, const kernel_ulong_t arg,
164 const struct xlat decode_nr[], const unsigned int max_nr,
165 const char *const dflt)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100166{
Dmitry V. Levin14a810e2016-05-27 00:41:51 +0000167 tprints(", ");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100168
169 unsigned int size;
Elliott Hughesd35df492017-02-15 15:19:05 -0800170 if ((kernel_ulong_t) tcp->u_rval > max_nr)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100171 size = max_nr;
172 else
173 size = tcp->u_rval;
174 char decoded_arg[size];
175
Dmitry V. Levin14a810e2016-05-27 00:41:51 +0000176 if (umove_or_printaddr(tcp, arg, &decoded_arg))
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700177 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100178
Dmitry V. Levin14a810e2016-05-27 00:41:51 +0000179 tprints("[");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100180
181 int bit_displayed = 0;
182 int i = next_set_bit(decoded_arg, 0, size);
183 if (i < 0) {
184 tprints(" 0 ");
185 } else {
186 printxval(decode_nr, i, dflt);
187
188 while ((i = next_set_bit(decoded_arg, i + 1, size)) > 0) {
189 if (abbrev(tcp) && bit_displayed >= 3) {
190 tprints(", ...");
191 break;
192 }
193 tprints(", ");
194 printxval(decode_nr, i, dflt);
195 bit_displayed++;
196 }
197 }
198
199 tprints("]");
200
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700201 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100202}
203
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000204# ifdef EVIOCGMTSLOTS
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100205static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800206mtslots_ioctl(struct tcb *const tcp, const unsigned int code,
207 const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100208{
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000209 tprints(", ");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100210
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000211 const size_t size = _IOC_SIZE(code) / sizeof(int);
212 if (!size) {
213 printaddr(arg);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700214 return RVAL_IOCTL_DECODED;
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000215 }
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100216
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000217 int buffer[size];
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100218
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000219 if (umove_or_printaddr(tcp, arg, &buffer))
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700220 return RVAL_IOCTL_DECODED;
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000221
222 tprints("{code=");
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100223 printxval(evdev_mtslots, buffer[0], "ABS_MT_???");
224
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100225 tprints(", values=[");
226
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000227 unsigned int i;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100228 for (i = 1; i < ARRAY_SIZE(buffer); i++)
229 tprintf("%s%d", i > 1 ? ", " : "", buffer[i]);
230
231 tprints("]}");
Dmitry V. Levin563f0ce2016-05-27 00:41:59 +0000232
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700233 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100234}
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000235# endif /* EVIOCGMTSLOTS */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100236
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000237# if defined EVIOCGREP || defined EVIOCSREP
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100238static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800239repeat_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100240{
Dmitry V. Levinb6795082015-07-06 22:33:39 +0000241 tprints(", ");
242 printpair_int(tcp, arg, "%u");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700243 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100244}
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000245# endif /* EVIOCGREP || EVIOCSREP */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100246
247static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800248bit_ioctl(struct tcb *const tcp, const unsigned int ev_nr,
249 const kernel_ulong_t arg)
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000250{
251 switch (ev_nr) {
252 case EV_SYN:
253 return decode_bitset(tcp, arg, evdev_sync,
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000254 SYN_MAX, "SYN_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000255 case EV_KEY:
256 return decode_bitset(tcp, arg, evdev_keycode,
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000257 KEY_MAX, "KEY_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000258 case EV_REL:
259 return decode_bitset(tcp, arg, evdev_relative_axes,
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000260 REL_MAX, "REL_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000261 case EV_ABS:
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000262 return decode_bitset(tcp, arg, evdev_abs,
263 ABS_MAX, "ABS_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000264 case EV_MSC:
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000265 return decode_bitset(tcp, arg, evdev_misc,
266 MSC_MAX, "MSC_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000267# ifdef EV_SW
268 case EV_SW:
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000269 return decode_bitset(tcp, arg, evdev_switch,
270 SW_MAX, "SW_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000271# endif
272 case EV_LED:
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000273 return decode_bitset(tcp, arg, evdev_leds,
274 LED_MAX, "LED_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000275 case EV_SND:
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000276 return decode_bitset(tcp, arg, evdev_snd,
277 SND_MAX, "SND_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000278 case EV_REP:
279 return decode_bitset(tcp, arg, evdev_autorepeat,
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000280 REP_MAX, "REP_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000281 case EV_FF:
282 return decode_bitset(tcp, arg, evdev_ff_types,
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000283 FF_MAX, "FF_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000284 case EV_PWR:
Dmitry V. Levin47be9f22016-05-28 00:12:01 +0000285 tprints(", ");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000286 printnum_int(tcp, arg, "%d");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700287 return RVAL_IOCTL_DECODED;
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000288 case EV_FF_STATUS:
289 return decode_bitset(tcp, arg, evdev_ff_status,
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000290 FF_STATUS_MAX, "FF_STATUS_???");
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000291 default:
Dmitry V. Levinaa21c072016-05-28 00:49:17 +0000292 tprints(", ");
293 printaddr(arg);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700294 return RVAL_IOCTL_DECODED;
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000295 }
296}
297
298static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800299evdev_read_ioctl(struct tcb *const tcp, const unsigned int code,
300 const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100301{
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000302 /* fixed-number fixed-length commands */
303 switch (code) {
304 case EVIOCGVERSION:
305 tprints(", ");
Dmitry V. Levinb29569a2016-05-27 00:42:07 +0000306 printnum_int(tcp, arg, "%#x");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700307 return RVAL_IOCTL_DECODED;
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000308 case EVIOCGEFFECTS:
309 tprints(", ");
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000310 printnum_int(tcp, arg, "%u");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700311 return RVAL_IOCTL_DECODED;
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000312 case EVIOCGID:
313 return getid_ioctl(tcp, arg);
314# ifdef EVIOCGREP
315 case EVIOCGREP:
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000316 return repeat_ioctl(tcp, arg);
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000317# endif
318 case EVIOCGKEYCODE:
319 return keycode_ioctl(tcp, arg);
320# ifdef EVIOCGKEYCODE_V2
321 case EVIOCGKEYCODE_V2:
322 return keycode_V2_ioctl(tcp, arg);
323# endif
324 }
325
326 /* fixed-number variable-length commands */
327 switch (_IOC_NR(code)) {
328# ifdef EVIOCGMTSLOTS
329 case _IOC_NR(EVIOCGMTSLOTS(0)):
330 return mtslots_ioctl(tcp, code, arg);
331# endif
332 case _IOC_NR(EVIOCGNAME(0)):
333 case _IOC_NR(EVIOCGPHYS(0)):
334 case _IOC_NR(EVIOCGUNIQ(0)):
335 tprints(", ");
Dmitry V. Levin10de2eb2016-05-27 00:42:18 +0000336 if (syserror(tcp))
337 printaddr(arg);
338 else
Elliott Hughesd35df492017-02-15 15:19:05 -0800339 printstrn(tcp, arg, tcp->u_rval);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700340 return RVAL_IOCTL_DECODED;
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000341# ifdef EVIOCGPROP
342 case _IOC_NR(EVIOCGPROP(0)):
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000343 return decode_bitset(tcp, arg, evdev_prop,
344 INPUT_PROP_MAX, "PROP_???");
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000345# endif
346 case _IOC_NR(EVIOCGSND(0)):
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000347 return decode_bitset(tcp, arg, evdev_snd,
348 SND_MAX, "SND_???");
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000349# ifdef EVIOCGSW
350 case _IOC_NR(EVIOCGSW(0)):
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000351 return decode_bitset(tcp, arg, evdev_switch,
352 SW_MAX, "SW_???");
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000353# endif
354 case _IOC_NR(EVIOCGKEY(0)):
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000355 return decode_bitset(tcp, arg, evdev_keycode,
356 KEY_MAX, "KEY_???");
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000357 case _IOC_NR(EVIOCGLED(0)):
Dmitry V. Levin3f23c0c2016-05-27 00:42:25 +0000358 return decode_bitset(tcp, arg, evdev_leds,
359 LED_MAX, "LED_???");
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000360 }
361
362 /* multi-number fixed-length commands */
363 if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0)))
364 return abs_ioctl(tcp, arg);
365
366 /* multi-number variable-length commands */
Dmitry V. Levin53767d82016-05-27 00:40:18 +0000367 if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
368 return bit_ioctl(tcp, _IOC_NR(code) & EV_MAX, arg);
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100369
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000370 return 0;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100371}
372
373static int
Elliott Hughesd35df492017-02-15 15:19:05 -0800374evdev_write_ioctl(struct tcb *const tcp, const unsigned int code,
375 const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100376{
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000377 /* fixed-number fixed-length commands */
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100378 switch (code) {
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000379# ifdef EVIOCSREP
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100380 case EVIOCSREP:
381 return repeat_ioctl(tcp, arg);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000382# endif
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100383 case EVIOCSKEYCODE:
384 return keycode_ioctl(tcp, arg);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000385# ifdef EVIOCSKEYCODE_V2
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100386 case EVIOCSKEYCODE_V2:
387 return keycode_V2_ioctl(tcp, arg);
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000388# endif
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100389 case EVIOCRMFF:
Dmitry V. Levin00394242016-05-27 00:40:27 +0000390 tprintf(", %d", (int) arg);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700391 return RVAL_IOCTL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100392 case EVIOCGRAB:
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000393# ifdef EVIOCREVOKE
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100394 case EVIOCREVOKE:
Dmitry V. Levin8d85c232016-05-27 00:39:33 +0000395# endif
Elliott Hughesd35df492017-02-15 15:19:05 -0800396 tprintf(", %" PRI_klu, arg);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700397 return RVAL_IOCTL_DECODED;
Dmitry V. Levin9635df42016-05-27 00:40:45 +0000398# ifdef EVIOCSCLOCKID
399 case EVIOCSCLOCKID:
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100400 tprints(", ");
401 printnum_int(tcp, arg, "%u");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700402 return RVAL_IOCTL_DECODED;
Dmitry V. Levin9635df42016-05-27 00:40:45 +0000403# endif
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700404 default: {
405 int rc = evdev_write_ioctl_mpers(tcp, code, arg);
406
407 if (rc != RVAL_DECODED)
408 return rc;
409 }
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100410 }
Dmitry V. Levin8a18f802016-05-27 00:40:10 +0000411
412 /* multi-number fixed-length commands */
413 if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0)))
414 return abs_ioctl(tcp, arg);
415
416 return 0;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100417}
418
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700419void
420print_evdev_ff_type(const kernel_ulong_t val)
421{
422 printxval(evdev_ff_types, val, "FF_???");
423}
424
425int
426evdev_ioctl(struct tcb *const tcp,
427 const unsigned int code, const kernel_ulong_t arg)
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100428{
Elliott Hughesdc75b012017-07-05 13:54:44 -0700429 switch (_IOC_DIR(code)) {
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100430 case _IOC_READ:
Dmitry V. Levin2114e082016-05-27 00:40:02 +0000431 if (entering(tcp))
432 return 0;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100433 return evdev_read_ioctl(tcp, code, arg);
434 case _IOC_WRITE:
Dmitry V. Levin2114e082016-05-27 00:40:02 +0000435 return evdev_write_ioctl(tcp, code, arg) | RVAL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100436 default:
Dmitry V. Levin2114e082016-05-27 00:40:02 +0000437 return RVAL_DECODED;
Etienne Gemsa4f750b92015-02-20 17:14:10 +0100438 }
439}
440
441#endif /* HAVE_LINUX_INPUT_H */