diff options
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/mtdchar.c | 48 | ||||
-rw-r--r-- | drivers/mtd/nand/davinci_nand.c | 3 |
2 files changed, 48 insertions, 3 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a825002123c8..24d35ba62b84 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -477,6 +477,39 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, return ret; } +/* + * Copies (and truncates, if necessary) data from the larger struct, + * nand_ecclayout, to the smaller, deprecated layout struct, + * nand_ecclayout_user. This is necessary only to suppport the deprecated + * API ioctl ECCGETLAYOUT while allowing all new functionality to use + * nand_ecclayout flexibly (i.e. the struct may change size in new + * releases without requiring major rewrites). + */ +static int shrink_ecclayout(const struct nand_ecclayout *from, + struct nand_ecclayout_user *to) +{ + int i; + + if (!from || !to) + return -EINVAL; + + memset(to, 0, sizeof(*to)); + + to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES_OLD); + for (i = 0; i < to->eccbytes; i++) + to->eccpos[i] = from->eccpos[i]; + + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) { + if (from->oobfree[i].length == 0 && + from->oobfree[i].offset == 0) + break; + to->oobavail += from->oobfree[i].length; + to->oobfree[i] = from->oobfree[i]; + } + + return 0; +} + static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct mtd_file_info *mfi = file->private_data; @@ -812,14 +845,23 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) } #endif + /* This ioctl is being deprecated - it truncates the ecc layout */ case ECCGETLAYOUT: { + struct nand_ecclayout_user *usrlay; + if (!mtd->ecclayout) return -EOPNOTSUPP; - if (copy_to_user(argp, mtd->ecclayout, - sizeof(struct nand_ecclayout))) - return -EFAULT; + usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL); + if (!usrlay) + return -ENOMEM; + + shrink_ecclayout(mtd->ecclayout, usrlay); + + if (copy_to_user(argp, usrlay, sizeof(*usrlay))) + ret = -EFAULT; + kfree(usrlay); break; } diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 2ac7367afe77..70698e86e437 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -749,6 +749,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) * breaks userspace ioctl interface with mtd-utils. Once we * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used * for the 4KiB page chips. + * + * TODO: Note that nand_ecclayout has now been expanded and can + * hold plenty of OOB entries. */ dev_warn(&pdev->dev, "no 4-bit ECC support yet " "for 4KiB-page NAND\n"); |