diff options
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r-- | drivers/mtd/mtdchar.c | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index b45e7747daa3..7522fc3a2827 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -408,8 +408,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
408 | case MEMWRITEOOB: | 408 | case MEMWRITEOOB: |
409 | { | 409 | { |
410 | struct mtd_oob_buf buf; | 410 | struct mtd_oob_buf buf; |
411 | void *databuf; | 411 | struct mtd_oob_ops ops; |
412 | ssize_t retlen; | ||
413 | 412 | ||
414 | if(!(file->f_mode & 2)) | 413 | if(!(file->f_mode & 2)) |
415 | return -EPERM; | 414 | return -EPERM; |
@@ -417,7 +416,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
417 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) | 416 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) |
418 | return -EFAULT; | 417 | return -EFAULT; |
419 | 418 | ||
420 | if (buf.length > 0x4096) | 419 | if (buf.length > 4096) |
421 | return -EINVAL; | 420 | return -EINVAL; |
422 | 421 | ||
423 | if (!mtd->write_oob) | 422 | if (!mtd->write_oob) |
@@ -429,21 +428,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
429 | if (ret) | 428 | if (ret) |
430 | return ret; | 429 | return ret; |
431 | 430 | ||
432 | databuf = kmalloc(buf.length, GFP_KERNEL); | 431 | ops.len = buf.length; |
433 | if (!databuf) | 432 | ops.ooblen = mtd->oobsize; |
433 | ops.ooboffs = buf.start & (mtd->oobsize - 1); | ||
434 | ops.datbuf = NULL; | ||
435 | ops.mode = MTD_OOB_PLACE; | ||
436 | |||
437 | if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs)) | ||
438 | return -EINVAL; | ||
439 | |||
440 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); | ||
441 | if (!ops.oobbuf) | ||
434 | return -ENOMEM; | 442 | return -ENOMEM; |
435 | 443 | ||
436 | if (copy_from_user(databuf, buf.ptr, buf.length)) { | 444 | if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) { |
437 | kfree(databuf); | 445 | kfree(ops.oobbuf); |
438 | return -EFAULT; | 446 | return -EFAULT; |
439 | } | 447 | } |
440 | 448 | ||
441 | ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf); | 449 | buf.start &= ~(mtd->oobsize - 1); |
450 | ret = mtd->write_oob(mtd, buf.start, &ops); | ||
442 | 451 | ||
443 | if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t))) | 452 | if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen, |
453 | sizeof(uint32_t))) | ||
444 | ret = -EFAULT; | 454 | ret = -EFAULT; |
445 | 455 | ||
446 | kfree(databuf); | 456 | kfree(ops.oobbuf); |
447 | break; | 457 | break; |
448 | 458 | ||
449 | } | 459 | } |
@@ -451,13 +461,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
451 | case MEMREADOOB: | 461 | case MEMREADOOB: |
452 | { | 462 | { |
453 | struct mtd_oob_buf buf; | 463 | struct mtd_oob_buf buf; |
454 | void *databuf; | 464 | struct mtd_oob_ops ops; |
455 | ssize_t retlen; | ||
456 | 465 | ||
457 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) | 466 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) |
458 | return -EFAULT; | 467 | return -EFAULT; |
459 | 468 | ||
460 | if (buf.length > 0x4096) | 469 | if (buf.length > 4096) |
461 | return -EINVAL; | 470 | return -EINVAL; |
462 | 471 | ||
463 | if (!mtd->read_oob) | 472 | if (!mtd->read_oob) |
@@ -465,22 +474,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
465 | else | 474 | else |
466 | ret = access_ok(VERIFY_WRITE, buf.ptr, | 475 | ret = access_ok(VERIFY_WRITE, buf.ptr, |
467 | buf.length) ? 0 : -EFAULT; | 476 | buf.length) ? 0 : -EFAULT; |
468 | |||
469 | if (ret) | 477 | if (ret) |
470 | return ret; | 478 | return ret; |
471 | 479 | ||
472 | databuf = kmalloc(buf.length, GFP_KERNEL); | 480 | ops.len = buf.length; |
473 | if (!databuf) | 481 | ops.ooblen = mtd->oobsize; |
482 | ops.ooboffs = buf.start & (mtd->oobsize - 1); | ||
483 | ops.datbuf = NULL; | ||
484 | ops.mode = MTD_OOB_PLACE; | ||
485 | |||
486 | if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs)) | ||
487 | return -EINVAL; | ||
488 | |||
489 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); | ||
490 | if (!ops.oobbuf) | ||
474 | return -ENOMEM; | 491 | return -ENOMEM; |
475 | 492 | ||
476 | ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); | 493 | buf.start &= ~(mtd->oobsize - 1); |
494 | ret = mtd->read_oob(mtd, buf.start, &ops); | ||
477 | 495 | ||
478 | if (put_user(retlen, (uint32_t __user *)argp)) | 496 | if (put_user(ops.retlen, (uint32_t __user *)argp)) |
479 | ret = -EFAULT; | 497 | ret = -EFAULT; |
480 | else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) | 498 | else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf, |
499 | ops.retlen)) | ||
481 | ret = -EFAULT; | 500 | ret = -EFAULT; |
482 | 501 | ||
483 | kfree(databuf); | 502 | kfree(ops.oobbuf); |
484 | break; | 503 | break; |
485 | } | 504 | } |
486 | 505 | ||