[PATCH 3/4] Add GPIO uAPI v2 ioctl decoding

Kent Gibson warthog618 at gmail.com
Tue Dec 22 22:07:47 UTC 2020


Add decoding of GPIO uAPI v2 ioctls added in Linux v5.10.

Signed-off-by: Kent Gibson <warthog618 at gmail.com>
---
 gpio_ioctl.c                  | 284 ++++++++++++++++++++++++++++++++++
 xlat/gpio_v2_line_attr_ids.in |   5 +
 xlat/gpio_v2_line_flags.in    |  13 ++
 3 files changed, 302 insertions(+)
 create mode 100644 xlat/gpio_v2_line_attr_ids.in
 create mode 100644 xlat/gpio_v2_line_flags.in

diff --git a/gpio_ioctl.c b/gpio_ioctl.c
index 228b4cf4..2dbc898d 100644
--- a/gpio_ioctl.c
+++ b/gpio_ioctl.c
@@ -35,6 +35,67 @@ struct gpiohandle_config {
 #define GPIO_GET_LINEINFO_UNWATCH_IOCTL _IOWR(0xB4, 0x0C, __u32)
 #endif
 
+#ifndef GPIO_V2_GET_LINEINFO_IOCTL
+/* added in Linux v5.10 */
+#define GPIO_V2_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x05, struct gpio_v2_line_info)
+#define GPIO_V2_GET_LINEINFO_WATCH_IOCTL _IOWR(0xB4, 0x06, struct gpio_v2_line_info)
+#define GPIO_V2_GET_LINE_IOCTL _IOWR(0xB4, 0x07, struct gpio_v2_line_request)
+#define GPIO_V2_LINE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0D, struct gpio_v2_line_config)
+#define GPIO_V2_LINE_GET_VALUES_IOCTL _IOWR(0xB4, 0x0E, struct gpio_v2_line_values)
+#define GPIO_V2_LINE_SET_VALUES_IOCTL _IOWR(0xB4, 0x0F, struct gpio_v2_line_values)
+
+#define GPIO_MAX_NAME_SIZE 32
+#define GPIO_V2_LINES_MAX 64
+#define GPIO_V2_LINE_NUM_ATTRS_MAX 10
+
+struct gpio_v2_line_values {
+	__aligned_u64 bits;
+	__aligned_u64 mask;
+};
+
+struct gpio_v2_line_attribute {
+	__u32 id;
+	__u32 padding;
+	union {
+		__aligned_u64 flags;
+		__aligned_u64 values;
+		__u32 debounce_period_us;
+	};
+};
+
+struct gpio_v2_line_config_attribute {
+	struct gpio_v2_line_attribute attr;
+	__aligned_u64 mask;
+};
+
+struct gpio_v2_line_config {
+	__aligned_u64 flags;
+	__u32 num_attrs;
+	__u32 padding[5];
+	struct gpio_v2_line_config_attribute attrs[GPIO_V2_LINE_NUM_ATTRS_MAX];
+};
+
+struct gpio_v2_line_request {
+	__u32 offsets[GPIO_V2_LINES_MAX];
+	char consumer[GPIO_MAX_NAME_SIZE];
+	struct gpio_v2_line_config config;
+	__u32 num_lines;
+	__u32 event_buffer_size;
+	__u32 padding[5];
+	__s32 fd;
+};
+struct gpio_v2_line_info {
+	char name[GPIO_MAX_NAME_SIZE];
+	char consumer[GPIO_MAX_NAME_SIZE];
+	__u32 offset;
+	__u32 num_attrs;
+	__aligned_u64 flags;
+	struct gpio_v2_line_attribute attrs[GPIO_V2_LINE_NUM_ATTRS_MAX];
+	__u32 padding[4];
+};
+
+#endif
+
 static int
 print_gpiochip_info(struct tcb *const tcp, const kernel_ulong_t arg)
 {
@@ -222,6 +283,218 @@ print_gpiohandle_set_config(struct tcb *const tcp, const kernel_ulong_t arg)
 	return RVAL_IOCTL_DECODED;
 }
 
+#include "xlat/gpio_v2_line_flags.h"
+#include "xlat/gpio_v2_line_attr_ids.h"
+
+static void
+print_gpio_v2_line_attribute(struct tcb *const tcp,
+			     struct gpio_v2_line_attribute *attr)
+{
+	switch (attr->id) {
+	case GPIO_V2_LINE_ATTR_ID_FLAGS:
+		PRINT_FIELD_FLAGS("", *attr, flags, gpio_v2_line_flags,
+				  "GPIO_V2_LINE_FLAG_???");
+		break;
+	case GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES:
+		PRINT_FIELD_X("", *attr, values);
+		break;
+	case GPIO_V2_LINE_ATTR_ID_DEBOUNCE:
+		PRINT_FIELD_U("", *attr, debounce_period_us);
+		break;
+	default:
+		tprintf("(id=%u)=%#" PRI__x64, attr->id, attr->values);
+		break;
+	}
+}
+
+static void
+print_gpio_v2_line_config_attribute(struct tcb *const tcp,
+				    struct gpio_v2_line_config_attribute *attr)
+{
+	tprints("{");
+	print_gpio_v2_line_attribute(tcp, &attr->attr);
+	PRINT_FIELD_X(", ", *attr, mask);
+	tprints("}");
+}
+
+static bool
+print_gpio_v2_line_attr_array_member(struct tcb *tcp, void *elem_buf,
+				     size_t elem_size, void *data)
+{
+	struct gpio_v2_line_attribute *la;
+
+	la = (struct gpio_v2_line_attribute *)elem_buf;
+	if (la->padding) {
+		PRINT_FIELD_X("{", *la, padding);
+		tprints(", ");
+	}
+	print_gpio_v2_line_attribute(tcp, la);
+	if (la->padding)
+		tprints("}");
+
+	return true;
+}
+
+
+static bool
+print_gpio_v2_line_config_attr_array_member(struct tcb *tcp, void *elem_buf,
+					    size_t elem_size, void *data)
+{
+	print_gpio_v2_line_config_attribute(tcp,
+		(struct gpio_v2_line_config_attribute *)elem_buf);
+
+	return true;
+}
+
+static void
+print_gpio_v2_line_config(struct tcb *const tcp, struct gpio_v2_line_config *lc)
+{
+	__u32 num_attrs = lc->num_attrs;
+
+	PRINT_FIELD_FLAGS("{", *lc, flags, gpio_v2_line_flags,
+			  "GPIO_V2_LINE_FLAG_???");
+	PRINT_FIELD_U(", ", *lc, num_attrs);
+	if (!IS_ARRAY_ZERO(lc->padding))
+		PRINT_FIELD_X_ARRAY(", ", *lc, padding);
+	if (num_attrs) {
+		if (num_attrs > GPIO_V2_LINE_NUM_ATTRS_MAX)
+			num_attrs = GPIO_V2_LINE_NUM_ATTRS_MAX;
+		tprints(", attrs=");
+		print_local_array_ex(tcp, lc->attrs, num_attrs,
+			sizeof(lc->attrs[0]),
+			print_gpio_v2_line_config_attr_array_member,
+			NULL, 0, NULL, NULL);
+	}
+	tprints("}");
+}
+
+static void
+print_gpio_v2_line_values(struct tcb *const tcp, struct gpio_v2_line_values *vals)
+{
+	PRINT_FIELD_X("{", *vals, bits);
+	PRINT_FIELD_X(", ", *vals, mask);
+	tprints("}");
+}
+
+static int
+print_gpio_v2_line_info(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpio_v2_line_info li;
+
+	if (entering(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &li))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_U("{", li, offset);
+	if (!tcp->u_rval) {
+		PRINT_FIELD_CSTRING(", ", li, name);
+		PRINT_FIELD_CSTRING(", ", li, consumer);
+		PRINT_FIELD_FLAGS(", ", li, flags, gpio_v2_line_flags,
+				  "GPIO_V2_LINE_FLAG_???");
+		PRINT_FIELD_U(", ", li, num_attrs);
+		if (li.num_attrs) {
+			if (li.num_attrs > GPIO_V2_LINE_NUM_ATTRS_MAX)
+				li.num_attrs = GPIO_V2_LINE_NUM_ATTRS_MAX;
+			tprints(", attrs=");
+			print_local_array_ex(tcp, li.attrs, li.num_attrs,
+				sizeof(li.attrs[0]),
+				print_gpio_v2_line_attr_array_member,
+				NULL, 0, NULL, NULL);
+		}
+	}
+	if (!IS_ARRAY_ZERO(li.padding))
+		PRINT_FIELD_X_ARRAY(", ", li, padding);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static int
+print_gpio_v2_line_request(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpio_v2_line_request lr;
+
+	if (entering(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &lr))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_U("{", lr, num_lines);
+	if (lr.num_lines > GPIO_V2_LINES_MAX)
+		lr.num_lines = GPIO_V2_LINES_MAX;
+	tprints(", offsets=");
+	print_local_array_ex(tcp, lr.offsets, lr.num_lines,
+			sizeof(lr.offsets[0]), print_uint32_array_member,
+			NULL, 0, NULL, NULL);
+	tprints(", config=");
+	print_gpio_v2_line_config(tcp, &lr.config);
+	PRINT_FIELD_CSTRING(", ", lr, consumer);
+	PRINT_FIELD_U(", ", lr, event_buffer_size);
+	if (!IS_ARRAY_ZERO(lr.padding))
+		PRINT_FIELD_X_ARRAY(", ", lr, padding);
+	if (!tcp->u_rval)
+		PRINT_FIELD_FD(", ", lr, fd, tcp);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static int
+print_gpio_v2_line_get_values(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpio_v2_line_values vals;
+
+	if (entering(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &vals))
+		return RVAL_IOCTL_DECODED;
+
+	print_gpio_v2_line_values(tcp, &vals);
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static int
+print_gpio_v2_line_set_values(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpio_v2_line_values vals;
+
+	if (exiting(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &vals))
+		return RVAL_IOCTL_DECODED;
+
+	print_gpio_v2_line_values(tcp, &vals);
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static int
+print_gpio_v2_line_set_config(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpio_v2_line_config lc;
+
+	if (exiting(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &lc))
+		return RVAL_IOCTL_DECODED;
+
+	print_gpio_v2_line_config(tcp, &lc);
+
+	return RVAL_IOCTL_DECODED;
+}
+
 MPERS_PRINTER_DECL(int, gpio_ioctl,
 		   struct tcb *const tcp, const unsigned int code,
 		   const kernel_ulong_t arg)
@@ -231,6 +504,17 @@ MPERS_PRINTER_DECL(int, gpio_ioctl,
 		return print_gpiochip_info(tcp, arg);
 	case GPIO_GET_LINEINFO_UNWATCH_IOCTL:
 		return print_gpioline_info_unwatch(tcp, arg);
+	case GPIO_V2_GET_LINEINFO_IOCTL:
+	case GPIO_V2_GET_LINEINFO_WATCH_IOCTL:
+		return print_gpio_v2_line_info(tcp, arg);
+	case GPIO_V2_GET_LINE_IOCTL:
+		return print_gpio_v2_line_request(tcp, arg);
+	case GPIO_V2_LINE_SET_CONFIG_IOCTL:
+		return print_gpio_v2_line_set_config(tcp, arg);
+	case GPIO_V2_LINE_GET_VALUES_IOCTL:
+		return print_gpio_v2_line_get_values(tcp, arg);
+	case GPIO_V2_LINE_SET_VALUES_IOCTL:
+		return print_gpio_v2_line_set_values(tcp, arg);
 	case GPIO_GET_LINEINFO_IOCTL:
 	case GPIO_GET_LINEINFO_WATCH_IOCTL:
 		return print_gpioline_info(tcp, arg);
diff --git a/xlat/gpio_v2_line_attr_ids.in b/xlat/gpio_v2_line_attr_ids.in
new file mode 100644
index 00000000..89f8a02b
--- /dev/null
+++ b/xlat/gpio_v2_line_attr_ids.in
@@ -0,0 +1,5 @@
+#enum
+#include <linux/gpio.h>
+GPIO_V2_LINE_ATTR_ID_FLAGS              0x00000001
+GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES      0x00000002
+GPIO_V2_LINE_ATTR_ID_DEBOUNCE           0x00000003
diff --git a/xlat/gpio_v2_line_flags.in b/xlat/gpio_v2_line_flags.in
new file mode 100644
index 00000000..1314c2d0
--- /dev/null
+++ b/xlat/gpio_v2_line_flags.in
@@ -0,0 +1,13 @@
+#enum
+#include <linux/gpio.h>
+GPIO_V2_LINE_FLAG_USED                  0x00000001
+GPIO_V2_LINE_FLAG_ACTIVE_LOW	        0x00000002
+GPIO_V2_LINE_FLAG_INPUT                 0x00000004
+GPIO_V2_LINE_FLAG_OUTPUT	        0x00000008
+GPIO_V2_LINE_FLAG_EDGE_RISING	        0x00000010
+GPIO_V2_LINE_FLAG_EDGE_FALLING	        0x00000020
+GPIO_V2_LINE_FLAG_OPEN_DRAIN	        0x00000040
+GPIO_V2_LINE_FLAG_OPEN_SOURCE	        0x00000080
+GPIO_V2_LINE_FLAG_BIAS_PULL_UP	        0x00000100
+GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN	0x00000200
+GPIO_V2_LINE_FLAG_BIAS_DISABLED	        0x00000400
-- 
2.29.2



More information about the Strace-devel mailing list