+/*
+ * 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);
+ 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;
+}
+
+#ifdef CONFIG_MTD_PARTITIONS
+static int mtd_blkpg_ioctl(struct mtd_info *mtd,
+ struct blkpg_ioctl_arg __user *arg)
+{
+ struct blkpg_ioctl_arg a;
+ struct blkpg_partition p;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ /* Only master mtd device must be used to control partitions */
+ if (!mtd_is_master(mtd))
+ return -EINVAL;
+
+ if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
+ return -EFAULT;
+
+ if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+ return -EFAULT;
+
+ switch (a.op) {
+ case BLKPG_ADD_PARTITION:
+
+ return mtd_add_partition(mtd, p.devname, p.start, p.length);
+
+ case BLKPG_DEL_PARTITION:
+
+ if (p.pno < 0)
+ return -EINVAL;
+
+ return mtd_del_partition(mtd, p.pno);
+
+ default:
+ return -EINVAL;
+ }
+}
+#endif
+
+