Commit 9b1ace8b authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] compat_ioctl for i2c

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.
parent c596442a
...@@ -223,7 +223,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, ...@@ -223,7 +223,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
/* Put an arbritrary limit on the number of messages that can /* Put an arbritrary limit on the number of messages that can
* be sent at once */ * be sent at once */
if (rdwr_arg.nmsgs > 42) if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL; return -EINVAL;
rdwr_pa = (struct i2c_msg *) rdwr_pa = (struct i2c_msg *)
......
...@@ -63,6 +63,8 @@ ...@@ -63,6 +63,8 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/ioctl32.h> #include <linux/ioctl32.h>
#include <linux/ncp_fs.h> #include <linux/ncp_fs.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <net/sock.h> /* siocdevprivate_ioctl */ #include <net/sock.h> /* siocdevprivate_ioctl */
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
...@@ -128,7 +130,7 @@ static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) ...@@ -128,7 +130,7 @@ static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
set_fs (KERNEL_DS); set_fs (KERNEL_DS);
err = sys_ioctl(fd, cmd, (unsigned long)&val); err = sys_ioctl(fd, cmd, (unsigned long)&val);
set_fs (old_fs); set_fs (old_fs);
if (!err && put_user(val, (u32 *)arg)) if (!err && put_user(val, (u32 *)compat_ptr(arg)))
return -EFAULT; return -EFAULT;
return err; return err;
} }
...@@ -136,15 +138,16 @@ static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) ...@@ -136,15 +138,16 @@ static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg) static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
mm_segment_t old_fs = get_fs(); mm_segment_t old_fs = get_fs();
u32 *argptr = compat_ptr(arg);
int err; int err;
unsigned long val; unsigned long val;
if(get_user(val, (u32 *)arg)) if(get_user(val, argptr))
return -EFAULT; return -EFAULT;
set_fs (KERNEL_DS); set_fs (KERNEL_DS);
err = sys_ioctl(fd, cmd, (unsigned long)&val); err = sys_ioctl(fd, cmd, (unsigned long)&val);
set_fs (old_fs); set_fs (old_fs);
if (!err && put_user(val, (u32 *)arg)) if (!err && put_user(val, argptr))
return -EFAULT; return -EFAULT;
return err; return err;
} }
...@@ -2869,6 +2872,105 @@ static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned lo ...@@ -2869,6 +2872,105 @@ static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned lo
return err; 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_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 #undef CODE
#endif #endif
...@@ -3027,5 +3129,10 @@ HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk) ...@@ -3027,5 +3129,10 @@ HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb) HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb) HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal) HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
/* i2c */
HANDLE_IOCTL(I2C_FUNCS, w_long)
HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl)
#undef DECLARES #undef DECLARES
#endif #endif
...@@ -678,3 +678,10 @@ COMPATIBLE_IOCTL(NBD_CLEAR_QUE) ...@@ -678,3 +678,10 @@ COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
COMPATIBLE_IOCTL(NBD_PRINT_DEBUG) COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS) COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
COMPATIBLE_IOCTL(NBD_DISCONNECT) 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)
...@@ -43,4 +43,6 @@ struct i2c_rdwr_ioctl_data { ...@@ -43,4 +43,6 @@ struct i2c_rdwr_ioctl_data {
__u32 nmsgs; /* number of i2c_msgs */ __u32 nmsgs; /* number of i2c_msgs */
}; };
#define I2C_RDRW_IOCTL_MAX_MSGS 42
#endif /* _LINUX_I2C_DEV_H */ #endif /* _LINUX_I2C_DEV_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment