1 /*
2 * Copyright (c) 2020-2022 The strace developers.
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7
8 #include "defs.h"
9
10 #include <linux/gpio.h>
11
12 static int
13 print_gpiochip_info(struct tcb *const tcp, const kernel_ulong_t arg)
14 {
15 struct gpiochip_info info;
16
17 if (entering(tcp))
18 return 0;
19
20 tprint_arg_next();
21 if (umove_or_printaddr(tcp, arg, &info))
22 return RVAL_IOCTL_DECODED;
23
24 tprint_struct_begin();
25 PRINT_FIELD_CSTRING(info, name);
26 tprint_struct_next();
27 PRINT_FIELD_CSTRING(info, label);
28 tprint_struct_next();
29 PRINT_FIELD_U(info, lines);
30 tprint_struct_end();
31
32 return RVAL_IOCTL_DECODED;
33 }
34
35 #include "xlat/gpio_line_flags.h"
36
37 static int
38 print_gpioline_info(struct tcb *const tcp, const kernel_ulong_t arg)
39 {
40 struct gpioline_info info;
41
42 if (entering(tcp))
43 tprint_arg_next();
44 else if (syserror(tcp))
45 return RVAL_IOCTL_DECODED;
46 else
47 tprint_value_changed();
48
49 if (umove_or_printaddr(tcp, arg, &info))
50 return RVAL_IOCTL_DECODED;
51
52 if (entering(tcp)) {
53 tprint_struct_begin();
54 PRINT_FIELD_U(info, line_offset);
55 tprint_struct_end();
56 return 0;
57 }
58
59 /* exiting */
60 tprint_struct_begin();
61 PRINT_FIELD_FLAGS(info, flags, gpio_line_flags, "GPIOLINE_FLAG_???");
62 tprint_struct_next();
63 PRINT_FIELD_CSTRING(info, name);
64 tprint_struct_next();
65 PRINT_FIELD_CSTRING(info, consumer);
66 tprint_struct_end();
67
68 return RVAL_IOCTL_DECODED;
69 }
70
71 static int
72 print_gpioline_info_unwatch(struct tcb *const tcp, const kernel_ulong_t arg)
73 {
74 struct { uint32_t offset; } data;
75
76 tprint_arg_next();
77 if (!umove_or_printaddr(tcp, arg, &data)) {
78 tprint_struct_begin();
79 PRINT_FIELD_U(data, offset);
80 tprint_struct_end();
81 }
82
83 return RVAL_IOCTL_DECODED;
84 }
85
86 #include "xlat/gpio_handle_flags.h"
87
88 static int
89 print_gpiohandle_request(struct tcb *const tcp, const kernel_ulong_t arg)
90 {
91 struct gpiohandle_request hr;
92
93 if (entering(tcp))
94 tprint_arg_next();
95 else if (syserror(tcp))
96 return RVAL_IOCTL_DECODED;
97 else
98 tprint_value_changed();
99
100 if (umove_or_printaddr(tcp, arg, &hr))
101 return RVAL_IOCTL_DECODED;
102
103 if (exiting(tcp)) {
104 tprint_struct_begin();
105 PRINT_FIELD_FD(hr, fd, tcp);
106 tprint_struct_end();
107 return RVAL_IOCTL_DECODED;
108 }
109
110 /* entering */
111 tprint_struct_begin();
112 PRINT_FIELD_U(hr, lines);
113 tprint_struct_next();
114 PRINT_FIELD_ARRAY_UPTO(hr, lineoffsets, hr.lines, tcp,
115 print_uint_array_member);
116 tprint_struct_next();
117 PRINT_FIELD_FLAGS(hr, flags, gpio_handle_flags,
118 "GPIOHANDLE_REQUEST_???");
119 tprint_struct_next();
120 PRINT_FIELD_ARRAY_UPTO(hr, default_values, hr.lines, tcp,
121 print_uint_array_member);
122 tprint_struct_next();
123 PRINT_FIELD_CSTRING(hr, consumer_label);
124 tprint_struct_end();
125 return 0;
126 }
127
128 #include "xlat/gpio_event_flags.h"
129
130 static int
131 print_gpioevent_request(struct tcb *const tcp, const kernel_ulong_t arg)
132 {
133 struct gpioevent_request er;
134
135 if (entering(tcp))
136 tprint_arg_next();
137 else if (syserror(tcp))
138 return RVAL_IOCTL_DECODED;
139 else
140 tprint_value_changed();
141
142 if (umove_or_printaddr(tcp, arg, &er))
143 return RVAL_IOCTL_DECODED;
144
145 if (exiting(tcp)) {
146 tprint_struct_begin();
147 PRINT_FIELD_FD(er, fd, tcp);
148 tprint_struct_end();
149 return RVAL_IOCTL_DECODED;
150 }
151
152 /* entering */
153 tprint_struct_begin();
154 PRINT_FIELD_U(er, lineoffset);
155 tprint_struct_next();
156 PRINT_FIELD_FLAGS(er, handleflags, gpio_handle_flags,
157 "GPIOHANDLE_REQUEST_???");
158 tprint_struct_next();
159 PRINT_FIELD_FLAGS(er, eventflags, gpio_event_flags,
160 "GPIOEVENT_REQUEST_???");
161 tprint_struct_next();
162 PRINT_FIELD_CSTRING(er, consumer_label);
163 tprint_struct_end();
164 return 0;
165 }
166
167 static void
168 print_gpiohandle_data(struct tcb *const tcp, const struct gpiohandle_data *vals)
169 {
170 tprint_struct_begin();
171 PRINT_FIELD_ARRAY(*vals, values, tcp, print_uint_array_member);
172 tprint_struct_end();
173 }
174
175 static int
176 print_gpiohandle_get_values(struct tcb *const tcp, const kernel_ulong_t arg)
177 {
178 struct gpiohandle_data vals;
179
180 if (entering(tcp))
181 return 0;
182
183 /* exiting */
184 tprint_arg_next();
185 if (!umove_or_printaddr(tcp, arg, &vals))
186 print_gpiohandle_data(tcp, &vals);
187
188 return RVAL_IOCTL_DECODED;
189 }
190
191 static int
192 print_gpiohandle_set_values(struct tcb *const tcp, const kernel_ulong_t arg)
193 {
194 struct gpiohandle_data vals;
195
196 tprint_arg_next();
197 if (!umove_or_printaddr(tcp, arg, &vals))
198 print_gpiohandle_data(tcp, &vals);
199
200 return RVAL_IOCTL_DECODED;
201 }
202
203 static int
204 print_gpiohandle_set_config(struct tcb *const tcp, const kernel_ulong_t arg)
205 {
206 struct gpiohandle_config hc;
207
208 tprint_arg_next();
209 if (umove_or_printaddr(tcp, arg, &hc))
210 return RVAL_IOCTL_DECODED;
211
212 tprint_struct_begin();
213 PRINT_FIELD_FLAGS(hc, flags, gpio_handle_flags, "GPIOHANDLE_REQUEST_???");
214 tprint_struct_next();
215 PRINT_FIELD_ARRAY(hc, default_values, tcp, print_uint_array_member);
216 tprint_struct_end();
217
218 return RVAL_IOCTL_DECODED;
219 }
220
221 #include "xlat/gpio_v2_line_flags.h"
222 #include "xlat/gpio_v2_line_attr_ids.h"
223
224 static void
225 print_gpio_v2_line_attribute_raw(const struct gpio_v2_line_attribute *attr,
226 bool as_field)
227 {
228 if (as_field) {
229 tprints_field_name("attr");
230 tprint_struct_begin();
231 }
232 PRINT_FIELD_U(*attr, id);
233 if (attr->padding) {
234 tprint_struct_next();
235 PRINT_FIELD_X(*attr, padding);
236 }
237 tprint_struct_next();
238 tprints_field_name("data");
239 PRINT_VAL_X(attr->values);
240 if (as_field)
241 tprint_struct_end();
242 }
243
244 static void
245 print_gpio_v2_line_attribute(const struct gpio_v2_line_attribute *attr,
246 bool as_field)
247 {
248 if (attr->padding) {
249 /* unexpected padding usage so decode fields raw */
250 print_gpio_v2_line_attribute_raw(attr, as_field);
251 return;
252 }
253 switch (attr->id) {
254 case GPIO_V2_LINE_ATTR_ID_FLAGS:
255 PRINT_FIELD_FLAGS(*attr, flags, gpio_v2_line_flags,
256 "GPIO_V2_LINE_FLAG_???");
257 break;
258 case GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES:
259 PRINT_FIELD_X(*attr, values);
260 break;
261 case GPIO_V2_LINE_ATTR_ID_DEBOUNCE:
262 PRINT_FIELD_U(*attr, debounce_period_us);
263 break;
264 default:
265 /* unknown id so decode fields raw */
266 print_gpio_v2_line_attribute_raw(attr, as_field);
267 break;
268 }
269 }
270
271 static void
272 print_gpio_v2_line_config_attribute(const struct gpio_v2_line_config_attribute *attr)
273 {
274 tprint_struct_begin();
275 print_gpio_v2_line_attribute(&attr->attr, true);
276 tprint_struct_next();
277 PRINT_FIELD_X(*attr, mask);
278 tprint_struct_end();
279 }
280
281 static bool
282 print_gpio_v2_line_attr_array_member(struct tcb *tcp, void *elem_buf,
283 size_t elem_size, void *data)
284 {
285 tprint_struct_begin();
286 print_gpio_v2_line_attribute(elem_buf, false);
287 tprint_struct_end();
288
289 return true;
290 }
291
292 static bool
293 print_gpio_v2_line_config_attr_array_member(struct tcb *tcp, void *elem_buf,
294 size_t elem_size, void *data)
295 {
296 print_gpio_v2_line_config_attribute(elem_buf);
297
298 return true;
299 }
300
301 static void
302 print_gpio_v2_line_config(struct tcb *const tcp,
303 const struct gpio_v2_line_config *lc)
304 {
305 tprint_struct_begin();
306 PRINT_FIELD_FLAGS(*lc, flags, gpio_v2_line_flags,
307 "GPIO_V2_LINE_FLAG_???");
308 tprint_struct_next();
309 PRINT_FIELD_U(*lc, num_attrs);
310 if (!IS_ARRAY_ZERO(lc->padding)) {
311 tprint_struct_next();
312 PRINT_FIELD_X_ARRAY(*lc, padding);
313 }
314 if (lc->num_attrs) {
315 tprint_struct_next();
316 PRINT_FIELD_ARRAY_UPTO(*lc, attrs, lc->num_attrs, tcp,
317 print_gpio_v2_line_config_attr_array_member);
318 }
319 tprint_struct_end();
320 }
321
322 static int
323 print_gpio_v2_line_info(struct tcb *const tcp, const kernel_ulong_t arg)
324 {
325 struct gpio_v2_line_info li;
326
327 if (entering(tcp))
328 tprint_arg_next();
329 else if (syserror(tcp))
330 return RVAL_IOCTL_DECODED;
331 else
332 tprint_value_changed();
333
334 if (umove_or_printaddr(tcp, arg, &li))
335 return RVAL_IOCTL_DECODED;
336
337 if (entering(tcp)) {
338 tprint_struct_begin();
339 PRINT_FIELD_U(li, offset);
340 tprint_struct_end();
341 return 0;
342 }
343
344 /* exiting */
345 tprint_struct_begin();
346 PRINT_FIELD_CSTRING(li, name);
347 tprint_struct_next();
348 PRINT_FIELD_CSTRING(li, consumer);
349 tprint_struct_next();
350 PRINT_FIELD_FLAGS(li, flags, gpio_v2_line_flags, "GPIO_V2_LINE_FLAG_???");
351 tprint_struct_next();
352 PRINT_FIELD_U(li, num_attrs);
353 if (li.num_attrs) {
354 tprint_struct_next();
355 PRINT_FIELD_ARRAY_UPTO(li, attrs, li.num_attrs, tcp,
356 print_gpio_v2_line_attr_array_member);
357 }
358 if (!IS_ARRAY_ZERO(li.padding)) {
359 tprint_struct_next();
360 PRINT_FIELD_X_ARRAY(li, padding);
361 }
362 tprint_struct_end();
363
364 return RVAL_IOCTL_DECODED;
365 }
366
367 static int
368 print_gpio_v2_line_request(struct tcb *const tcp, const kernel_ulong_t arg)
369 {
370 struct gpio_v2_line_request lr;
371
372 if (entering(tcp))
373 tprint_arg_next();
374 else if (syserror(tcp))
375 return RVAL_IOCTL_DECODED;
376 else
377 tprint_value_changed();
378
379 if (umove_or_printaddr(tcp, arg, &lr))
380 return RVAL_IOCTL_DECODED;
381
382 if (exiting(tcp)) {
383 tprint_struct_begin();
384 PRINT_FIELD_FD(lr, fd, tcp);
385 tprint_struct_end();
386 return RVAL_IOCTL_DECODED;
387 }
388
389 /* entering */
390 tprint_struct_begin();
391 PRINT_FIELD_U(lr, num_lines);
392 tprint_struct_next();
393 PRINT_FIELD_ARRAY_UPTO(lr, offsets, lr.num_lines, tcp,
394 print_uint_array_member);
395 tprint_struct_next();
396 PRINT_FIELD_CSTRING(lr, consumer);
397 tprint_struct_next();
398 PRINT_FIELD_OBJ_TCB_PTR(lr, config, tcp,
399 print_gpio_v2_line_config);
400 if (lr.event_buffer_size) {
401 tprint_struct_next();
402 PRINT_FIELD_U(lr, event_buffer_size);
403 }
404 if (!IS_ARRAY_ZERO(lr.padding)) {
405 tprint_struct_next();
406 PRINT_FIELD_X_ARRAY(lr, padding);
407 }
408 tprint_struct_end();
409 return 0;
410 }
411
412 static int
413 print_gpio_v2_line_get_values(struct tcb *const tcp, const kernel_ulong_t arg)
414 {
415 struct gpio_v2_line_values vals;
416
417 if (entering(tcp))
418 tprint_arg_next();
419 else if (syserror(tcp))
420 return RVAL_IOCTL_DECODED;
421 else
422 tprint_value_changed();
423
424 if (umove_or_printaddr(tcp, arg, &vals))
425 return RVAL_IOCTL_DECODED;
426
427 if (entering(tcp)) {
428 tprint_struct_begin();
429 PRINT_FIELD_X(vals, mask);
430 tprint_struct_end();
431 return 0;
432 }
433
434 /* exiting */
435 tprint_struct_begin();
436 PRINT_FIELD_X(vals, bits);
437 tprint_struct_end();
438
439 return RVAL_IOCTL_DECODED;
440 }
441
442 static int
443 print_gpio_v2_line_set_values(struct tcb *const tcp, const kernel_ulong_t arg)
444 {
445 struct gpio_v2_line_values vals;
446
447 tprint_arg_next();
448 if (!umove_or_printaddr(tcp, arg, &vals)) {
449 tprint_struct_begin();
450 PRINT_FIELD_X(vals, bits);
451 tprint_struct_next();
452 PRINT_FIELD_X(vals, mask);
453 tprint_struct_end();
454 }
455
456 return RVAL_IOCTL_DECODED;
457 }
458
459 static int
460 print_gpio_v2_line_set_config(struct tcb *const tcp, const kernel_ulong_t arg)
461 {
462 struct gpio_v2_line_config lc;
463
464 tprint_arg_next();
465 if (!umove_or_printaddr(tcp, arg, &lc))
466 print_gpio_v2_line_config(tcp, &lc);
467
468 return RVAL_IOCTL_DECODED;
469 }
470
471 int
472 gpio_ioctl(struct tcb *const tcp, const unsigned int code,
473 const kernel_ulong_t arg)
474 {
475 switch (code) {
476 case GPIO_GET_CHIPINFO_IOCTL:
477 return print_gpiochip_info(tcp, arg);
478 case GPIO_GET_LINEINFO_UNWATCH_IOCTL:
479 return print_gpioline_info_unwatch(tcp, arg);
480 case GPIO_V2_GET_LINEINFO_IOCTL:
481 case GPIO_V2_GET_LINEINFO_WATCH_IOCTL:
482 return print_gpio_v2_line_info(tcp, arg);
483 case GPIO_V2_GET_LINE_IOCTL:
484 return print_gpio_v2_line_request(tcp, arg);
485 case GPIO_V2_LINE_SET_CONFIG_IOCTL:
486 return print_gpio_v2_line_set_config(tcp, arg);
487 case GPIO_V2_LINE_GET_VALUES_IOCTL:
488 return print_gpio_v2_line_get_values(tcp, arg);
489 case GPIO_V2_LINE_SET_VALUES_IOCTL:
490 return print_gpio_v2_line_set_values(tcp, arg);
491 case GPIO_GET_LINEINFO_IOCTL:
492 case GPIO_GET_LINEINFO_WATCH_IOCTL:
493 return print_gpioline_info(tcp, arg);
494 case GPIO_GET_LINEHANDLE_IOCTL:
495 return print_gpiohandle_request(tcp, arg);
496 case GPIO_GET_LINEEVENT_IOCTL:
497 return print_gpioevent_request(tcp, arg);
498 case GPIOHANDLE_GET_LINE_VALUES_IOCTL:
499 return print_gpiohandle_get_values(tcp, arg);
500 case GPIOHANDLE_SET_LINE_VALUES_IOCTL:
501 return print_gpiohandle_set_values(tcp, arg);
502 case GPIOHANDLE_SET_CONFIG_IOCTL:
503 return print_gpiohandle_set_config(tcp, arg);
504 }
505 return RVAL_DECODED;
506 }