diff options
Diffstat (limited to 'drivers/i2c/i2c-dev.c')
| -rw-r--r-- | drivers/i2c/i2c-dev.c | 66 |
1 files changed, 46 insertions, 20 deletions
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index e0694e4d86c7..5f3a52d517c3 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
| @@ -167,13 +167,9 @@ static ssize_t i2cdev_write(struct file *file, const char __user *buf, | |||
| 167 | if (count > 8192) | 167 | if (count > 8192) |
| 168 | count = 8192; | 168 | count = 8192; |
| 169 | 169 | ||
| 170 | tmp = kmalloc(count, GFP_KERNEL); | 170 | tmp = memdup_user(buf, count); |
| 171 | if (tmp == NULL) | 171 | if (IS_ERR(tmp)) |
| 172 | return -ENOMEM; | 172 | return PTR_ERR(tmp); |
| 173 | if (copy_from_user(tmp, buf, count)) { | ||
| 174 | kfree(tmp); | ||
| 175 | return -EFAULT; | ||
| 176 | } | ||
| 177 | 173 | ||
| 178 | pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n", | 174 | pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n", |
| 179 | iminor(file->f_path.dentry->d_inode), count); | 175 | iminor(file->f_path.dentry->d_inode), count); |
| @@ -193,12 +189,50 @@ static int i2cdev_check(struct device *dev, void *addrp) | |||
| 193 | return dev->driver ? -EBUSY : 0; | 189 | return dev->driver ? -EBUSY : 0; |
| 194 | } | 190 | } |
| 195 | 191 | ||
| 192 | /* walk up mux tree */ | ||
| 193 | static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr) | ||
| 194 | { | ||
| 195 | int result; | ||
| 196 | |||
| 197 | result = device_for_each_child(&adapter->dev, &addr, i2cdev_check); | ||
| 198 | |||
| 199 | if (!result && i2c_parent_is_i2c_adapter(adapter)) | ||
| 200 | result = i2cdev_check_mux_parents( | ||
| 201 | to_i2c_adapter(adapter->dev.parent), addr); | ||
| 202 | |||
| 203 | return result; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* recurse down mux tree */ | ||
| 207 | static int i2cdev_check_mux_children(struct device *dev, void *addrp) | ||
| 208 | { | ||
| 209 | int result; | ||
| 210 | |||
| 211 | if (dev->type == &i2c_adapter_type) | ||
| 212 | result = device_for_each_child(dev, addrp, | ||
| 213 | i2cdev_check_mux_children); | ||
| 214 | else | ||
| 215 | result = i2cdev_check(dev, addrp); | ||
| 216 | |||
| 217 | return result; | ||
| 218 | } | ||
| 219 | |||
| 196 | /* This address checking function differs from the one in i2c-core | 220 | /* This address checking function differs from the one in i2c-core |
| 197 | in that it considers an address with a registered device, but no | 221 | in that it considers an address with a registered device, but no |
| 198 | driver bound to it, as NOT busy. */ | 222 | driver bound to it, as NOT busy. */ |
| 199 | static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) | 223 | static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) |
| 200 | { | 224 | { |
| 201 | return device_for_each_child(&adapter->dev, &addr, i2cdev_check); | 225 | int result = 0; |
| 226 | |||
| 227 | if (i2c_parent_is_i2c_adapter(adapter)) | ||
| 228 | result = i2cdev_check_mux_parents( | ||
| 229 | to_i2c_adapter(adapter->dev.parent), addr); | ||
| 230 | |||
| 231 | if (!result) | ||
| 232 | result = device_for_each_child(&adapter->dev, &addr, | ||
| 233 | i2cdev_check_mux_children); | ||
| 234 | |||
| 235 | return result; | ||
| 202 | } | 236 | } |
| 203 | 237 | ||
| 204 | static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, | 238 | static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, |
| @@ -219,9 +253,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, | |||
| 219 | if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) | 253 | if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) |
| 220 | return -EINVAL; | 254 | return -EINVAL; |
| 221 | 255 | ||
| 222 | rdwr_pa = (struct i2c_msg *) | 256 | rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); |
| 223 | kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), | ||
| 224 | GFP_KERNEL); | ||
| 225 | if (!rdwr_pa) | 257 | if (!rdwr_pa) |
| 226 | return -ENOMEM; | 258 | return -ENOMEM; |
| 227 | 259 | ||
| @@ -247,15 +279,9 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, | |||
| 247 | break; | 279 | break; |
| 248 | } | 280 | } |
| 249 | data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; | 281 | data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; |
| 250 | rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); | 282 | rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); |
| 251 | if (rdwr_pa[i].buf == NULL) { | 283 | if (IS_ERR(rdwr_pa[i].buf)) { |
| 252 | res = -ENOMEM; | 284 | res = PTR_ERR(rdwr_pa[i].buf); |
| 253 | break; | ||
| 254 | } | ||
| 255 | if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i], | ||
| 256 | rdwr_pa[i].len)) { | ||
| 257 | ++i; /* Needs to be kfreed too */ | ||
| 258 | res = -EFAULT; | ||
| 259 | break; | 285 | break; |
| 260 | } | 286 | } |
| 261 | } | 287 | } |
