1 /*
2 * Check GPIO_* ioctl decoding.
3 *
4 * Copyright (c) 2021-2022 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include <errno.h>
12 #include <inttypes.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/ioctl.h>
17 #include <linux/gpio.h>
18
19 #define str_event_flags XLAT_KNOWN(0x3, "GPIOEVENT_REQUEST_BOTH_EDGES")
20 #define str_handle_flags XLAT_KNOWN(0x14, \
21 "GPIOHANDLE_REQUEST_ACTIVE_LOW|GPIOHANDLE_REQUEST_OPEN_SOURCE")
22 #define str_info_flags XLAT_KNOWN(0xc, \
23 "GPIOLINE_FLAG_ACTIVE_LOW|GPIOLINE_FLAG_OPEN_DRAIN")
24 #define str_line_flags XLAT_KNOWN(0x102, \
25 "GPIO_V2_LINE_FLAG_ACTIVE_LOW|GPIO_V2_LINE_FLAG_BIAS_PULL_UP")
26
27 #define UNK_GPIO_FLAG 0x8000
28
29 #define str_handle_unk_flag XLAT_UNKNOWN(UNK_GPIO_FLAG, "GPIOHANDLE_REQUEST_???")
30 #define str_info_unk_flag XLAT_UNKNOWN(UNK_GPIO_FLAG, "GPIOLINE_FLAG_???")
31 #define str_line_unk_flag XLAT_UNKNOWN(UNK_GPIO_FLAG, "GPIO_V2_LINE_FLAG_???")
32
33 #if VERBOSE
34 # define str_line_seq "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, " \
35 "16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, " \
36 "33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, " \
37 "50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64]"
38 # define str_default_seq "[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, " \
39 "29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, " \
40 "63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, " \
41 "97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, " \
42 "125, 127]"
43 #else
44 # define str_line_seq "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, " \
45 "16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ...]"
46 # define str_default_seq "[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, " \
47 "29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, " \
48 "63, ...]"
49 #endif
50
51 static const char *errstr;
52
53 static long
54 do_ioctl(kernel_ulong_t cmd, kernel_ulong_t arg)
55 {
56 long rc = ioctl(-1, cmd, arg);
57
58 errstr = sprintrc(rc);
59
60 #ifdef INJECT_RETVAL
61 if (rc != INJECT_RETVAL)
62 error_msg_and_fail("Got a return value of %ld != %ld",
63 rc, (long) INJECT_RETVAL);
64
65 static char inj_errstr[4096];
66
67 snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
68 errstr = inj_errstr;
69 #endif
70
71 return rc;
72 }
73
74 static long
75 do_ioctl_ptr(kernel_ulong_t cmd, const void *arg)
76 {
77 return do_ioctl(cmd, (uintptr_t) arg);
78 }
79
80 static void
81 test_print_gpiochip_info(void)
82 {
83 long rc;
84
85 do_ioctl(GPIO_GET_CHIPINFO_IOCTL, 0);
86 printf("ioctl(-1, %s, NULL) = %s\n",
87 XLAT_STR(GPIO_GET_CHIPINFO_IOCTL), errstr);
88
89 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpiochip_info, p_chipinfo);
90
91 p_chipinfo->lines = 0xca;
92 strcpy(p_chipinfo->name, "chip name");
93 strcpy(p_chipinfo->label, "chip label");
94
95 do_ioctl_ptr(GPIO_GET_CHIPINFO_IOCTL, (char *) p_chipinfo + 1);
96 printf("ioctl(-1, %s, %p) = %s\n",
97 XLAT_STR(GPIO_GET_CHIPINFO_IOCTL), (char *) p_chipinfo + 1, errstr);
98
99 rc = do_ioctl_ptr(GPIO_GET_CHIPINFO_IOCTL, p_chipinfo);
100 printf("ioctl(-1, %s, ", XLAT_STR(GPIO_GET_CHIPINFO_IOCTL));
101 if (rc >= 0)
102 printf("{name=\"chip name\", label=\"chip label\", lines=202}");
103 else
104 printf("%p", p_chipinfo);
105 printf(") = %s\n", errstr);
106 }
107
108 static void
109 test_print_gpioline_info(void)
110 {
111 long rc;
112
113 do_ioctl(GPIO_GET_LINEINFO_IOCTL, 0);
114 printf("ioctl(-1, %s, NULL) = %s\n",
115 XLAT_STR(GPIO_GET_LINEINFO_IOCTL), errstr);
116
117 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpioline_info, p_lineinfo);
118
119 p_lineinfo->line_offset = 0x32;
120 p_lineinfo->flags = GPIOLINE_FLAG_ACTIVE_LOW|GPIOLINE_FLAG_OPEN_DRAIN;
121 strcpy(p_lineinfo->name, "line name");
122 strcpy(p_lineinfo->consumer, "line consumer");
123
124 do_ioctl_ptr(GPIO_GET_LINEINFO_IOCTL, (char *) p_lineinfo + 1);
125 printf("ioctl(-1, %s, %p) = %s\n",
126 XLAT_STR(GPIO_GET_LINEINFO_IOCTL), (char *) p_lineinfo + 1, errstr);
127
128 /* GPIO_GET_LINEINFO_IOCTL */
129 rc = do_ioctl_ptr(GPIO_GET_LINEINFO_IOCTL, p_lineinfo);
130 printf("ioctl(-1, %s, {line_offset=50}",
131 XLAT_STR(GPIO_GET_LINEINFO_IOCTL));
132 if (rc >= 0)
133 printf(" => {flags=" str_info_flags
134 ", name=\"line name\", consumer=\"line consumer\"}");
135 printf(") = %s\n", errstr);
136
137 /* GPIO_GET_LINEINFO_WATCH_IOCTL */
138 rc = do_ioctl_ptr(GPIO_GET_LINEINFO_WATCH_IOCTL, p_lineinfo);
139 printf("ioctl(-1, %s, {line_offset=50}",
140 XLAT_STR(GPIO_GET_LINEINFO_WATCH_IOCTL));
141 if (rc >= 0)
142 printf(" => {flags=" str_info_flags
143 ", name=\"line name\", consumer=\"line consumer\"}");
144 printf(") = %s\n", errstr);
145
146 /* unknown flag */
147 p_lineinfo->flags = UNK_GPIO_FLAG;
148 rc = do_ioctl_ptr(GPIO_GET_LINEINFO_IOCTL, p_lineinfo);
149 printf("ioctl(-1, %s, {line_offset=50}",
150 XLAT_STR(GPIO_GET_LINEINFO_IOCTL));
151 if (rc >= 0)
152 printf(" => {flags=" str_info_unk_flag
153 ", name=\"line name\", consumer=\"line consumer\"}");
154 printf(") = %s\n", errstr);
155 }
156
157 static void
158 test_print_gpioline_info_unwatch(void)
159 {
160 do_ioctl_ptr(GPIO_GET_LINEINFO_UNWATCH_IOCTL, 0);
161 printf("ioctl(-1, %s, NULL) = %s\n",
162 XLAT_STR(GPIO_GET_LINEINFO_UNWATCH_IOCTL), errstr);
163
164 TAIL_ALLOC_OBJECT_VAR_PTR(uint32_t, p_offset);
165
166 *p_offset = 0;
167 do_ioctl_ptr(GPIO_GET_LINEINFO_UNWATCH_IOCTL, p_offset);
168 printf("ioctl(-1, %s, {offset=0}) = %s\n",
169 XLAT_STR(GPIO_GET_LINEINFO_UNWATCH_IOCTL), errstr);
170
171 *p_offset = 78;
172 do_ioctl_ptr(GPIO_GET_LINEINFO_UNWATCH_IOCTL, p_offset);
173 printf("ioctl(-1, %s, {offset=78}) = %s\n",
174 XLAT_STR(GPIO_GET_LINEINFO_UNWATCH_IOCTL), errstr);
175 }
176
177 static void
178 test_print_gpiohandle_request(void)
179 {
180 long rc;
181
182 do_ioctl(GPIO_GET_LINEHANDLE_IOCTL, 0);
183 printf("ioctl(-1, %s, NULL) = %s\n",
184 XLAT_STR(GPIO_GET_LINEHANDLE_IOCTL), errstr);
185
186 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpiohandle_request, p_handle_request);
187
188 p_handle_request->lines = 4;
189 p_handle_request->lineoffsets[0] = 0x12;
190 p_handle_request->lineoffsets[1] = 0x23;
191 p_handle_request->lineoffsets[2] = 0x34;
192 p_handle_request->lineoffsets[3] = 0x45;
193 p_handle_request->default_values[0] = 0x0;
194 p_handle_request->default_values[1] = 0x1;
195 p_handle_request->default_values[2] = 0x2;
196 p_handle_request->default_values[3] = 0x6;
197 p_handle_request->flags = GPIOHANDLE_REQUEST_ACTIVE_LOW|GPIOHANDLE_REQUEST_OPEN_SOURCE;
198 strcpy(p_handle_request->consumer_label, "line consumer");
199 p_handle_request->fd = 0x64;
200
201 do_ioctl_ptr(GPIO_GET_LINEHANDLE_IOCTL, (char *) p_handle_request + 1);
202 printf("ioctl(-1, %s, %p) = %s\n",
203 XLAT_STR(GPIO_GET_LINEHANDLE_IOCTL), (char *) p_handle_request + 1, errstr);
204
205 rc = do_ioctl_ptr(GPIO_GET_LINEHANDLE_IOCTL, p_handle_request);
206 printf("ioctl(-1, %s, {lines=4, lineoffsets=[18, 35, 52, 69], flags=" str_handle_flags
207 ", default_values=[0, 1, 2, 6], consumer_label=\"line consumer\"}",
208 XLAT_STR(GPIO_GET_LINEHANDLE_IOCTL));
209 if (rc >= 0)
210 printf(" => {fd=100}");
211 printf(") = %s\n", errstr);
212
213 /* lines > GPIOHANDLES_MAX */
214 p_handle_request->lines = GPIOHANDLES_MAX + 1;
215 for (int i = 0; i < GPIOHANDLES_MAX; i++) {
216 p_handle_request->lineoffsets[i] = i + 1;
217 p_handle_request->default_values[i] = 2*i + 1;
218 }
219 rc = do_ioctl_ptr(GPIO_GET_LINEHANDLE_IOCTL, p_handle_request);
220 printf("ioctl(-1, %s, {lines=65, lineoffsets=" str_line_seq
221 ", flags=" str_handle_flags ", default_values=" str_default_seq
222 ", consumer_label=\"line consumer\"}",
223 XLAT_STR(GPIO_GET_LINEHANDLE_IOCTL));
224 if (rc >= 0)
225 printf(" => {fd=100}");
226 printf(") = %s\n", errstr);
227 }
228
229 static void
230 test_print_gpioevent_request(void)
231 {
232 long rc;
233
234 do_ioctl(GPIO_GET_LINEEVENT_IOCTL, 0);
235 printf("ioctl(-1, %s, NULL) = %s\n",
236 XLAT_STR(GPIO_GET_LINEEVENT_IOCTL), errstr);
237
238 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpioevent_request, p_event_request);
239
240 p_event_request->lineoffset = 4;
241 p_event_request->handleflags = GPIOHANDLE_REQUEST_ACTIVE_LOW|GPIOHANDLE_REQUEST_OPEN_SOURCE;
242 p_event_request->eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
243 strcpy(p_event_request->consumer_label, "line consumer");
244 p_event_request->fd = 0x65;
245
246 do_ioctl_ptr(GPIO_GET_LINEEVENT_IOCTL, (char *) p_event_request + 1);
247 printf("ioctl(-1, %s, %p) = %s\n",
248 XLAT_STR(GPIO_GET_LINEEVENT_IOCTL), (char *) p_event_request + 1, errstr);
249
250 rc = do_ioctl_ptr(GPIO_GET_LINEEVENT_IOCTL, p_event_request);
251 printf("ioctl(-1, %s, {lineoffset=4, handleflags=" str_handle_flags
252 ", eventflags=" str_event_flags ", consumer_label=\"line consumer\"}",
253 XLAT_STR(GPIO_GET_LINEEVENT_IOCTL));
254 if (rc >= 0)
255 printf(" => {fd=101}");
256 printf(") = %s\n", errstr);
257 }
258
259 static void
260 test_print_gpiohandle_get_values(void)
261 {
262 long rc;
263
264 do_ioctl(GPIOHANDLE_GET_LINE_VALUES_IOCTL, 0);
265 printf("ioctl(-1, %s, NULL) = %s\n",
266 XLAT_STR(GPIOHANDLE_GET_LINE_VALUES_IOCTL), errstr);
267
268 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpiohandle_data, p_handle_data);
269
270 for (int i = 0; i < GPIOHANDLES_MAX; i++)
271 p_handle_data->values[i] = i + 1;
272
273 do_ioctl_ptr(GPIOHANDLE_GET_LINE_VALUES_IOCTL, (char *) p_handle_data + 1);
274 printf("ioctl(-1, %s, %p) = %s\n",
275 XLAT_STR(GPIOHANDLE_GET_LINE_VALUES_IOCTL), (char *) p_handle_data + 1, errstr);
276
277 rc = do_ioctl_ptr(GPIOHANDLE_GET_LINE_VALUES_IOCTL, p_handle_data);
278 printf("ioctl(-1, %s, ", XLAT_STR(GPIOHANDLE_GET_LINE_VALUES_IOCTL));
279 if (rc >= 0)
280 printf("{values=" str_line_seq "}");
281 else
282 printf("%p", p_handle_data);
283 printf(") = %s\n", errstr);
284 }
285
286 static void
287 test_print_gpiohandle_set_values(void)
288 {
289 do_ioctl(GPIOHANDLE_SET_LINE_VALUES_IOCTL, 0);
290 printf("ioctl(-1, %s, NULL) = %s\n",
291 XLAT_STR(GPIOHANDLE_SET_LINE_VALUES_IOCTL), errstr);
292
293 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpiohandle_data, p_handle_data);
294
295 for (int i = 0; i < GPIOHANDLES_MAX; i++)
296 p_handle_data->values[i] = i + 1;
297
298 do_ioctl_ptr(GPIOHANDLE_SET_LINE_VALUES_IOCTL, (char *) p_handle_data + 1);
299 printf("ioctl(-1, %s, %p) = %s\n",
300 XLAT_STR(GPIOHANDLE_SET_LINE_VALUES_IOCTL), (char *) p_handle_data + 1, errstr);
301
302 do_ioctl_ptr(GPIOHANDLE_SET_LINE_VALUES_IOCTL, p_handle_data);
303 printf("ioctl(-1, %s, {values=" str_line_seq "}) = %s\n",
304 XLAT_STR(GPIOHANDLE_SET_LINE_VALUES_IOCTL),
305 errstr);
306 }
307
308 static void
309 test_print_gpiohandle_set_config(void)
310 {
311 do_ioctl(GPIOHANDLE_SET_CONFIG_IOCTL, 0);
312 printf("ioctl(-1, %s, NULL) = %s\n",
313 XLAT_STR(GPIOHANDLE_SET_CONFIG_IOCTL), errstr);
314
315 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpiohandle_config, p_handle_config);
316
317 p_handle_config->flags = GPIOHANDLE_REQUEST_ACTIVE_LOW|GPIOHANDLE_REQUEST_OPEN_SOURCE;
318 for (int i = 0; i < GPIOHANDLES_MAX; i++)
319 p_handle_config->default_values[i] = i + 1;
320
321 do_ioctl_ptr(GPIOHANDLE_SET_CONFIG_IOCTL, (char *) p_handle_config + 1);
322 printf("ioctl(-1, %s, %p) = %s\n",
323 XLAT_STR(GPIOHANDLE_SET_CONFIG_IOCTL), (char *) p_handle_config + 1, errstr);
324
325 do_ioctl_ptr(GPIOHANDLE_SET_CONFIG_IOCTL, p_handle_config);
326 printf("ioctl(-1, %s, {flags=" str_handle_flags
327 ", default_values=" str_line_seq "}) = %s\n",
328 XLAT_STR(GPIOHANDLE_SET_CONFIG_IOCTL), errstr);
329
330 /* unknown flag */
331 p_handle_config->flags = UNK_GPIO_FLAG;
332 do_ioctl_ptr(GPIOHANDLE_SET_CONFIG_IOCTL, p_handle_config);
333 printf("ioctl(-1, %s, {flags=" str_handle_unk_flag
334 ", default_values=" str_line_seq "}) = %s\n",
335 XLAT_STR(GPIOHANDLE_SET_CONFIG_IOCTL), errstr);
336 }
337
338 static void
339 print_gpio_v2_line_attr(struct gpio_v2_line_attribute *attr)
340 {
341 printf("{");
342 switch (attr->id) {
343 case GPIO_V2_LINE_ATTR_ID_FLAGS:
344 printf("flags=%#" PRIx64 NRAW(" /* GPIO_V2_LINE_FLAG_??? */"),
345 (uint64_t) attr->flags);
346 break;
347 case GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES:
348 printf("values=%#" PRIx64, (uint64_t) attr->values);
349 break;
350 case GPIO_V2_LINE_ATTR_ID_DEBOUNCE:
351 printf("debounce_period_us=%u", attr->debounce_period_us);
352 break;
353 default:
354 printf("id=%u, data=%#" PRIx64, attr->id, (uint64_t) attr->values);
355 break;
356 }
357 printf("}");
358 }
359
360 static void
361 test_print_gpio_v2_line_info(void)
362 {
363 long rc;
364
365 do_ioctl(GPIO_V2_GET_LINEINFO_IOCTL, 0);
366 printf("ioctl(-1, %s, NULL) = %s\n",
367 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL), errstr);
368
369 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpio_v2_line_info, p_lineinfo);
370
371 strcpy(p_lineinfo->name, "line name");
372 strcpy(p_lineinfo->consumer, "line consumer");
373 p_lineinfo->offset = 0x32;
374 p_lineinfo->num_attrs = 0;
375 p_lineinfo->flags = GPIO_V2_LINE_FLAG_ACTIVE_LOW|GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
376 memset(p_lineinfo->padding, 0, sizeof(p_lineinfo->padding));
377
378 do_ioctl_ptr(GPIO_V2_GET_LINEINFO_IOCTL, (char *) p_lineinfo + 1);
379 printf("ioctl(-1, %s, %p) = %s\n",
380 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL), (char *) p_lineinfo + 1, errstr);
381
382 /* GPIO_V2_GET_LINEINFO_IOCTL */
383 rc = do_ioctl_ptr(GPIO_V2_GET_LINEINFO_IOCTL, p_lineinfo);
384 printf("ioctl(-1, %s, {offset=50}",
385 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL));
386 if (rc >= 0)
387 printf(" => {name=\"line name\", consumer=\"line consumer\", flags="
388 str_line_flags ", num_attrs=0}");
389 printf(") = %s\n", errstr);
390
391 /* GPIO_V2_GET_LINEINFO_WATCH_IOCTL */
392 rc = do_ioctl_ptr(GPIO_V2_GET_LINEINFO_WATCH_IOCTL, p_lineinfo);
393 printf("ioctl(-1, %s, {offset=50}",
394 XLAT_STR(GPIO_V2_GET_LINEINFO_WATCH_IOCTL));
395 if (rc >= 0)
396 printf(" => {name=\"line name\", consumer=\"line consumer\", flags="
397 str_line_flags ", num_attrs=0}");
398 printf(") = %s\n", errstr);
399
400 /* unknown flag */
401 p_lineinfo->offset = 0x35;
402 p_lineinfo->flags = UNK_GPIO_FLAG;
403 rc = do_ioctl_ptr(GPIO_V2_GET_LINEINFO_IOCTL, p_lineinfo);
404 printf("ioctl(-1, %s, {offset=53}",
405 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL));
406 if (rc >= 0)
407 printf(" => {name=\"line name\", consumer=\"line consumer\", flags="
408 str_line_unk_flag ", num_attrs=0}");
409 printf(") = %s\n", errstr);
410 p_lineinfo->flags = GPIO_V2_LINE_FLAG_ACTIVE_LOW|GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
411
412 /* with non-zero padding */
413 p_lineinfo->offset = 0x36;
414 p_lineinfo->padding[2] = 0xdeadd0d0;
415 rc = do_ioctl_ptr(GPIO_V2_GET_LINEINFO_IOCTL, p_lineinfo);
416 printf("ioctl(-1, %s, {offset=54}",
417 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL));
418 if (rc >= 0)
419 printf(" => {name=\"line name\", consumer=\"line consumer\", flags="
420 str_line_flags ", num_attrs=0, padding=[0, 0, 0xdeadd0d0, 0]}");
421 printf(") = %s\n", errstr);
422 memset(p_lineinfo->padding, 0, sizeof(p_lineinfo->padding));
423
424 /* num_attrs = 1 */
425 p_lineinfo->offset = 0x37;
426 memset(p_lineinfo->attrs, 0, sizeof(p_lineinfo->attrs));
427 p_lineinfo->num_attrs = 1;
428 p_lineinfo->attrs[0].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
429 p_lineinfo->attrs[0].debounce_period_us = 0xdeadbeef;
430
431 rc = do_ioctl_ptr(GPIO_V2_GET_LINEINFO_IOCTL, p_lineinfo);
432 printf("ioctl(-1, %s, {offset=55}",
433 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL));
434 if (rc >= 0)
435 printf(" => {name=\"line name\", consumer=\"line consumer\", flags="
436 str_line_flags ", num_attrs=1, attrs=[{debounce_period_us=3735928559}]}");
437 printf(") = %s\n", errstr);
438
439 /* num_attrs = 1 with non-zero padding */
440 p_lineinfo->offset = 0x38;
441 memset(p_lineinfo->attrs, 0, sizeof(p_lineinfo->attrs));
442 p_lineinfo->num_attrs = 1;
443 p_lineinfo->attrs[0].id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;
444 p_lineinfo->attrs[0].values = 0xdeadbeefba11c0da;
445 p_lineinfo->attrs[0].padding = 0xfeedface;
446
447 rc = do_ioctl_ptr(GPIO_V2_GET_LINEINFO_IOCTL, p_lineinfo);
448 printf("ioctl(-1, %s, {offset=56}",
449 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL));
450 if (rc >= 0)
451 printf(" => {name=\"line name\", consumer=\"line consumer\", flags="
452 str_line_flags ", num_attrs=1, "
453 "attrs=[{id=2, padding=0xfeedface, data=0xdeadbeefba11c0da}]}");
454 printf(") = %s\n", errstr);
455
456 /* num_attrs > GPIO_V2_LINE_NUM_ATTRS_MAX */
457 memset(p_lineinfo->attrs, 0, sizeof(p_lineinfo->attrs));
458 p_lineinfo->num_attrs = GPIO_V2_LINE_NUM_ATTRS_MAX;
459 for (int i = 0; i < GPIO_V2_LINE_NUM_ATTRS_MAX; i++) {
460 p_lineinfo->attrs[i].id = i + 1;
461 p_lineinfo->attrs[i].flags = 0xafeddeadd0d00000 + i;
462 }
463 p_lineinfo->offset = 0x39;
464 p_lineinfo->num_attrs = GPIO_V2_LINE_NUM_ATTRS_MAX + 1;
465 rc = do_ioctl_ptr(GPIO_V2_GET_LINEINFO_IOCTL, p_lineinfo);
466 printf("ioctl(-1, %s, {offset=57}",
467 XLAT_STR(GPIO_V2_GET_LINEINFO_IOCTL));
468 if (rc >= 0) {
469 printf(" => {name=\"line name\", consumer=\"line consumer\", flags="
470 str_line_flags ", num_attrs=11, attrs=[");
471 for (int i = 0; i < GPIO_V2_LINE_NUM_ATTRS_MAX; i++) {
472 print_gpio_v2_line_attr(&p_lineinfo->attrs[i]);
473 if (i != GPIO_V2_LINE_NUM_ATTRS_MAX-1)
474 printf(", ");
475 }
476 printf("]}");
477 }
478 printf(") = %s\n", errstr);
479 }
480
481 static void
482 test_print_gpio_v2_line_request(void)
483 {
484 long rc;
485
486 do_ioctl(GPIO_V2_GET_LINE_IOCTL, 0);
487 printf("ioctl(-1, %s, NULL) = %s\n",
488 XLAT_STR(GPIO_V2_GET_LINE_IOCTL), errstr);
489
490 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpio_v2_line_request, p_line_request);
491
492 p_line_request->offsets[0] = 0x12;
493 p_line_request->offsets[1] = 0x23;
494 p_line_request->offsets[2] = 0x34;
495 p_line_request->offsets[3] = 0x45;
496 strcpy(p_line_request->consumer, "line consumer");
497 memset(&p_line_request->config, 0, sizeof(p_line_request->config));
498 p_line_request->num_lines = 4;
499 p_line_request->event_buffer_size = 0;
500 memset(p_line_request->padding, 0, sizeof(p_line_request->padding));
501 p_line_request->fd = 0x64;
502
503 do_ioctl_ptr(GPIO_V2_GET_LINE_IOCTL, (char *) p_line_request + 1);
504 printf("ioctl(-1, %s, %p) = %s\n",
505 XLAT_STR(GPIO_V2_GET_LINE_IOCTL), (char *) p_line_request + 1, errstr);
506
507 rc = do_ioctl_ptr(GPIO_V2_GET_LINE_IOCTL, p_line_request);
508 printf("ioctl(-1, %s, {num_lines=4, offsets=[18, 35, 52, 69], "
509 "consumer=\"line consumer\", config={flags=0, num_attrs=0}}",
510 XLAT_STR(GPIO_V2_GET_LINE_IOCTL));
511 if (rc >= 0)
512 printf(" => {fd=100}");
513 printf(") = %s\n", errstr);
514
515 /* with event_buffer_size */
516 p_line_request->event_buffer_size = 0xdeafdace;
517 rc = do_ioctl_ptr(GPIO_V2_GET_LINE_IOCTL, p_line_request);
518 printf("ioctl(-1, %s, {num_lines=4, offsets=[18, 35, 52, 69], "
519 "consumer=\"line consumer\", config={flags=0, num_attrs=0}, "
520 "event_buffer_size=3736066766}",
521 XLAT_STR(GPIO_V2_GET_LINE_IOCTL));
522 if (rc >= 0)
523 printf(" => {fd=100}");
524 printf(") = %s\n", errstr);
525 p_line_request->event_buffer_size = 0;
526
527 /* with non-zero-padding */
528 p_line_request->padding[1] = 0xfeedface;
529 rc = do_ioctl_ptr(GPIO_V2_GET_LINE_IOCTL, p_line_request);
530 printf("ioctl(-1, %s, {num_lines=4, offsets=[18, 35, 52, 69], "
531 "consumer=\"line consumer\", config={flags=0, num_attrs=0}, "
532 "padding=[0, 0xfeedface, 0, 0, 0]}",
533 XLAT_STR(GPIO_V2_GET_LINE_IOCTL));
534 if (rc >= 0)
535 printf(" => {fd=100}");
536 printf(") = %s\n", errstr);
537 p_line_request->padding[1] = 0;
538
539 /* num_lines > GPIO_V2_LINES_MAX */
540 p_line_request->num_lines = GPIO_V2_LINES_MAX + 1;
541 for (int i = 0; i < GPIO_V2_LINES_MAX; i++)
542 p_line_request->offsets[i] = i + 1;
543 rc = do_ioctl_ptr(GPIO_V2_GET_LINE_IOCTL, p_line_request);
544 printf("ioctl(-1, %s, {num_lines=65, offsets=" str_line_seq
545 ", consumer=\"line consumer\", config={flags=0, num_attrs=0}}",
546 XLAT_STR(GPIO_V2_GET_LINE_IOCTL));
547 if (rc >= 0)
548 printf(" => {fd=100}");
549 printf(") = %s\n", errstr);
550 }
551
552 static void
553 test_print_gpio_v2_line_get_values(void)
554 {
555 long rc;
556
557 do_ioctl(GPIO_V2_LINE_GET_VALUES_IOCTL, 0);
558 printf("ioctl(-1, %s, NULL) = %s\n",
559 XLAT_STR(GPIO_V2_LINE_GET_VALUES_IOCTL), errstr);
560
561 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpio_v2_line_values, p_line_values);
562
563 p_line_values->bits = 0xcacafeedfacecafe;
564 p_line_values->mask = 0xfadebeaddeedbabe;
565
566 do_ioctl_ptr(GPIO_V2_LINE_GET_VALUES_IOCTL, (char *) p_line_values + 1);
567 printf("ioctl(-1, %s, %p) = %s\n",
568 XLAT_STR(GPIO_V2_LINE_GET_VALUES_IOCTL), (char *) p_line_values + 1, errstr);
569
570 rc = do_ioctl_ptr(GPIO_V2_LINE_GET_VALUES_IOCTL, p_line_values);
571 printf("ioctl(-1, %s, {mask=0xfadebeaddeedbabe}",
572 XLAT_STR(GPIO_V2_LINE_GET_VALUES_IOCTL));
573 if (rc >= 0)
574 printf(" => {bits=0xcacafeedfacecafe}");
575 printf(") = %s\n", errstr);
576 }
577
578 static void
579 test_print_gpio_v2_line_set_values(void)
580 {
581 do_ioctl(GPIO_V2_LINE_SET_VALUES_IOCTL, 0);
582 printf("ioctl(-1, %s, NULL) = %s\n",
583 XLAT_STR(GPIO_V2_LINE_SET_VALUES_IOCTL), errstr);
584
585 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpio_v2_line_values, p_line_values);
586
587 p_line_values->bits = 0xcacafeedfacecafe;
588 p_line_values->mask = 0xfadebeaddeedbabe;
589
590 do_ioctl_ptr(GPIO_V2_LINE_SET_VALUES_IOCTL, (char *) p_line_values + 1);
591 printf("ioctl(-1, %s, %p) = %s\n",
592 XLAT_STR(GPIO_V2_LINE_SET_VALUES_IOCTL), (char *) p_line_values + 1, errstr);
593
594 do_ioctl_ptr(GPIO_V2_LINE_SET_VALUES_IOCTL, p_line_values);
595 printf("ioctl(-1, %s, {bits=0xcacafeedfacecafe, mask=0xfadebeaddeedbabe}) = %s\n",
596 XLAT_STR(GPIO_V2_LINE_SET_VALUES_IOCTL),
597 errstr);
598 }
599
600 static void
601 test_print_gpio_v2_line_set_config(void)
602 {
603 do_ioctl(GPIO_V2_LINE_SET_CONFIG_IOCTL, 0);
604 printf("ioctl(-1, %s, NULL) = %s\n",
605 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL), errstr);
606
607 TAIL_ALLOC_OBJECT_CONST_PTR(struct gpio_v2_line_config, p_line_config);
608
609 p_line_config->flags = GPIO_V2_LINE_FLAG_ACTIVE_LOW|GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
610 p_line_config->num_attrs = 0;
611 memset(p_line_config->attrs, 0, sizeof(p_line_config->attrs));
612 memset(p_line_config->padding, 0, sizeof(p_line_config->padding));
613
614 do_ioctl_ptr(GPIO_V2_LINE_SET_CONFIG_IOCTL, (char *) p_line_config + 1);
615 printf("ioctl(-1, %s, %p) = %s\n",
616 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL), (char *) p_line_config + 1, errstr);
617
618 do_ioctl_ptr(GPIO_V2_LINE_SET_CONFIG_IOCTL, p_line_config);
619 printf("ioctl(-1, %s, {flags=" str_line_flags ", num_attrs=0}) = %s\n",
620 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL), errstr);
621
622 /* unknown flag */
623 p_line_config->flags = UNK_GPIO_FLAG;
624 do_ioctl_ptr(GPIO_V2_LINE_SET_CONFIG_IOCTL, p_line_config);
625 printf("ioctl(-1, %s, {flags=" str_line_unk_flag
626 ", num_attrs=0}) = %s\n",
627 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL), errstr);
628 p_line_config->flags = GPIO_V2_LINE_FLAG_ACTIVE_LOW|GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
629
630 /* with non-zero-padding */
631 p_line_config->padding[1] = 0xfeedface;
632 do_ioctl_ptr(GPIO_V2_LINE_SET_CONFIG_IOCTL, p_line_config);
633 printf("ioctl(-1, %s, {flags=" str_line_flags
634 ", num_attrs=0, padding=[0, 0xfeedface, 0, 0, 0]}) = %s\n",
635 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL), errstr);
636 p_line_config->padding[1] = 0;
637
638 /* num_attrs > GPIO_V2_LINE_NUM_ATTRS_MAX */
639 for (int i = 0; i < GPIO_V2_LINE_NUM_ATTRS_MAX; i++) {
640 p_line_config->attrs[i].mask = 2 * i + 1;
641 p_line_config->attrs[i].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS;
642 p_line_config->attrs[i].attr.flags =
643 GPIO_V2_LINE_FLAG_ACTIVE_LOW|GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
644 }
645 p_line_config->num_attrs = GPIO_V2_LINE_NUM_ATTRS_MAX + 1;
646 do_ioctl_ptr(GPIO_V2_LINE_SET_CONFIG_IOCTL, p_line_config);
647 printf("ioctl(-1, %s, {flags=" str_line_flags ", num_attrs=11, attrs=[",
648 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL));
649 for (int i = 0; i < GPIO_V2_LINE_NUM_ATTRS_MAX - 1; i++)
650 printf("{flags=" str_line_flags ", mask=0x%x}, ", 2 * i + 1);
651 printf("{flags=" str_line_flags ", mask=0x13}]}) = %s\n", errstr);
652
653 /* num_attrs = 1 */
654 p_line_config->num_attrs = 1;
655 do_ioctl_ptr(GPIO_V2_LINE_SET_CONFIG_IOCTL, p_line_config);
656 printf("ioctl(-1, %s, {flags=" str_line_flags ", num_attrs=1, attrs=[{flags="
657 str_line_flags ", mask=0x1}]}) = %s\n",
658 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL), errstr);
659
660 /* num_attrs = 1 with non-zero padding*/
661 p_line_config->attrs[0].attr.padding = 0xfeedface;
662 p_line_config->attrs[0].attr.values = 0xdeadbeefba11c0da;
663 do_ioctl_ptr(GPIO_V2_LINE_SET_CONFIG_IOCTL, p_line_config);
664 printf("ioctl(-1, %s, {flags=" str_line_flags ", num_attrs=1, attrs=["
665 "{attr={id=%u, padding=0xfeedface, data=0xdeadbeefba11c0da}, "
666 "mask=0x1}]}) = %s\n",
667 XLAT_STR(GPIO_V2_LINE_SET_CONFIG_IOCTL),
668 GPIO_V2_LINE_ATTR_ID_FLAGS, errstr);
669 }
670
671 int
672 main(int argc, char *argv[])
673 {
674 unsigned long unknown_gpio_cmd =
675 _IOC(_IOC_READ|_IOC_WRITE, 0xb4, 0x5e, 0xfed) |
676 (unsigned long) 0xfacefeed00000000ULL;
677 unsigned long cmd_arg = (unsigned long) 0xdeadbeefbadc0dedULL;
678 #ifdef INJECT_RETVAL
679 unsigned long num_skip;
680 bool locked = false;
681
682 if (argc < 2)
683 error_msg_and_fail("Usage: %s NUM_SKIP", argv[0]);
684
685 num_skip = strtoul(argv[1], NULL, 0);
686
687 for (size_t i = 0; i < num_skip; i++) {
688 long ret = ioctl(-1, GPIO_GET_CHIPINFO_IOCTL, 0);
689
690 printf("ioctl(-1, %s, NULL) = %s%s\n",
691 XLAT_STR(GPIO_GET_CHIPINFO_IOCTL), sprintrc(ret),
692 ret == INJECT_RETVAL ? " (INJECTED)" : "");
693
694 if (ret != INJECT_RETVAL)
695 continue;
696
697 locked = true;
698 break;
699 }
700
701 if (!locked)
702 error_msg_and_fail("Hasn't locked on ioctl(-1"
703 ", GPIO_GET_CHIPINFO_IOCTL, NULL) returning %d",
704 INJECT_RETVAL);
705 #endif
706 /* unknown GPIO command */
707 do_ioctl(unknown_gpio_cmd, cmd_arg);
708 printf("ioctl(-1, " XLAT_FMT ", %#lx) = %s\n",
709 XLAT_SEL((unsigned int) unknown_gpio_cmd,
710 "_IOC(_IOC_READ|_IOC_WRITE, 0xb4, 0x5e, 0xfed)"),
711 cmd_arg, errstr);
712
713 /* GPIO v1 ioctls */
714 test_print_gpiochip_info();
715 test_print_gpioline_info();
716 test_print_gpioline_info_unwatch();
717 test_print_gpiohandle_request();
718 test_print_gpioevent_request();
719 test_print_gpiohandle_get_values();
720 test_print_gpiohandle_set_values();
721 test_print_gpiohandle_set_config();
722
723 /* GPIO v2 ioctls */
724 test_print_gpio_v2_line_info();
725 test_print_gpio_v2_line_request();
726 test_print_gpio_v2_line_get_values();
727 test_print_gpio_v2_line_set_values();
728 test_print_gpio_v2_line_set_config();
729
730 puts("+++ exited with 0 +++");
731 return 0;
732 }