From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

I needed those for the G5 on ppc64, so here they are, I was only
able to test the SMBUS stuff though.



 fs/compat_ioctl.c            |  122 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/compat_ioctl.h |    7 ++
 2 files changed, 129 insertions(+)

diff -puN fs/compat_ioctl.c~compat-ioctl-for-i2c fs/compat_ioctl.c
--- 25/fs/compat_ioctl.c~compat-ioctl-for-i2c	2003-11-09 22:57:52.000000000 -0800
+++ 25-akpm/fs/compat_ioctl.c	2003-11-09 22:57:52.000000000 -0800
@@ -63,6 +63,8 @@
 #include <linux/ctype.h>
 #include <linux/ioctl32.h>
 #include <linux/ncp_fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
 
 #include <net/sock.h>          /* siocdevprivate_ioctl */
 #include <net/bluetooth/bluetooth.h>
@@ -2869,6 +2871,121 @@ static int do_usbdevfs_discsignal(unsign
 
         return err;
 }
+
+/*
+ * I2C layer ioctls
+ */
+
+struct i2c_msg32 {
+	u16 addr;
+	u16 flags;
+	u16 len;
+	compat_caddr_t buf;
+};
+
+struct i2c_rdwr_ioctl_data32 {
+	compat_caddr_t msgs; /* struct i2c_msg __user *msgs */
+	u32 nmsgs;
+};
+
+struct i2c_smbus_ioctl_data32 {
+	u8 read_write;
+	u8 command;
+	u32 size;
+	compat_caddr_t data; /* union i2c_smbus_data *data */
+};
+
+static int do_i2c_funcs_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	compat_ulong_t	result;
+	mm_segment_t old_fs;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, I2C_FUNCS, (unsigned long) &result);
+	set_fs(old_fs);
+
+	if (err >= 0 && put_user(result, (compat_ulong_t *)compat_ptr(arg)))
+		err = -EFAULT;
+	return err;
+}
+
+static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct i2c_rdwr_ioctl_data	*tdata;
+	struct i2c_rdwr_ioctl_data32	*udata;
+	struct i2c_msg			*tmsgs;
+	struct i2c_msg32		*umsgs;
+	compat_caddr_t			datap;
+	int				nmsgs, i;
+
+	tdata = compat_alloc_user_space(sizeof(*tdata));
+	if (tdata == NULL)
+		return -ENOMEM;
+	if (verify_area(VERIFY_WRITE, tdata, sizeof(*tdata)))
+		return -EFAULT;
+
+	udata = (struct i2c_rdwr_ioctl_data32 *)compat_ptr(arg);
+	if (verify_area(VERIFY_READ, udata, sizeof(*udata)))
+		return -EFAULT;
+	if (__get_user(nmsgs, &udata->nmsgs) || __put_user(nmsgs, &tdata->nmsgs))
+		return -EFAULT;
+	if (nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+		return -EINVAL;
+	if (__get_user(datap, &udata->msgs))
+		return -EFAULT;
+	umsgs = (struct i2c_msg32 *)compat_ptr(datap);
+	if (verify_area(VERIFY_READ, umsgs, sizeof(struct i2c_msg) * nmsgs))
+		return -EFAULT;
+
+	tmsgs = compat_alloc_user_space(sizeof(struct i2c_msg) * nmsgs);
+	if (tmsgs == NULL)
+		return -ENOMEM;
+	if (verify_area(VERIFY_WRITE, tmsgs, sizeof(struct i2c_msg) * nmsgs))
+		return -EFAULT;
+	if (__put_user(tmsgs, &tdata->msgs))
+		return -ENOMEM;
+	for (i = 0; i < nmsgs; i++) {
+		if (__copy_in_user(&tmsgs[i].addr,
+				   &umsgs[i].addr,
+				   3 * sizeof(u16)))
+			return -EFAULT;
+		if (__get_user(datap, &umsgs[i].buf) ||
+		    __put_user(compat_ptr(datap), &tmsgs[i].buf))
+			return -EFAULT;
+	}
+	return sys_ioctl(fd, cmd, (unsigned long)tdata);
+}
+
+static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct i2c_smbus_ioctl_data	*tdata;
+	struct i2c_smbus_ioctl_data32	*udata;
+	compat_caddr_t			datap;
+
+	tdata = compat_alloc_user_space(sizeof(*tdata));
+	if (tdata == NULL)
+		return -ENOMEM;
+	if (verify_area(VERIFY_WRITE, tdata, sizeof(*tdata)))
+		return -EFAULT;
+
+	udata = (struct i2c_smbus_ioctl_data32 *)compat_ptr(arg);
+	if (verify_area(VERIFY_READ, udata, sizeof(*udata)))
+		return -EFAULT;
+
+	if (__copy_in_user(&tdata->read_write, &udata->read_write, 2 * sizeof(u8)))
+		return -EFAULT;
+	if (__copy_in_user(&tdata->size, &udata->size, 2 * sizeof(u32)))
+		return -EFAULT;
+	if (__get_user(datap, &udata->data) ||
+	    __put_user(compat_ptr(datap), &tdata->data))
+		return -EFAULT;
+
+	return sys_ioctl(fd, cmd, (unsigned long)tdata);
+}
+
+
 #undef CODE
 #endif
 
@@ -3027,5 +3144,10 @@ HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevf
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+/* i2c */
+HANDLE_IOCTL(I2C_FUNCS, do_i2c_funcs_ioctl)
+HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
+HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl)
+
 #undef DECLARES
 #endif
diff -puN include/linux/compat_ioctl.h~compat-ioctl-for-i2c include/linux/compat_ioctl.h
--- 25/include/linux/compat_ioctl.h~compat-ioctl-for-i2c	2003-11-09 22:57:52.000000000 -0800
+++ 25-akpm/include/linux/compat_ioctl.h	2003-11-09 22:57:52.000000000 -0800
@@ -678,3 +678,10 @@ COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
 COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
 COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
 COMPATIBLE_IOCTL(NBD_DISCONNECT)
+/* i2c */
+COMPATIBLE_IOCTL(I2C_SLAVE)
+COMPATIBLE_IOCTL(I2C_SLAVE_FORCE)
+COMPATIBLE_IOCTL(I2C_TENBIT)
+COMPATIBLE_IOCTL(I2C_PEC)
+COMPATIBLE_IOCTL(I2C_RETRIES)
+COMPATIBLE_IOCTL(I2C_TIMEOUT)

_