[PATCH v4 4/6] Add GPIO v2 ioctl decoding
Kent Gibson
warthog618 at gmail.com
Sat Jan 23 01:56:43 UTC 2021
Add decoding of GPIO uAPI v2 ioctls added in Linux v5.10.
Signed-off-by: Kent Gibson <warthog618 at gmail.com>
---
gpio_ioctl.c | 226 ++++++++++++++++++++++++++++++++++
types/gpio.h | 73 +++++++++++
xlat/gpio_v2_line_attr_ids.in | 5 +
xlat/gpio_v2_line_flags.in | 13 ++
4 files changed, 317 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 1098699b..b7cdcd51 100644
--- a/gpio_ioctl.c
+++ b/gpio_ioctl.c
@@ -197,6 +197,221 @@ 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_raw(const struct_gpio_v2_line_attribute *attr,
+ bool as_field)
+{
+ if (as_field)
+ tprints("attr={");
+ PRINT_FIELD_U("", *attr, id);
+ if (attr->padding)
+ PRINT_FIELD_X(", ", *attr, padding);
+ tprintf(", data=%#" PRIx64, attr->values);
+ if (as_field)
+ tprints("}");
+}
+
+static void
+print_gpio_v2_line_attribute(const struct_gpio_v2_line_attribute *attr,
+ bool as_field)
+{
+ if (attr->padding) {
+ /* unexpected padding usage so decode fields raw */
+ print_gpio_v2_line_attribute_raw(attr, as_field);
+ return;
+ }
+ 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:
+ /* unknown id so decode fields raw */
+ print_gpio_v2_line_attribute_raw(attr, as_field);
+ break;
+ }
+}
+
+static void
+print_gpio_v2_line_config_attribute(const struct_gpio_v2_line_config_attribute *attr)
+{
+ tprints("{");
+ print_gpio_v2_line_attribute(&attr->attr, true);
+ 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)
+{
+ tprints("{");
+ print_gpio_v2_line_attribute(elem_buf, false);
+ 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(elem_buf);
+
+ return true;
+}
+
+static void
+print_gpio_v2_line_config(struct tcb *const tcp,
+ const struct_gpio_v2_line_config *lc)
+{
+ 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 (lc->num_attrs)
+ PRINT_FIELD_ARRAY_UPTO(", ", *lc, attrs, lc->num_attrs, tcp,
+ print_gpio_v2_line_config_attr_array_member);
+ 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))
+ tprints(", ");
+ else if (syserror(tcp))
+ return RVAL_IOCTL_DECODED;
+ else
+ tprints(" => ");
+
+ if (umove_or_printaddr(tcp, arg, &li))
+ return RVAL_IOCTL_DECODED;
+
+ if (entering(tcp)) {
+ PRINT_FIELD_U("{", li, offset);
+ tprints("}");
+ return 0;
+ }
+
+ /* exiting */
+ 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)
+ PRINT_FIELD_ARRAY_UPTO(", ", li, attrs, li.num_attrs, tcp,
+ print_gpio_v2_line_attr_array_member);
+ 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))
+ tprints(", ");
+ else if (syserror(tcp))
+ return RVAL_IOCTL_DECODED;
+ else
+ tprints(" => ");
+
+ if (umove_or_printaddr(tcp, arg, &lr))
+ return RVAL_IOCTL_DECODED;
+
+ if (exiting(tcp)) {
+ PRINT_FIELD_FD("{", lr, fd, tcp);
+ tprints("}");
+ return RVAL_IOCTL_DECODED;
+ }
+
+ /* entering */
+ PRINT_FIELD_U("{", lr, num_lines);
+ PRINT_FIELD_ARRAY_UPTO(", ", lr, offsets, lr.num_lines, tcp,
+ print_uint32_array_member);
+ tprints(", config=");
+ print_gpio_v2_line_config(tcp, &lr.config);
+ PRINT_FIELD_CSTRING(", ", lr, consumer);
+ if (lr.event_buffer_size)
+ PRINT_FIELD_U(", ", lr, event_buffer_size);
+ if (!IS_ARRAY_ZERO(lr.padding))
+ PRINT_FIELD_X_ARRAY(", ", lr, padding);
+ tprints("}");
+ return 0;
+}
+
+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))
+ tprints(", ");
+ else if (syserror(tcp))
+ return RVAL_IOCTL_DECODED;
+ else
+ tprints(" => ");
+
+ if (umove_or_printaddr(tcp, arg, &vals))
+ return RVAL_IOCTL_DECODED;
+
+ if (entering(tcp)) {
+ PRINT_FIELD_X("{", vals, mask);
+ tprints("}");
+ return 0;
+ }
+
+ /* exiting */
+ PRINT_FIELD_X("{", vals, bits);
+ tprints("}");
+
+ 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;
+
+ tprints(", ");
+ if (!umove_or_printaddr(tcp, arg, &vals)) {
+ PRINT_FIELD_X("{", vals, bits);
+ PRINT_FIELD_X(", ", vals, mask);
+ tprints("}");
+ }
+
+ 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;
+
+ tprints(", ");
+ if (!umove_or_printaddr(tcp, arg, &lc))
+ print_gpio_v2_line_config(tcp, &lc);
+
+ return RVAL_IOCTL_DECODED;
+}
+
int
gpio_ioctl(struct tcb *const tcp, const unsigned int code,
const kernel_ulong_t arg)
@@ -206,6 +421,17 @@ gpio_ioctl(struct tcb *const tcp, const unsigned int code,
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/types/gpio.h b/types/gpio.h
index 47fa00da..87e76c72 100644
--- a/types/gpio.h
+++ b/types/gpio.h
@@ -35,4 +35,77 @@ typedef struct {
uint32_t padding[4];
} struct_gpiohandle_config;
+# 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
+
+enum gpio_v2_line_flag {
+ GPIO_V2_LINE_FLAG_ACTIVE_LOW = (1ULL << 1),
+ GPIO_V2_LINE_FLAG_BIAS_PULL_UP = (1ULL << 8),
+};
+
+enum gpio_v2_line_attr_id {
+ GPIO_V2_LINE_ATTR_ID_FLAGS = 1,
+ GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES = 2,
+ GPIO_V2_LINE_ATTR_ID_DEBOUNCE = 3,
+};
+
+# endif /* GPIO_V2_GET_LINEINFO_IOCTL */
+
+typedef struct {
+ uint64_t bits;
+ uint64_t mask;
+} struct_gpio_v2_line_values;
+
+typedef struct {
+ uint32_t id;
+ uint32_t padding;
+ union {
+ uint64_t flags;
+ uint64_t values;
+ uint32_t debounce_period_us;
+ };
+} struct_gpio_v2_line_attribute;
+
+typedef struct {
+ struct_gpio_v2_line_attribute attr;
+ uint64_t mask;
+} struct_gpio_v2_line_config_attribute;
+
+typedef struct {
+ uint64_t flags;
+ uint32_t num_attrs;
+ uint32_t padding[5];
+ struct_gpio_v2_line_config_attribute attrs[GPIO_V2_LINE_NUM_ATTRS_MAX];
+} struct_gpio_v2_line_config;
+
+typedef struct {
+ uint32_t offsets[GPIO_V2_LINES_MAX];
+ char consumer[GPIO_MAX_NAME_SIZE];
+ struct_gpio_v2_line_config config;
+ uint32_t num_lines;
+ uint32_t event_buffer_size;
+ uint32_t padding[5];
+ int32_t fd;
+} struct_gpio_v2_line_request;
+
+typedef struct {
+ char name[GPIO_MAX_NAME_SIZE];
+ char consumer[GPIO_MAX_NAME_SIZE];
+ uint32_t offset;
+ uint32_t num_attrs;
+ uint64_t flags;
+ struct_gpio_v2_line_attribute attrs[GPIO_V2_LINE_NUM_ATTRS_MAX];
+ uint32_t padding[4];
+} struct_gpio_v2_line_info;
+
#endif /* STRACE_TYPES_GPIO_H */
diff --git a/xlat/gpio_v2_line_attr_ids.in b/xlat/gpio_v2_line_attr_ids.in
new file mode 100644
index 00000000..5217e400
--- /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..04ffa9e4
--- /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.30.0
More information about the Strace-devel
mailing list