(root)/
strace-6.5/
tests/
ioctl_gpio.c
       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  }