diff options
Diffstat (limited to 'drivers/i2c/i2c-dev.c')
| -rw-r--r-- | drivers/i2c/i2c-dev.c | 329 |
1 files changed, 168 insertions, 161 deletions
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 393e679d9faa..d34c14c81c29 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
| @@ -200,16 +200,176 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) | |||
| 200 | return device_for_each_child(&adapter->dev, &addr, i2cdev_check); | 200 | return device_for_each_child(&adapter->dev, &addr, i2cdev_check); |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | static int i2cdev_ioctl(struct inode *inode, struct file *file, | 203 | static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, |
| 204 | unsigned int cmd, unsigned long arg) | 204 | unsigned long arg) |
| 205 | { | 205 | { |
| 206 | struct i2c_client *client = (struct i2c_client *)file->private_data; | ||
| 207 | struct i2c_rdwr_ioctl_data rdwr_arg; | 206 | struct i2c_rdwr_ioctl_data rdwr_arg; |
| 208 | struct i2c_smbus_ioctl_data data_arg; | ||
| 209 | union i2c_smbus_data temp; | ||
| 210 | struct i2c_msg *rdwr_pa; | 207 | struct i2c_msg *rdwr_pa; |
| 211 | u8 __user **data_ptrs; | 208 | u8 __user **data_ptrs; |
| 212 | int i,datasize,res; | 209 | int i, res; |
| 210 | |||
| 211 | if (copy_from_user(&rdwr_arg, | ||
| 212 | (struct i2c_rdwr_ioctl_data __user *)arg, | ||
| 213 | sizeof(rdwr_arg))) | ||
| 214 | return -EFAULT; | ||
| 215 | |||
| 216 | /* Put an arbitrary limit on the number of messages that can | ||
| 217 | * be sent at once */ | ||
| 218 | if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) | ||
| 219 | return -EINVAL; | ||
| 220 | |||
| 221 | rdwr_pa = (struct i2c_msg *) | ||
| 222 | kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), | ||
| 223 | GFP_KERNEL); | ||
| 224 | if (!rdwr_pa) | ||
| 225 | return -ENOMEM; | ||
| 226 | |||
| 227 | if (copy_from_user(rdwr_pa, rdwr_arg.msgs, | ||
| 228 | rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { | ||
| 229 | kfree(rdwr_pa); | ||
| 230 | return -EFAULT; | ||
| 231 | } | ||
| 232 | |||
| 233 | data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); | ||
| 234 | if (data_ptrs == NULL) { | ||
| 235 | kfree(rdwr_pa); | ||
| 236 | return -ENOMEM; | ||
| 237 | } | ||
| 238 | |||
| 239 | res = 0; | ||
| 240 | for (i = 0; i < rdwr_arg.nmsgs; i++) { | ||
| 241 | /* Limit the size of the message to a sane amount; | ||
| 242 | * and don't let length change either. */ | ||
| 243 | if ((rdwr_pa[i].len > 8192) || | ||
| 244 | (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { | ||
| 245 | res = -EINVAL; | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; | ||
| 249 | rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); | ||
| 250 | if (rdwr_pa[i].buf == NULL) { | ||
| 251 | res = -ENOMEM; | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i], | ||
| 255 | rdwr_pa[i].len)) { | ||
| 256 | ++i; /* Needs to be kfreed too */ | ||
| 257 | res = -EFAULT; | ||
| 258 | break; | ||
| 259 | } | ||
| 260 | } | ||
| 261 | if (res < 0) { | ||
| 262 | int j; | ||
| 263 | for (j = 0; j < i; ++j) | ||
| 264 | kfree(rdwr_pa[j].buf); | ||
| 265 | kfree(data_ptrs); | ||
| 266 | kfree(rdwr_pa); | ||
| 267 | return res; | ||
| 268 | } | ||
| 269 | |||
| 270 | res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); | ||
| 271 | while (i-- > 0) { | ||
| 272 | if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { | ||
| 273 | if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, | ||
| 274 | rdwr_pa[i].len)) | ||
| 275 | res = -EFAULT; | ||
| 276 | } | ||
| 277 | kfree(rdwr_pa[i].buf); | ||
| 278 | } | ||
| 279 | kfree(data_ptrs); | ||
| 280 | kfree(rdwr_pa); | ||
| 281 | return res; | ||
| 282 | } | ||
| 283 | |||
| 284 | static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, | ||
| 285 | unsigned long arg) | ||
| 286 | { | ||
| 287 | struct i2c_smbus_ioctl_data data_arg; | ||
| 288 | union i2c_smbus_data temp; | ||
| 289 | int datasize, res; | ||
| 290 | |||
| 291 | if (copy_from_user(&data_arg, | ||
| 292 | (struct i2c_smbus_ioctl_data __user *) arg, | ||
| 293 | sizeof(struct i2c_smbus_ioctl_data))) | ||
| 294 | return -EFAULT; | ||
| 295 | if ((data_arg.size != I2C_SMBUS_BYTE) && | ||
| 296 | (data_arg.size != I2C_SMBUS_QUICK) && | ||
| 297 | (data_arg.size != I2C_SMBUS_BYTE_DATA) && | ||
| 298 | (data_arg.size != I2C_SMBUS_WORD_DATA) && | ||
| 299 | (data_arg.size != I2C_SMBUS_PROC_CALL) && | ||
| 300 | (data_arg.size != I2C_SMBUS_BLOCK_DATA) && | ||
| 301 | (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && | ||
| 302 | (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && | ||
| 303 | (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { | ||
| 304 | dev_dbg(&client->adapter->dev, | ||
| 305 | "size out of range (%x) in ioctl I2C_SMBUS.\n", | ||
| 306 | data_arg.size); | ||
| 307 | return -EINVAL; | ||
| 308 | } | ||
| 309 | /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, | ||
| 310 | so the check is valid if size==I2C_SMBUS_QUICK too. */ | ||
| 311 | if ((data_arg.read_write != I2C_SMBUS_READ) && | ||
| 312 | (data_arg.read_write != I2C_SMBUS_WRITE)) { | ||
| 313 | dev_dbg(&client->adapter->dev, | ||
| 314 | "read_write out of range (%x) in ioctl I2C_SMBUS.\n", | ||
| 315 | data_arg.read_write); | ||
| 316 | return -EINVAL; | ||
| 317 | } | ||
| 318 | |||
| 319 | /* Note that command values are always valid! */ | ||
| 320 | |||
| 321 | if ((data_arg.size == I2C_SMBUS_QUICK) || | ||
| 322 | ((data_arg.size == I2C_SMBUS_BYTE) && | ||
| 323 | (data_arg.read_write == I2C_SMBUS_WRITE))) | ||
| 324 | /* These are special: we do not use data */ | ||
| 325 | return i2c_smbus_xfer(client->adapter, client->addr, | ||
| 326 | client->flags, data_arg.read_write, | ||
| 327 | data_arg.command, data_arg.size, NULL); | ||
| 328 | |||
| 329 | if (data_arg.data == NULL) { | ||
| 330 | dev_dbg(&client->adapter->dev, | ||
| 331 | "data is NULL pointer in ioctl I2C_SMBUS.\n"); | ||
| 332 | return -EINVAL; | ||
| 333 | } | ||
| 334 | |||
| 335 | if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || | ||
| 336 | (data_arg.size == I2C_SMBUS_BYTE)) | ||
| 337 | datasize = sizeof(data_arg.data->byte); | ||
| 338 | else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || | ||
| 339 | (data_arg.size == I2C_SMBUS_PROC_CALL)) | ||
| 340 | datasize = sizeof(data_arg.data->word); | ||
| 341 | else /* size == smbus block, i2c block, or block proc. call */ | ||
| 342 | datasize = sizeof(data_arg.data->block); | ||
| 343 | |||
| 344 | if ((data_arg.size == I2C_SMBUS_PROC_CALL) || | ||
| 345 | (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || | ||
| 346 | (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || | ||
| 347 | (data_arg.read_write == I2C_SMBUS_WRITE)) { | ||
| 348 | if (copy_from_user(&temp, data_arg.data, datasize)) | ||
| 349 | return -EFAULT; | ||
| 350 | } | ||
| 351 | if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { | ||
| 352 | /* Convert old I2C block commands to the new | ||
| 353 | convention. This preserves binary compatibility. */ | ||
| 354 | data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; | ||
| 355 | if (data_arg.read_write == I2C_SMBUS_READ) | ||
| 356 | temp.block[0] = I2C_SMBUS_BLOCK_MAX; | ||
| 357 | } | ||
| 358 | res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, | ||
| 359 | data_arg.read_write, data_arg.command, data_arg.size, &temp); | ||
| 360 | if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || | ||
| 361 | (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || | ||
| 362 | (data_arg.read_write == I2C_SMBUS_READ))) { | ||
| 363 | if (copy_to_user(data_arg.data, &temp, datasize)) | ||
| 364 | return -EFAULT; | ||
| 365 | } | ||
| 366 | return res; | ||
| 367 | } | ||
| 368 | |||
| 369 | static int i2cdev_ioctl(struct inode *inode, struct file *file, | ||
| 370 | unsigned int cmd, unsigned long arg) | ||
| 371 | { | ||
| 372 | struct i2c_client *client = (struct i2c_client *)file->private_data; | ||
| 213 | unsigned long funcs; | 373 | unsigned long funcs; |
| 214 | 374 | ||
| 215 | dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n", | 375 | dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n", |
| @@ -253,164 +413,11 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, | |||
| 253 | return put_user(funcs, (unsigned long __user *)arg); | 413 | return put_user(funcs, (unsigned long __user *)arg); |
| 254 | 414 | ||
| 255 | case I2C_RDWR: | 415 | case I2C_RDWR: |
| 256 | if (copy_from_user(&rdwr_arg, | 416 | return i2cdev_ioctl_rdrw(client, arg); |
| 257 | (struct i2c_rdwr_ioctl_data __user *)arg, | ||
| 258 | sizeof(rdwr_arg))) | ||
| 259 | return -EFAULT; | ||
| 260 | |||
| 261 | /* Put an arbitrary limit on the number of messages that can | ||
| 262 | * be sent at once */ | ||
| 263 | if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) | ||
| 264 | return -EINVAL; | ||
| 265 | |||
| 266 | rdwr_pa = (struct i2c_msg *) | ||
| 267 | kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), | ||
| 268 | GFP_KERNEL); | ||
| 269 | |||
| 270 | if (rdwr_pa == NULL) return -ENOMEM; | ||
| 271 | |||
| 272 | if (copy_from_user(rdwr_pa, rdwr_arg.msgs, | ||
| 273 | rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { | ||
| 274 | kfree(rdwr_pa); | ||
| 275 | return -EFAULT; | ||
| 276 | } | ||
| 277 | |||
| 278 | data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); | ||
| 279 | if (data_ptrs == NULL) { | ||
| 280 | kfree(rdwr_pa); | ||
| 281 | return -ENOMEM; | ||
| 282 | } | ||
| 283 | |||
| 284 | res = 0; | ||
| 285 | for( i=0; i<rdwr_arg.nmsgs; i++ ) { | ||
| 286 | /* Limit the size of the message to a sane amount; | ||
| 287 | * and don't let length change either. */ | ||
| 288 | if ((rdwr_pa[i].len > 8192) || | ||
| 289 | (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { | ||
| 290 | res = -EINVAL; | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; | ||
| 294 | rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); | ||
| 295 | if(rdwr_pa[i].buf == NULL) { | ||
| 296 | res = -ENOMEM; | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | if(copy_from_user(rdwr_pa[i].buf, | ||
| 300 | data_ptrs[i], | ||
| 301 | rdwr_pa[i].len)) { | ||
| 302 | ++i; /* Needs to be kfreed too */ | ||
| 303 | res = -EFAULT; | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | if (res < 0) { | ||
| 308 | int j; | ||
| 309 | for (j = 0; j < i; ++j) | ||
| 310 | kfree(rdwr_pa[j].buf); | ||
| 311 | kfree(data_ptrs); | ||
| 312 | kfree(rdwr_pa); | ||
| 313 | return res; | ||
| 314 | } | ||
| 315 | |||
| 316 | res = i2c_transfer(client->adapter, | ||
| 317 | rdwr_pa, | ||
| 318 | rdwr_arg.nmsgs); | ||
| 319 | while(i-- > 0) { | ||
| 320 | if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) { | ||
| 321 | if(copy_to_user( | ||
| 322 | data_ptrs[i], | ||
| 323 | rdwr_pa[i].buf, | ||
| 324 | rdwr_pa[i].len)) { | ||
| 325 | res = -EFAULT; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | kfree(rdwr_pa[i].buf); | ||
| 329 | } | ||
| 330 | kfree(data_ptrs); | ||
| 331 | kfree(rdwr_pa); | ||
| 332 | return res; | ||
| 333 | 417 | ||
| 334 | case I2C_SMBUS: | 418 | case I2C_SMBUS: |
| 335 | if (copy_from_user(&data_arg, | 419 | return i2cdev_ioctl_smbus(client, arg); |
| 336 | (struct i2c_smbus_ioctl_data __user *) arg, | ||
| 337 | sizeof(struct i2c_smbus_ioctl_data))) | ||
| 338 | return -EFAULT; | ||
| 339 | if ((data_arg.size != I2C_SMBUS_BYTE) && | ||
| 340 | (data_arg.size != I2C_SMBUS_QUICK) && | ||
| 341 | (data_arg.size != I2C_SMBUS_BYTE_DATA) && | ||
| 342 | (data_arg.size != I2C_SMBUS_WORD_DATA) && | ||
| 343 | (data_arg.size != I2C_SMBUS_PROC_CALL) && | ||
| 344 | (data_arg.size != I2C_SMBUS_BLOCK_DATA) && | ||
| 345 | (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && | ||
| 346 | (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && | ||
| 347 | (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { | ||
| 348 | dev_dbg(&client->adapter->dev, | ||
| 349 | "size out of range (%x) in ioctl I2C_SMBUS.\n", | ||
| 350 | data_arg.size); | ||
| 351 | return -EINVAL; | ||
| 352 | } | ||
| 353 | /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, | ||
| 354 | so the check is valid if size==I2C_SMBUS_QUICK too. */ | ||
| 355 | if ((data_arg.read_write != I2C_SMBUS_READ) && | ||
| 356 | (data_arg.read_write != I2C_SMBUS_WRITE)) { | ||
| 357 | dev_dbg(&client->adapter->dev, | ||
| 358 | "read_write out of range (%x) in ioctl I2C_SMBUS.\n", | ||
| 359 | data_arg.read_write); | ||
| 360 | return -EINVAL; | ||
| 361 | } | ||
| 362 | |||
| 363 | /* Note that command values are always valid! */ | ||
| 364 | |||
| 365 | if ((data_arg.size == I2C_SMBUS_QUICK) || | ||
| 366 | ((data_arg.size == I2C_SMBUS_BYTE) && | ||
| 367 | (data_arg.read_write == I2C_SMBUS_WRITE))) | ||
| 368 | /* These are special: we do not use data */ | ||
| 369 | return i2c_smbus_xfer(client->adapter, client->addr, | ||
| 370 | client->flags, | ||
| 371 | data_arg.read_write, | ||
| 372 | data_arg.command, | ||
| 373 | data_arg.size, NULL); | ||
| 374 | |||
| 375 | if (data_arg.data == NULL) { | ||
| 376 | dev_dbg(&client->adapter->dev, | ||
| 377 | "data is NULL pointer in ioctl I2C_SMBUS.\n"); | ||
| 378 | return -EINVAL; | ||
| 379 | } | ||
| 380 | 420 | ||
| 381 | if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || | ||
| 382 | (data_arg.size == I2C_SMBUS_BYTE)) | ||
| 383 | datasize = sizeof(data_arg.data->byte); | ||
| 384 | else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || | ||
| 385 | (data_arg.size == I2C_SMBUS_PROC_CALL)) | ||
| 386 | datasize = sizeof(data_arg.data->word); | ||
| 387 | else /* size == smbus block, i2c block, or block proc. call */ | ||
| 388 | datasize = sizeof(data_arg.data->block); | ||
| 389 | |||
| 390 | if ((data_arg.size == I2C_SMBUS_PROC_CALL) || | ||
| 391 | (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || | ||
| 392 | (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || | ||
| 393 | (data_arg.read_write == I2C_SMBUS_WRITE)) { | ||
| 394 | if (copy_from_user(&temp, data_arg.data, datasize)) | ||
| 395 | return -EFAULT; | ||
| 396 | } | ||
| 397 | if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { | ||
| 398 | /* Convert old I2C block commands to the new | ||
| 399 | convention. This preserves binary compatibility. */ | ||
| 400 | data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; | ||
| 401 | if (data_arg.read_write == I2C_SMBUS_READ) | ||
| 402 | temp.block[0] = I2C_SMBUS_BLOCK_MAX; | ||
| 403 | } | ||
| 404 | res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, | ||
| 405 | data_arg.read_write, | ||
| 406 | data_arg.command,data_arg.size,&temp); | ||
| 407 | if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || | ||
| 408 | (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || | ||
| 409 | (data_arg.read_write == I2C_SMBUS_READ))) { | ||
| 410 | if (copy_to_user(data_arg.data, &temp, datasize)) | ||
| 411 | return -EFAULT; | ||
| 412 | } | ||
| 413 | return res; | ||
| 414 | case I2C_RETRIES: | 421 | case I2C_RETRIES: |
| 415 | client->adapter->retries = arg; | 422 | client->adapter->retries = arg; |
| 416 | break; | 423 | break; |
