[PATCH 1/1] i2c: add I2C ioctl decoding

Tobias Peter git at tobyp.net
Tue Apr 6 16:47:01 UTC 2021


Add decoding of I2C (and SMBUS) ioctls. These have been part of the uapi
since v3.7 and existed since v.2.3.34 (partial) and v2.3.35 (all
ioctls).

Signed-off-by: Tobias Peter <git at tobyp.net>
---
 bundled/linux/include/uapi/linux/i2c-dev.h |  59 +++++
 bundled/linux/include/uapi/linux/i2c.h     | 164 ++++++++++++++
 maint/ioctls_gen.sh                        |   1 +
 src/Makefile.am                            |   1 +
 src/defs.h                                 |   1 +
 src/i2c_ioctl.c                            | 239 +++++++++++++++++++++
 src/ioctl.c                                |   2 +
 src/linux/32/ioctls_inc_align16.h          |   9 +
 src/linux/32/ioctls_inc_align32.h          |   9 +
 src/linux/32/ioctls_inc_align64.h          |   9 +
 src/linux/64/ioctls_inc.h                  |   9 +
 src/xlat/i2c_funcs.in                      |  21 ++
 src/xlat/i2c_msg_flags.in                  |  10 +
 src/xlat/i2c_smbus_read_write.in           |   3 +
 src/xlat/i2c_smbus_size.in                 |  10 +
 15 files changed, 547 insertions(+)
 create mode 100644 bundled/linux/include/uapi/linux/i2c-dev.h
 create mode 100644 bundled/linux/include/uapi/linux/i2c.h
 create mode 100644 src/i2c_ioctl.c
 create mode 100644 src/xlat/i2c_funcs.in
 create mode 100644 src/xlat/i2c_msg_flags.in
 create mode 100644 src/xlat/i2c_smbus_read_write.in
 create mode 100644 src/xlat/i2c_smbus_size.in

diff --git a/bundled/linux/include/uapi/linux/i2c-dev.h b/bundled/linux/include/uapi/linux/i2c-dev.h
new file mode 100644
index 00000000..1f1f16ea
--- /dev/null
+++ b/bundled/linux/include/uapi/linux/i2c-dev.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * i2c-dev.h - I2C bus char device interface
+ *
+ * Copyright (C) 1995-97 Simon G. Vogl
+ * Copyright (C) 1998-99 Frodo Looijaard <frodol at dds.nl>
+ */
+
+#ifndef _UAPI_LINUX_I2C_DEV_H
+#define _UAPI_LINUX_I2C_DEV_H
+
+#include <linux/types.h>
+
+/* /dev/i2c-X ioctl commands.  The ioctl's parameter is always an
+ * unsigned long, except for:
+ *	- I2C_FUNCS, takes pointer to an unsigned long
+ *	- I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data
+ *	- I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data
+ */
+#define I2C_RETRIES	0x0701	/* number of times a device address should
+				   be polled when not acknowledging */
+#define I2C_TIMEOUT	0x0702	/* set timeout in units of 10 ms */
+
+/* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses
+ * are NOT supported! (due to code brokenness)
+ */
+#define I2C_SLAVE	0x0703	/* Use this slave address */
+#define I2C_SLAVE_FORCE	0x0706	/* Use this slave address, even if it
+				   is already in use by a driver! */
+#define I2C_TENBIT	0x0704	/* 0 for 7 bit addrs, != 0 for 10 bit */
+
+#define I2C_FUNCS	0x0705	/* Get the adapter functionality mask */
+
+#define I2C_RDWR	0x0707	/* Combined R/W transfer (one STOP only) */
+
+#define I2C_PEC		0x0708	/* != 0 to use PEC with SMBus */
+#define I2C_SMBUS	0x0720	/* SMBus transfer */
+
+
+/* This is the structure as used in the I2C_SMBUS ioctl call */
+struct i2c_smbus_ioctl_data {
+	__u8 read_write;
+	__u8 command;
+	__u32 size;
+	union i2c_smbus_data *data;
+};
+
+/* This is the structure as used in the I2C_RDWR ioctl call */
+struct i2c_rdwr_ioctl_data {
+	struct i2c_msg *msgs;	/* pointers to i2c_msgs */
+	__u32 nmsgs;			/* number of i2c_msgs */
+};
+
+#define  I2C_RDWR_IOCTL_MAX_MSGS	42
+/* Originally defined with a typo, keep it for compatibility */
+#define  I2C_RDRW_IOCTL_MAX_MSGS	I2C_RDWR_IOCTL_MAX_MSGS
+
+
+#endif /* _UAPI_LINUX_I2C_DEV_H */
diff --git a/bundled/linux/include/uapi/linux/i2c.h b/bundled/linux/include/uapi/linux/i2c.h
new file mode 100644
index 00000000..92326ebd
--- /dev/null
+++ b/bundled/linux/include/uapi/linux/i2c.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * i2c.h - definitions for the I2C bus interface
+ *
+ * Copyright (C) 1995-2000 Simon G. Vogl
+ * With some changes from Kyösti Mälkki <kmalkki at cc.hut.fi> and
+ * Frodo Looijaard <frodol at dds.nl>
+ */
+
+#ifndef _UAPI_LINUX_I2C_H
+#define _UAPI_LINUX_I2C_H
+
+#include <linux/types.h>
+
+/**
+ * struct i2c_msg - an I2C transaction segment beginning with START
+ *
+ * @addr: Slave address, either 7 or 10 bits. When this is a 10 bit address,
+ *   %I2C_M_TEN must be set in @flags and the adapter must support
+ *   %I2C_FUNC_10BIT_ADDR.
+ *
+ * @flags:
+ *   Supported by all adapters:
+ *   %I2C_M_RD: read data (from slave to master). Guaranteed to be 0x0001!
+ *
+ *   Optional:
+ *   %I2C_M_DMA_SAFE: the buffer of this message is DMA safe. Makes only sense
+ *     in kernelspace, because userspace buffers are copied anyway
+ *
+ *   Only if I2C_FUNC_10BIT_ADDR is set:
+ *   %I2C_M_TEN: this is a 10 bit chip address
+ *
+ *   Only if I2C_FUNC_SMBUS_READ_BLOCK_DATA is set:
+ *   %I2C_M_RECV_LEN: message length will be first received byte
+ *
+ *   Only if I2C_FUNC_NOSTART is set:
+ *   %I2C_M_NOSTART: skip repeated start sequence
+
+ *   Only if I2C_FUNC_PROTOCOL_MANGLING is set:
+ *   %I2C_M_NO_RD_ACK: in a read message, master ACK/NACK bit is skipped
+ *   %I2C_M_IGNORE_NAK: treat NACK from client as ACK
+ *   %I2C_M_REV_DIR_ADDR: toggles the Rd/Wr bit
+ *   %I2C_M_STOP: force a STOP condition after the message
+ *
+ * @len: Number of data bytes in @buf being read from or written to the I2C
+ *   slave address. For read transactions where %I2C_M_RECV_LEN is set, the
+ *   caller guarantees that this buffer can hold up to %I2C_SMBUS_BLOCK_MAX
+ *   bytes in addition to the initial length byte sent by the slave (plus,
+ *   if used, the SMBus PEC); and this value will be incremented by the number
+ *   of block data bytes received.
+ *
+ * @buf: The buffer into which data is read, or from which it's written.
+ *
+ * An i2c_msg is the low level representation of one segment of an I2C
+ * transaction.  It is visible to drivers in the @i2c_transfer() procedure,
+ * to userspace from i2c-dev, and to I2C adapter drivers through the
+ * @i2c_adapter. at master_xfer() method.
+ *
+ * Except when I2C "protocol mangling" is used, all I2C adapters implement
+ * the standard rules for I2C transactions.  Each transaction begins with a
+ * START.  That is followed by the slave address, and a bit encoding read
+ * versus write.  Then follow all the data bytes, possibly including a byte
+ * with SMBus PEC.  The transfer terminates with a NAK, or when all those
+ * bytes have been transferred and ACKed.  If this is the last message in a
+ * group, it is followed by a STOP.  Otherwise it is followed by the next
+ * @i2c_msg transaction segment, beginning with a (repeated) START.
+ *
+ * Alternatively, when the adapter supports %I2C_FUNC_PROTOCOL_MANGLING then
+ * passing certain @flags may have changed those standard protocol behaviors.
+ * Those flags are only for use with broken/nonconforming slaves, and with
+ * adapters which are known to support the specific mangling options they need.
+ */
+struct i2c_msg {
+	__u16 addr;
+	__u16 flags;
+#define I2C_M_RD		0x0001	/* guaranteed to be 0x0001! */
+#define I2C_M_TEN		0x0010	/* use only if I2C_FUNC_10BIT_ADDR */
+#define I2C_M_DMA_SAFE		0x0200	/* use only in kernel space */
+#define I2C_M_RECV_LEN		0x0400	/* use only if I2C_FUNC_SMBUS_READ_BLOCK_DATA */
+#define I2C_M_NO_RD_ACK		0x0800	/* use only if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_IGNORE_NAK	0x1000	/* use only if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_REV_DIR_ADDR	0x2000	/* use only if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_NOSTART		0x4000	/* use only if I2C_FUNC_NOSTART */
+#define I2C_M_STOP		0x8000	/* use only if I2C_FUNC_PROTOCOL_MANGLING */
+	__u16 len;
+	__u8 *buf;
+};
+
+/* To determine what functionality is present */
+
+#define I2C_FUNC_I2C			0x00000001
+#define I2C_FUNC_10BIT_ADDR		0x00000002 /* required for I2C_M_TEN */
+#define I2C_FUNC_PROTOCOL_MANGLING	0x00000004 /* required for I2C_M_IGNORE_NAK etc. */
+#define I2C_FUNC_SMBUS_PEC		0x00000008
+#define I2C_FUNC_NOSTART		0x00000010 /* required for I2C_M_NOSTART */
+#define I2C_FUNC_SLAVE			0x00000020
+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL	0x00008000 /* SMBus 2.0 or later */
+#define I2C_FUNC_SMBUS_QUICK		0x00010000
+#define I2C_FUNC_SMBUS_READ_BYTE	0x00020000
+#define I2C_FUNC_SMBUS_WRITE_BYTE	0x00040000
+#define I2C_FUNC_SMBUS_READ_BYTE_DATA	0x00080000
+#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA	0x00100000
+#define I2C_FUNC_SMBUS_READ_WORD_DATA	0x00200000
+#define I2C_FUNC_SMBUS_WRITE_WORD_DATA	0x00400000
+#define I2C_FUNC_SMBUS_PROC_CALL	0x00800000
+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA	0x01000000 /* required for I2C_M_RECV_LEN */
+#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
+#define I2C_FUNC_SMBUS_READ_I2C_BLOCK	0x04000000 /* I2C-like block xfer  */
+#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK	0x08000000 /* w/ 1-byte reg. addr. */
+#define I2C_FUNC_SMBUS_HOST_NOTIFY	0x10000000 /* SMBus 2.0 or later */
+
+#define I2C_FUNC_SMBUS_BYTE		(I2C_FUNC_SMBUS_READ_BYTE | \
+					 I2C_FUNC_SMBUS_WRITE_BYTE)
+#define I2C_FUNC_SMBUS_BYTE_DATA	(I2C_FUNC_SMBUS_READ_BYTE_DATA | \
+					 I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
+#define I2C_FUNC_SMBUS_WORD_DATA	(I2C_FUNC_SMBUS_READ_WORD_DATA | \
+					 I2C_FUNC_SMBUS_WRITE_WORD_DATA)
+#define I2C_FUNC_SMBUS_BLOCK_DATA	(I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
+					 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
+#define I2C_FUNC_SMBUS_I2C_BLOCK	(I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
+					 I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
+
+#define I2C_FUNC_SMBUS_EMUL		(I2C_FUNC_SMBUS_QUICK | \
+					 I2C_FUNC_SMBUS_BYTE | \
+					 I2C_FUNC_SMBUS_BYTE_DATA | \
+					 I2C_FUNC_SMBUS_WORD_DATA | \
+					 I2C_FUNC_SMBUS_PROC_CALL | \
+					 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
+					 I2C_FUNC_SMBUS_I2C_BLOCK | \
+					 I2C_FUNC_SMBUS_PEC)
+
+/* if I2C_M_RECV_LEN is also supported */
+#define I2C_FUNC_SMBUS_EMUL_ALL		(I2C_FUNC_SMBUS_EMUL | \
+					 I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
+					 I2C_FUNC_SMBUS_BLOCK_PROC_CALL)
+
+/*
+ * Data for SMBus Messages
+ */
+#define I2C_SMBUS_BLOCK_MAX	32	/* As specified in SMBus standard */
+union i2c_smbus_data {
+	__u8 byte;
+	__u16 word;
+	__u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
+			       /* and one more for user-space compatibility */
+};
+
+/* i2c_smbus_xfer read or write markers */
+#define I2C_SMBUS_READ	1
+#define I2C_SMBUS_WRITE	0
+
+/* SMBus transaction types (size parameter in the above functions)
+   Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
+#define I2C_SMBUS_QUICK		    0
+#define I2C_SMBUS_BYTE		    1
+#define I2C_SMBUS_BYTE_DATA	    2
+#define I2C_SMBUS_WORD_DATA	    3
+#define I2C_SMBUS_PROC_CALL	    4
+#define I2C_SMBUS_BLOCK_DATA	    5
+#define I2C_SMBUS_I2C_BLOCK_BROKEN  6
+#define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
+#define I2C_SMBUS_I2C_BLOCK_DATA    8
+
+#endif /* _UAPI_LINUX_I2C_H */
diff --git a/maint/ioctls_gen.sh b/maint/ioctls_gen.sh
index fa1fd687..dba461fd 100755
--- a/maint/ioctls_gen.sh
+++ b/maint/ioctls_gen.sh
@@ -53,6 +53,7 @@ trap 'cleanup 1' HUP PIPE INT QUIT TERM
 # Fetch ioctl commands defined in hex form.
 {
 	"$mydir"/ioctls_hex.sh "$inc_dir" 03 linux/hdreg.h
+	"$mydir"/ioctls_hex.sh "$inc_dir" 07 linux/i2c-dev.h
 	"$mydir"/ioctls_hex.sh "$inc_dir" 22 scsi/sg.h
 	"$mydir"/ioctls_hex.sh "$inc_dir" 46 linux/fb.h
 	"$mydir"/ioctls_hex.sh "$inc_dir" 4B linux/kd.h
diff --git a/src/Makefile.am b/src/Makefile.am
index b5abd1c8..b2db6333 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -139,6 +139,7 @@ libstrace_a_SOURCES =	\
 	hostname.c	\
 	inotify.c	\
 	inotify_ioctl.c	\
+	i2c_ioctl.c	\
 	io.c		\
 	io_uring.c	\
 	ioctl.c		\
diff --git a/src/defs.h b/src/defs.h
index 08a29313..031af714 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -1250,6 +1250,7 @@ DECL_IOCTL(fs_0x94);
 DECL_IOCTL(fs_f);
 DECL_IOCTL(fs_x);
 DECL_IOCTL(gpio);
+DECL_IOCTL(i2c);
 DECL_IOCTL(inotify);
 DECL_IOCTL(kvm);
 DECL_IOCTL(nbd);
diff --git a/src/i2c_ioctl.c b/src/i2c_ioctl.c
new file mode 100644
index 00000000..e8cfa1d9
--- /dev/null
+++ b/src/i2c_ioctl.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2021 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "xlat/i2c_funcs.h"
+
+static int
+print_i2c_funcs(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	kernel_ulong_t funcs;
+
+	if (entering(tcp))
+		return 0;
+
+	tprint_arg_next();
+	if (umove_or_printaddr(tcp, arg, &funcs))
+		return RVAL_IOCTL_DECODED;
+
+	printflags(i2c_funcs, funcs, NULL);
+	return RVAL_IOCTL_DECODED;
+}
+
+#include "xlat/i2c_msg_flags.h"
+
+static void
+print_i2c_msg(struct tcb *const tcp, const struct i2c_msg *const sd)
+{
+	tprint_struct_begin();
+	PRINT_FIELD_X(*sd, addr);
+	tprint_struct_next();
+	PRINT_FIELD_FLAGS(*sd, flags, i2c_msg_flags, "I2C_M_???");
+	tprint_struct_next();
+	PRINT_FIELD_U(*sd, len);
+	tprint_struct_next();
+	tprints_field_name("buf");
+
+	__u8 * buf = xmalloc(sd->len);
+	if (!umoven_or_printaddr(tcp, (kernel_ulong_t)sd->buf, sd->len, buf)) {
+		print_quoted_string((const char *)buf, sd->len, 
+				    QUOTE_FORCE_HEX);
+	}
+	free(buf);
+	tprint_struct_end();
+}
+
+static int
+print_i2c_rdwr(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct i2c_rdwr_ioctl_data rwd;
+	struct i2c_msg msg;
+
+	if (entering(tcp))
+		tprint_arg_next();
+	else if (syserror(tcp))
+		return RVAL_IOCTL_DECODED;
+	else
+		tprint_value_changed();
+
+	if (umove_or_printaddr(tcp, arg, &rwd))
+		return RVAL_IOCTL_DECODED;
+
+	if (entering(tcp)) {
+		tprint_struct_begin();
+
+		PRINT_FIELD_D(rwd, nmsgs);
+		tprint_struct_next();
+
+		tprint_array_begin();
+		for (unsigned long i=0; i<rwd.nmsgs; ++i) {
+			if (i != 0) tprint_array_next();
+			if (!umove_or_printaddr(tcp,
+						(kernel_ulong_t)(rwd.msgs + i),
+						&msg)) {
+				print_i2c_msg(tcp, &msg);
+			}
+		}
+		tprint_array_end();
+
+		return 0;
+	}
+
+	/* exiting */
+	tprint_array_begin();
+	for (unsigned long i=0; i<rwd.nmsgs; ++i) {
+		if (i != 0) tprint_array_next();
+		if (!umove_or_printaddr(tcp, (kernel_ulong_t)(rwd.msgs + i),
+					&msg)) {
+			print_i2c_msg(tcp, &msg);
+		}
+	}
+	tprint_array_end();
+	tprint_struct_end();
+
+	return RVAL_IOCTL_DECODED;
+}
+
+#include "xlat/i2c_smbus_read_write.h"
+#include "xlat/i2c_smbus_size.h"
+
+#include <stdio.h>
+
+/* For QUICK actions and single-byte writes, the data field is ignored. */
+static int
+i2c_smbus_data_matters(const struct i2c_smbus_ioctl_data *const sd)
+{
+	return !(sd->size == I2C_SMBUS_QUICK ||
+	        ((sd->size == I2C_SMBUS_BYTE) &&
+	         (sd->read_write == I2C_SMBUS_WRITE)));
+}
+
+/* The kernel only changes data on procedure calls or reads. */
+static int
+i2c_smbus_data_mutation(const struct i2c_smbus_ioctl_data *const sd)
+{
+	return sd->size == I2C_SMBUS_PROC_CALL ||
+	       sd->size == I2C_SMBUS_BLOCK_PROC_CALL ||
+	       sd->read_write == I2C_SMBUS_READ;
+}
+
+static int
+print_i2c_smbus(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct i2c_smbus_ioctl_data sd;
+	union i2c_smbus_data d;
+
+	if (entering(tcp))
+		tprint_arg_next();
+	else if (syserror(tcp))
+		return RVAL_IOCTL_DECODED;
+
+	if (umove_or_printaddr(tcp, arg, &sd))
+		return RVAL_IOCTL_DECODED;
+
+	if (entering(tcp)) {
+		tprint_struct_begin();
+
+		PRINT_FIELD_XVAL(sd, read_write, i2c_smbus_read_write,
+				 "I2C_SMBUS_???");
+		tprint_struct_next();
+
+		PRINT_FIELD_X(sd, command);
+		tprint_struct_next();
+
+		PRINT_FIELD_XVAL(sd, size, i2c_smbus_size, "I2C_SMBUS_???");
+		tprint_struct_next();
+
+		if (!i2c_smbus_data_matters(&sd)) {
+			/* in this case data is not used at all, only command */
+			tprints_field_name("data");
+			tprint_more_data_follows();
+			tprint_struct_end();  // struct i2c_smbus_ioctl_data
+			return RVAL_IOCTL_DECODED;
+		}
+
+		tprints_field_name("data");
+		if (umove_or_printaddr(tcp, (kernel_ulong_t)sd.data, &d))
+			return RVAL_IOCTL_DECODED;
+		tprint_struct_begin();
+		if (sd.size == I2C_SMBUS_BYTE_DATA ||
+		    sd.size == I2C_SMBUS_BYTE)
+			PRINT_FIELD_X(d, byte);
+		else if (sd.size == I2C_SMBUS_WORD_DATA ||
+			 sd.size == I2C_SMBUS_PROC_CALL)
+			PRINT_FIELD_X(d, word);
+		else
+			PRINT_FIELD_HEX_ARRAY(d, block);
+		tprint_struct_end();
+
+		return 0;
+	}
+
+	/* exiting */
+	if (i2c_smbus_data_mutation(&sd)) {
+		tprint_value_changed();
+		if (!umove_or_printaddr(tcp, (kernel_ulong_t)sd.data, &d)) {
+			tprint_struct_begin();
+			if (sd.size == I2C_SMBUS_BYTE_DATA ||
+			    sd.size == I2C_SMBUS_BYTE)
+				PRINT_FIELD_X(d, byte);
+			else if (sd.size == I2C_SMBUS_WORD_DATA ||
+				 sd.size == I2C_SMBUS_PROC_CALL)
+				PRINT_FIELD_X(d, word);
+			else
+				PRINT_FIELD_HEX_ARRAY(d, block);
+			tprint_struct_end();
+		}
+	}
+
+	tprint_struct_end();  // struct i2c_smbus_ioctl_data
+
+	return RVAL_IOCTL_DECODED;
+}
+
+int
+i2c_ioctl(struct tcb *const tcp, const unsigned int code,
+	  const kernel_ulong_t arg)
+{
+	switch (code) {
+	/* numeric arguments; I2C_TIMEOUT is in units of 10ms */
+	case I2C_RETRIES:
+	case I2C_TIMEOUT:
+		tprint_arg_next();
+		PRINT_VAL_D((kernel_long_t)arg);
+		return RVAL_IOCTL_DECODED;
+
+	/* booleans (==0 as false, !=0 as true) */
+	case I2C_PEC:
+	case I2C_TENBIT:
+		tprint_arg_next();
+		PRINT_VAL_D((kernel_long_t)arg);
+		return RVAL_IOCTL_DECODED;
+
+	/* I2C Addresses */
+	case I2C_SLAVE:
+	case I2C_SLAVE_FORCE:
+		tprint_arg_next();
+		PRINT_VAL_X((kernel_long_t)arg);
+		return RVAL_IOCTL_DECODED;
+
+	/* Flags */
+	case I2C_FUNCS:
+		return print_i2c_funcs(tcp, arg);
+
+	/* Structures */
+	case I2C_RDWR:
+		return print_i2c_rdwr(tcp, arg);
+	case I2C_SMBUS:
+		return print_i2c_smbus(tcp, arg);
+	}
+	return RVAL_DECODED;
+}
diff --git a/src/ioctl.c b/src/ioctl.c
index 12029028..dad02bff 100644
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -346,6 +346,8 @@ ioctl_decode(struct tcb *tcp)
 	switch (_IOC_TYPE(code)) {
 	case 0x03:
 		return hdio_ioctl(tcp, code, arg);
+	case 0x07:
+		return i2c_ioctl(tcp, code, arg);
 	case 0x12:
 		return block_ioctl(tcp, code, arg);
 	case '"': /* 0x22 */
diff --git a/src/linux/32/ioctls_inc_align16.h b/src/linux/32/ioctls_inc_align16.h
index 2d028bb1..c09572bb 100644
--- a/src/linux/32/ioctls_inc_align16.h
+++ b/src/linux/32/ioctls_inc_align16.h
@@ -1218,6 +1218,15 @@
 { "linux/hsi/hsi_char.h", "HSC_SET_PM", _IOC_NONE, 0x6b11, 0x00 },
 { "linux/hsi/hsi_char.h", "HSC_SET_RX", _IOC_WRITE, 0x6b13, 0x0c },
 { "linux/hsi/hsi_char.h", "HSC_SET_TX", _IOC_WRITE, 0x6b15, 0x10 },
+{ "linux/i2c-dev.h", "I2C_FUNCS", 0, 0x0705, 0 },
+{ "linux/i2c-dev.h", "I2C_PEC", 0, 0x0708, 0 },
+{ "linux/i2c-dev.h", "I2C_RDWR", 0, 0x0707, 0 },
+{ "linux/i2c-dev.h", "I2C_RETRIES", 0, 0x0701, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE", 0, 0x0703, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE_FORCE", 0, 0x0706, 0 },
+{ "linux/i2c-dev.h", "I2C_SMBUS", 0, 0x0720, 0 },
+{ "linux/i2c-dev.h", "I2C_TENBIT", 0, 0x0704, 0 },
+{ "linux/i2c-dev.h", "I2C_TIMEOUT", 0, 0x0702, 0 },
 { "linux/i2o-dev.h", "I2OEVTGET", _IOC_READ, 0x690b, 0x68 },
 { "linux/i2o-dev.h", "I2OEVTREG", _IOC_WRITE, 0x690a, 0x0c },
 { "linux/i2o-dev.h", "I2OGETIOPS", _IOC_READ, 0x6900, 0x20 },
diff --git a/src/linux/32/ioctls_inc_align32.h b/src/linux/32/ioctls_inc_align32.h
index a6e9e351..a6e06617 100644
--- a/src/linux/32/ioctls_inc_align32.h
+++ b/src/linux/32/ioctls_inc_align32.h
@@ -1218,6 +1218,15 @@
 { "linux/hsi/hsi_char.h", "HSC_SET_PM", _IOC_NONE, 0x6b11, 0x00 },
 { "linux/hsi/hsi_char.h", "HSC_SET_RX", _IOC_WRITE, 0x6b13, 0x0c },
 { "linux/hsi/hsi_char.h", "HSC_SET_TX", _IOC_WRITE, 0x6b15, 0x10 },
+{ "linux/i2c-dev.h", "I2C_FUNCS", 0, 0x0705, 0 },
+{ "linux/i2c-dev.h", "I2C_PEC", 0, 0x0708, 0 },
+{ "linux/i2c-dev.h", "I2C_RDWR", 0, 0x0707, 0 },
+{ "linux/i2c-dev.h", "I2C_RETRIES", 0, 0x0701, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE", 0, 0x0703, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE_FORCE", 0, 0x0706, 0 },
+{ "linux/i2c-dev.h", "I2C_SMBUS", 0, 0x0720, 0 },
+{ "linux/i2c-dev.h", "I2C_TENBIT", 0, 0x0704, 0 },
+{ "linux/i2c-dev.h", "I2C_TIMEOUT", 0, 0x0702, 0 },
 { "linux/i2o-dev.h", "I2OEVTGET", _IOC_READ, 0x690b, 0x68 },
 { "linux/i2o-dev.h", "I2OEVTREG", _IOC_WRITE, 0x690a, 0x0c },
 { "linux/i2o-dev.h", "I2OGETIOPS", _IOC_READ, 0x6900, 0x20 },
diff --git a/src/linux/32/ioctls_inc_align64.h b/src/linux/32/ioctls_inc_align64.h
index 485f2d14..eb656a43 100644
--- a/src/linux/32/ioctls_inc_align64.h
+++ b/src/linux/32/ioctls_inc_align64.h
@@ -1218,6 +1218,15 @@
 { "linux/hsi/hsi_char.h", "HSC_SET_PM", _IOC_NONE, 0x6b11, 0x00 },
 { "linux/hsi/hsi_char.h", "HSC_SET_RX", _IOC_WRITE, 0x6b13, 0x0c },
 { "linux/hsi/hsi_char.h", "HSC_SET_TX", _IOC_WRITE, 0x6b15, 0x10 },
+{ "linux/i2c-dev.h", "I2C_FUNCS", 0, 0x0705, 0 },
+{ "linux/i2c-dev.h", "I2C_PEC", 0, 0x0708, 0 },
+{ "linux/i2c-dev.h", "I2C_RDWR", 0, 0x0707, 0 },
+{ "linux/i2c-dev.h", "I2C_RETRIES", 0, 0x0701, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE", 0, 0x0703, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE_FORCE", 0, 0x0706, 0 },
+{ "linux/i2c-dev.h", "I2C_SMBUS", 0, 0x0720, 0 },
+{ "linux/i2c-dev.h", "I2C_TENBIT", 0, 0x0704, 0 },
+{ "linux/i2c-dev.h", "I2C_TIMEOUT", 0, 0x0702, 0 },
 { "linux/i2o-dev.h", "I2OEVTGET", _IOC_READ, 0x690b, 0x68 },
 { "linux/i2o-dev.h", "I2OEVTREG", _IOC_WRITE, 0x690a, 0x0c },
 { "linux/i2o-dev.h", "I2OGETIOPS", _IOC_READ, 0x6900, 0x20 },
diff --git a/src/linux/64/ioctls_inc.h b/src/linux/64/ioctls_inc.h
index 902903de..e7b195c2 100644
--- a/src/linux/64/ioctls_inc.h
+++ b/src/linux/64/ioctls_inc.h
@@ -1223,6 +1223,15 @@
 { "linux/hsi/hsi_char.h", "HSC_SET_PM", _IOC_NONE, 0x6b11, 0x00 },
 { "linux/hsi/hsi_char.h", "HSC_SET_RX", _IOC_WRITE, 0x6b13, 0x0c },
 { "linux/hsi/hsi_char.h", "HSC_SET_TX", _IOC_WRITE, 0x6b15, 0x10 },
+{ "linux/i2c-dev.h", "I2C_FUNCS", 0, 0x0705, 0 },
+{ "linux/i2c-dev.h", "I2C_PEC", 0, 0x0708, 0 },
+{ "linux/i2c-dev.h", "I2C_RDWR", 0, 0x0707, 0 },
+{ "linux/i2c-dev.h", "I2C_RETRIES", 0, 0x0701, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE", 0, 0x0703, 0 },
+{ "linux/i2c-dev.h", "I2C_SLAVE_FORCE", 0, 0x0706, 0 },
+{ "linux/i2c-dev.h", "I2C_SMBUS", 0, 0x0720, 0 },
+{ "linux/i2c-dev.h", "I2C_TENBIT", 0, 0x0704, 0 },
+{ "linux/i2c-dev.h", "I2C_TIMEOUT", 0, 0x0702, 0 },
 { "linux/i2o-dev.h", "I2OEVTGET", _IOC_READ, 0x690b, 0x68 },
 { "linux/i2o-dev.h", "I2OEVTREG", _IOC_WRITE, 0x690a, 0x0c },
 { "linux/i2o-dev.h", "I2OGETIOPS", _IOC_READ, 0x6900, 0x20 },
diff --git a/src/xlat/i2c_funcs.in b/src/xlat/i2c_funcs.in
new file mode 100644
index 00000000..d3bb8d91
--- /dev/null
+++ b/src/xlat/i2c_funcs.in
@@ -0,0 +1,21 @@
+#unconditional
+I2C_FUNC_I2C
+I2C_FUNC_10BIT_ADDR
+I2C_FUNC_PROTOCOL_MANGLING
+I2C_FUNC_SMBUS_PEC
+I2C_FUNC_NOSTART
+I2C_FUNC_SLAVE
+I2C_FUNC_SMBUS_BLOCK_PROC_CALL
+I2C_FUNC_SMBUS_QUICK
+I2C_FUNC_SMBUS_READ_BYTE
+I2C_FUNC_SMBUS_WRITE_BYTE
+I2C_FUNC_SMBUS_READ_BYTE_DATA
+I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+I2C_FUNC_SMBUS_READ_WORD_DATA
+I2C_FUNC_SMBUS_WRITE_WORD_DATA
+I2C_FUNC_SMBUS_PROC_CALL
+I2C_FUNC_SMBUS_READ_BLOCK_DATA
+I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
+I2C_FUNC_SMBUS_READ_I2C_BLOCK
+I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
+I2C_FUNC_SMBUS_HOST_NOTIFY
diff --git a/src/xlat/i2c_msg_flags.in b/src/xlat/i2c_msg_flags.in
new file mode 100644
index 00000000..8eb5e921
--- /dev/null
+++ b/src/xlat/i2c_msg_flags.in
@@ -0,0 +1,10 @@
+#unconditional
+I2C_M_RD
+I2C_M_TEN
+I2C_M_DMA_SAFE
+I2C_M_RECV_LEN
+I2C_M_NO_RD_ACK
+I2C_M_IGNORE_NAK
+I2C_M_REV_DIR_ADDR
+I2C_M_NOSTART
+I2C_M_STOP
diff --git a/src/xlat/i2c_smbus_read_write.in b/src/xlat/i2c_smbus_read_write.in
new file mode 100644
index 00000000..cab3ae3c
--- /dev/null
+++ b/src/xlat/i2c_smbus_read_write.in
@@ -0,0 +1,3 @@
+#unconditional
+I2C_SMBUS_READ
+I2C_SMBUS_WRITE
diff --git a/src/xlat/i2c_smbus_size.in b/src/xlat/i2c_smbus_size.in
new file mode 100644
index 00000000..ca176072
--- /dev/null
+++ b/src/xlat/i2c_smbus_size.in
@@ -0,0 +1,10 @@
+#unconditional
+I2C_SMBUS_QUICK
+I2C_SMBUS_BYTE
+I2C_SMBUS_BYTE_DATA
+I2C_SMBUS_WORD_DATA
+I2C_SMBUS_PROC_CALL
+I2C_SMBUS_BLOCK_DATA
+I2C_SMBUS_I2C_BLOCK_BROKEN
+I2C_SMBUS_BLOCK_PROC_CALL
+I2C_SMBUS_I2C_BLOCK_DATA
-- 
2.31.1



More information about the Strace-devel mailing list