diff options
Diffstat (limited to 'drivers/i2c/i2c-dev.c')
-rw-r--r-- | drivers/i2c/i2c-dev.c | 268 |
1 files changed, 180 insertions, 88 deletions
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 6f638bbc922d..2cab27a68479 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/notifier.h> | 35 | #include <linux/notifier.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/uaccess.h> | 37 | #include <linux/uaccess.h> |
38 | #include <linux/compat.h> | ||
38 | 39 | ||
39 | /* | 40 | /* |
40 | * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a | 41 | * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a |
@@ -238,46 +239,29 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) | |||
238 | } | 239 | } |
239 | 240 | ||
240 | static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, | 241 | static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, |
241 | unsigned long arg) | 242 | unsigned nmsgs, struct i2c_msg *msgs) |
242 | { | 243 | { |
243 | struct i2c_rdwr_ioctl_data rdwr_arg; | ||
244 | struct i2c_msg *rdwr_pa; | ||
245 | u8 __user **data_ptrs; | 244 | u8 __user **data_ptrs; |
246 | int i, res; | 245 | int i, res; |
247 | 246 | ||
248 | if (copy_from_user(&rdwr_arg, | 247 | data_ptrs = kmalloc(nmsgs * sizeof(u8 __user *), GFP_KERNEL); |
249 | (struct i2c_rdwr_ioctl_data __user *)arg, | ||
250 | sizeof(rdwr_arg))) | ||
251 | return -EFAULT; | ||
252 | |||
253 | /* Put an arbitrary limit on the number of messages that can | ||
254 | * be sent at once */ | ||
255 | if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) | ||
256 | return -EINVAL; | ||
257 | |||
258 | rdwr_pa = memdup_user(rdwr_arg.msgs, | ||
259 | rdwr_arg.nmsgs * sizeof(struct i2c_msg)); | ||
260 | if (IS_ERR(rdwr_pa)) | ||
261 | return PTR_ERR(rdwr_pa); | ||
262 | |||
263 | data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); | ||
264 | if (data_ptrs == NULL) { | 248 | if (data_ptrs == NULL) { |
265 | kfree(rdwr_pa); | 249 | kfree(msgs); |
266 | return -ENOMEM; | 250 | return -ENOMEM; |
267 | } | 251 | } |
268 | 252 | ||
269 | res = 0; | 253 | res = 0; |
270 | for (i = 0; i < rdwr_arg.nmsgs; i++) { | 254 | for (i = 0; i < nmsgs; i++) { |
271 | /* Limit the size of the message to a sane amount */ | 255 | /* Limit the size of the message to a sane amount */ |
272 | if (rdwr_pa[i].len > 8192) { | 256 | if (msgs[i].len > 8192) { |
273 | res = -EINVAL; | 257 | res = -EINVAL; |
274 | break; | 258 | break; |
275 | } | 259 | } |
276 | 260 | ||
277 | data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; | 261 | data_ptrs[i] = (u8 __user *)msgs[i].buf; |
278 | rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); | 262 | msgs[i].buf = memdup_user(data_ptrs[i], msgs[i].len); |
279 | if (IS_ERR(rdwr_pa[i].buf)) { | 263 | if (IS_ERR(msgs[i].buf)) { |
280 | res = PTR_ERR(rdwr_pa[i].buf); | 264 | res = PTR_ERR(msgs[i].buf); |
281 | break; | 265 | break; |
282 | } | 266 | } |
283 | 267 | ||
@@ -292,121 +276,117 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, | |||
292 | * greater (for example to account for a checksum byte at | 276 | * greater (for example to account for a checksum byte at |
293 | * the end of the message.) | 277 | * the end of the message.) |
294 | */ | 278 | */ |
295 | if (rdwr_pa[i].flags & I2C_M_RECV_LEN) { | 279 | if (msgs[i].flags & I2C_M_RECV_LEN) { |
296 | if (!(rdwr_pa[i].flags & I2C_M_RD) || | 280 | if (!(msgs[i].flags & I2C_M_RD) || |
297 | rdwr_pa[i].buf[0] < 1 || | 281 | msgs[i].buf[0] < 1 || |
298 | rdwr_pa[i].len < rdwr_pa[i].buf[0] + | 282 | msgs[i].len < msgs[i].buf[0] + |
299 | I2C_SMBUS_BLOCK_MAX) { | 283 | I2C_SMBUS_BLOCK_MAX) { |
300 | res = -EINVAL; | 284 | res = -EINVAL; |
301 | break; | 285 | break; |
302 | } | 286 | } |
303 | 287 | ||
304 | rdwr_pa[i].len = rdwr_pa[i].buf[0]; | 288 | msgs[i].len = msgs[i].buf[0]; |
305 | } | 289 | } |
306 | } | 290 | } |
307 | if (res < 0) { | 291 | if (res < 0) { |
308 | int j; | 292 | int j; |
309 | for (j = 0; j < i; ++j) | 293 | for (j = 0; j < i; ++j) |
310 | kfree(rdwr_pa[j].buf); | 294 | kfree(msgs[j].buf); |
311 | kfree(data_ptrs); | 295 | kfree(data_ptrs); |
312 | kfree(rdwr_pa); | 296 | kfree(msgs); |
313 | return res; | 297 | return res; |
314 | } | 298 | } |
315 | 299 | ||
316 | res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); | 300 | res = i2c_transfer(client->adapter, msgs, nmsgs); |
317 | while (i-- > 0) { | 301 | while (i-- > 0) { |
318 | if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { | 302 | if (res >= 0 && (msgs[i].flags & I2C_M_RD)) { |
319 | if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, | 303 | if (copy_to_user(data_ptrs[i], msgs[i].buf, |
320 | rdwr_pa[i].len)) | 304 | msgs[i].len)) |
321 | res = -EFAULT; | 305 | res = -EFAULT; |
322 | } | 306 | } |
323 | kfree(rdwr_pa[i].buf); | 307 | kfree(msgs[i].buf); |
324 | } | 308 | } |
325 | kfree(data_ptrs); | 309 | kfree(data_ptrs); |
326 | kfree(rdwr_pa); | 310 | kfree(msgs); |
327 | return res; | 311 | return res; |
328 | } | 312 | } |
329 | 313 | ||
330 | static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, | 314 | static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, |
331 | unsigned long arg) | 315 | u8 read_write, u8 command, u32 size, |
316 | union i2c_smbus_data __user *data) | ||
332 | { | 317 | { |
333 | struct i2c_smbus_ioctl_data data_arg; | ||
334 | union i2c_smbus_data temp = {}; | 318 | union i2c_smbus_data temp = {}; |
335 | int datasize, res; | 319 | int datasize, res; |
336 | 320 | ||
337 | if (copy_from_user(&data_arg, | 321 | if ((size != I2C_SMBUS_BYTE) && |
338 | (struct i2c_smbus_ioctl_data __user *) arg, | 322 | (size != I2C_SMBUS_QUICK) && |
339 | sizeof(struct i2c_smbus_ioctl_data))) | 323 | (size != I2C_SMBUS_BYTE_DATA) && |
340 | return -EFAULT; | 324 | (size != I2C_SMBUS_WORD_DATA) && |
341 | if ((data_arg.size != I2C_SMBUS_BYTE) && | 325 | (size != I2C_SMBUS_PROC_CALL) && |
342 | (data_arg.size != I2C_SMBUS_QUICK) && | 326 | (size != I2C_SMBUS_BLOCK_DATA) && |
343 | (data_arg.size != I2C_SMBUS_BYTE_DATA) && | 327 | (size != I2C_SMBUS_I2C_BLOCK_BROKEN) && |
344 | (data_arg.size != I2C_SMBUS_WORD_DATA) && | 328 | (size != I2C_SMBUS_I2C_BLOCK_DATA) && |
345 | (data_arg.size != I2C_SMBUS_PROC_CALL) && | 329 | (size != I2C_SMBUS_BLOCK_PROC_CALL)) { |
346 | (data_arg.size != I2C_SMBUS_BLOCK_DATA) && | ||
347 | (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && | ||
348 | (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && | ||
349 | (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { | ||
350 | dev_dbg(&client->adapter->dev, | 330 | dev_dbg(&client->adapter->dev, |
351 | "size out of range (%x) in ioctl I2C_SMBUS.\n", | 331 | "size out of range (%x) in ioctl I2C_SMBUS.\n", |
352 | data_arg.size); | 332 | size); |
353 | return -EINVAL; | 333 | return -EINVAL; |
354 | } | 334 | } |
355 | /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, | 335 | /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, |
356 | so the check is valid if size==I2C_SMBUS_QUICK too. */ | 336 | so the check is valid if size==I2C_SMBUS_QUICK too. */ |
357 | if ((data_arg.read_write != I2C_SMBUS_READ) && | 337 | if ((read_write != I2C_SMBUS_READ) && |
358 | (data_arg.read_write != I2C_SMBUS_WRITE)) { | 338 | (read_write != I2C_SMBUS_WRITE)) { |
359 | dev_dbg(&client->adapter->dev, | 339 | dev_dbg(&client->adapter->dev, |
360 | "read_write out of range (%x) in ioctl I2C_SMBUS.\n", | 340 | "read_write out of range (%x) in ioctl I2C_SMBUS.\n", |
361 | data_arg.read_write); | 341 | read_write); |
362 | return -EINVAL; | 342 | return -EINVAL; |
363 | } | 343 | } |
364 | 344 | ||
365 | /* Note that command values are always valid! */ | 345 | /* Note that command values are always valid! */ |
366 | 346 | ||
367 | if ((data_arg.size == I2C_SMBUS_QUICK) || | 347 | if ((size == I2C_SMBUS_QUICK) || |
368 | ((data_arg.size == I2C_SMBUS_BYTE) && | 348 | ((size == I2C_SMBUS_BYTE) && |
369 | (data_arg.read_write == I2C_SMBUS_WRITE))) | 349 | (read_write == I2C_SMBUS_WRITE))) |
370 | /* These are special: we do not use data */ | 350 | /* These are special: we do not use data */ |
371 | return i2c_smbus_xfer(client->adapter, client->addr, | 351 | return i2c_smbus_xfer(client->adapter, client->addr, |
372 | client->flags, data_arg.read_write, | 352 | client->flags, read_write, |
373 | data_arg.command, data_arg.size, NULL); | 353 | command, size, NULL); |
374 | 354 | ||
375 | if (data_arg.data == NULL) { | 355 | if (data == NULL) { |
376 | dev_dbg(&client->adapter->dev, | 356 | dev_dbg(&client->adapter->dev, |
377 | "data is NULL pointer in ioctl I2C_SMBUS.\n"); | 357 | "data is NULL pointer in ioctl I2C_SMBUS.\n"); |
378 | return -EINVAL; | 358 | return -EINVAL; |
379 | } | 359 | } |
380 | 360 | ||
381 | if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || | 361 | if ((size == I2C_SMBUS_BYTE_DATA) || |
382 | (data_arg.size == I2C_SMBUS_BYTE)) | 362 | (size == I2C_SMBUS_BYTE)) |
383 | datasize = sizeof(data_arg.data->byte); | 363 | datasize = sizeof(data->byte); |
384 | else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || | 364 | else if ((size == I2C_SMBUS_WORD_DATA) || |
385 | (data_arg.size == I2C_SMBUS_PROC_CALL)) | 365 | (size == I2C_SMBUS_PROC_CALL)) |
386 | datasize = sizeof(data_arg.data->word); | 366 | datasize = sizeof(data->word); |
387 | else /* size == smbus block, i2c block, or block proc. call */ | 367 | else /* size == smbus block, i2c block, or block proc. call */ |
388 | datasize = sizeof(data_arg.data->block); | 368 | datasize = sizeof(data->block); |
389 | 369 | ||
390 | if ((data_arg.size == I2C_SMBUS_PROC_CALL) || | 370 | if ((size == I2C_SMBUS_PROC_CALL) || |
391 | (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || | 371 | (size == I2C_SMBUS_BLOCK_PROC_CALL) || |
392 | (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || | 372 | (size == I2C_SMBUS_I2C_BLOCK_DATA) || |
393 | (data_arg.read_write == I2C_SMBUS_WRITE)) { | 373 | (read_write == I2C_SMBUS_WRITE)) { |
394 | if (copy_from_user(&temp, data_arg.data, datasize)) | 374 | if (copy_from_user(&temp, data, datasize)) |
395 | return -EFAULT; | 375 | return -EFAULT; |
396 | } | 376 | } |
397 | if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { | 377 | if (size == I2C_SMBUS_I2C_BLOCK_BROKEN) { |
398 | /* Convert old I2C block commands to the new | 378 | /* Convert old I2C block commands to the new |
399 | convention. This preserves binary compatibility. */ | 379 | convention. This preserves binary compatibility. */ |
400 | data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; | 380 | size = I2C_SMBUS_I2C_BLOCK_DATA; |
401 | if (data_arg.read_write == I2C_SMBUS_READ) | 381 | if (read_write == I2C_SMBUS_READ) |
402 | temp.block[0] = I2C_SMBUS_BLOCK_MAX; | 382 | temp.block[0] = I2C_SMBUS_BLOCK_MAX; |
403 | } | 383 | } |
404 | res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 384 | res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, |
405 | data_arg.read_write, data_arg.command, data_arg.size, &temp); | 385 | read_write, command, size, &temp); |
406 | if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || | 386 | if (!res && ((size == I2C_SMBUS_PROC_CALL) || |
407 | (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || | 387 | (size == I2C_SMBUS_BLOCK_PROC_CALL) || |
408 | (data_arg.read_write == I2C_SMBUS_READ))) { | 388 | (read_write == I2C_SMBUS_READ))) { |
409 | if (copy_to_user(data_arg.data, &temp, datasize)) | 389 | if (copy_to_user(data, &temp, datasize)) |
410 | return -EFAULT; | 390 | return -EFAULT; |
411 | } | 391 | } |
412 | return res; | 392 | return res; |
@@ -454,12 +434,39 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
454 | funcs = i2c_get_functionality(client->adapter); | 434 | funcs = i2c_get_functionality(client->adapter); |
455 | return put_user(funcs, (unsigned long __user *)arg); | 435 | return put_user(funcs, (unsigned long __user *)arg); |
456 | 436 | ||
457 | case I2C_RDWR: | 437 | case I2C_RDWR: { |
458 | return i2cdev_ioctl_rdwr(client, arg); | 438 | struct i2c_rdwr_ioctl_data rdwr_arg; |
439 | struct i2c_msg *rdwr_pa; | ||
440 | |||
441 | if (copy_from_user(&rdwr_arg, | ||
442 | (struct i2c_rdwr_ioctl_data __user *)arg, | ||
443 | sizeof(rdwr_arg))) | ||
444 | return -EFAULT; | ||
445 | |||
446 | /* Put an arbitrary limit on the number of messages that can | ||
447 | * be sent at once */ | ||
448 | if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) | ||
449 | return -EINVAL; | ||
459 | 450 | ||
460 | case I2C_SMBUS: | 451 | rdwr_pa = memdup_user(rdwr_arg.msgs, |
461 | return i2cdev_ioctl_smbus(client, arg); | 452 | rdwr_arg.nmsgs * sizeof(struct i2c_msg)); |
453 | if (IS_ERR(rdwr_pa)) | ||
454 | return PTR_ERR(rdwr_pa); | ||
455 | |||
456 | return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); | ||
457 | } | ||
462 | 458 | ||
459 | case I2C_SMBUS: { | ||
460 | struct i2c_smbus_ioctl_data data_arg; | ||
461 | if (copy_from_user(&data_arg, | ||
462 | (struct i2c_smbus_ioctl_data __user *) arg, | ||
463 | sizeof(struct i2c_smbus_ioctl_data))) | ||
464 | return -EFAULT; | ||
465 | return i2cdev_ioctl_smbus(client, data_arg.read_write, | ||
466 | data_arg.command, | ||
467 | data_arg.size, | ||
468 | data_arg.data); | ||
469 | } | ||
463 | case I2C_RETRIES: | 470 | case I2C_RETRIES: |
464 | client->adapter->retries = arg; | 471 | client->adapter->retries = arg; |
465 | break; | 472 | break; |
@@ -480,6 +487,90 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
480 | return 0; | 487 | return 0; |
481 | } | 488 | } |
482 | 489 | ||
490 | #ifdef CONFIG_COMPAT | ||
491 | |||
492 | struct i2c_smbus_ioctl_data32 { | ||
493 | u8 read_write; | ||
494 | u8 command; | ||
495 | u32 size; | ||
496 | compat_caddr_t data; /* union i2c_smbus_data *data */ | ||
497 | }; | ||
498 | |||
499 | struct i2c_msg32 { | ||
500 | u16 addr; | ||
501 | u16 flags; | ||
502 | u16 len; | ||
503 | compat_caddr_t buf; | ||
504 | }; | ||
505 | |||
506 | struct i2c_rdwr_ioctl_data32 { | ||
507 | compat_caddr_t msgs; /* struct i2c_msg __user *msgs */ | ||
508 | u32 nmsgs; | ||
509 | }; | ||
510 | |||
511 | static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
512 | { | ||
513 | struct i2c_client *client = file->private_data; | ||
514 | unsigned long funcs; | ||
515 | switch (cmd) { | ||
516 | case I2C_FUNCS: | ||
517 | funcs = i2c_get_functionality(client->adapter); | ||
518 | return put_user(funcs, (compat_ulong_t __user *)arg); | ||
519 | case I2C_RDWR: { | ||
520 | struct i2c_rdwr_ioctl_data32 rdwr_arg; | ||
521 | struct i2c_msg32 *p; | ||
522 | struct i2c_msg *rdwr_pa; | ||
523 | int i; | ||
524 | |||
525 | if (copy_from_user(&rdwr_arg, | ||
526 | (struct i2c_rdwr_ioctl_data32 __user *)arg, | ||
527 | sizeof(rdwr_arg))) | ||
528 | return -EFAULT; | ||
529 | |||
530 | if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) | ||
531 | return -EINVAL; | ||
532 | |||
533 | rdwr_pa = kmalloc_array(rdwr_arg.nmsgs, sizeof(struct i2c_msg), | ||
534 | GFP_KERNEL); | ||
535 | if (!rdwr_pa) | ||
536 | return -ENOMEM; | ||
537 | |||
538 | p = compat_ptr(rdwr_arg.msgs); | ||
539 | for (i = 0; i < rdwr_arg.nmsgs; i++) { | ||
540 | struct i2c_msg32 umsg; | ||
541 | if (copy_from_user(&umsg, p + i, sizeof(umsg))) { | ||
542 | kfree(rdwr_pa); | ||
543 | return -EFAULT; | ||
544 | } | ||
545 | rdwr_pa[i] = (struct i2c_msg) { | ||
546 | .addr = umsg.addr, | ||
547 | .flags = umsg.flags, | ||
548 | .len = umsg.len, | ||
549 | .buf = compat_ptr(umsg.buf) | ||
550 | }; | ||
551 | } | ||
552 | |||
553 | return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); | ||
554 | } | ||
555 | case I2C_SMBUS: { | ||
556 | struct i2c_smbus_ioctl_data32 data32; | ||
557 | if (copy_from_user(&data32, | ||
558 | (void __user *) arg, | ||
559 | sizeof(data32))) | ||
560 | return -EFAULT; | ||
561 | return i2cdev_ioctl_smbus(client, data32.read_write, | ||
562 | data32.command, | ||
563 | data32.size, | ||
564 | compat_ptr(data32.data)); | ||
565 | } | ||
566 | default: | ||
567 | return i2cdev_ioctl(file, cmd, arg); | ||
568 | } | ||
569 | } | ||
570 | #else | ||
571 | #define compat_i2cdev_ioctl NULL | ||
572 | #endif | ||
573 | |||
483 | static int i2cdev_open(struct inode *inode, struct file *file) | 574 | static int i2cdev_open(struct inode *inode, struct file *file) |
484 | { | 575 | { |
485 | unsigned int minor = iminor(inode); | 576 | unsigned int minor = iminor(inode); |
@@ -527,6 +618,7 @@ static const struct file_operations i2cdev_fops = { | |||
527 | .read = i2cdev_read, | 618 | .read = i2cdev_read, |
528 | .write = i2cdev_write, | 619 | .write = i2cdev_write, |
529 | .unlocked_ioctl = i2cdev_ioctl, | 620 | .unlocked_ioctl = i2cdev_ioctl, |
621 | .compat_ioctl = compat_i2cdev_ioctl, | ||
530 | .open = i2cdev_open, | 622 | .open = i2cdev_open, |
531 | .release = i2cdev_release, | 623 | .release = i2cdev_release, |
532 | }; | 624 | }; |