From: Benjamin Herrenschmidt 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 #include #include +#include +#include #include /* siocdevprivate_ioctl */ #include @@ -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) _