@@ -22,6 +22,12 @@
#include <asm/uaccess.h>
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#define MTD_PART_DEV_NUM 0x0000FFFF
+#define MTD_PART_FLAGS 0xFFFF0000
+#endif
+
#define MTD_INODE_FS_MAGIC 0x11307854
static struct vfsmount *mtd_inode_mnt __read_mostly;
@@ -471,7 +477,15 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
int ret = 0;
u_long size;
struct mtd_info_user info;
-
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *pmtd;
+ struct mtd_partition *pmtd1;
+ struct mtd_partition free;
+ struct mtd_info *pinfo1;
+ struct mtd_info *pinfo2;
+ struct user_mtd *ppart = NULL;
+ struct user_mtd_info upart;
+#endif
DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
@@ -825,6 +839,117 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
}
file->f_pos = 0;
break;
+#ifdef CONFIG_MTD_PARTITIONS
+
+ case MTDPARTITIONCREATE:
+ {
+ u_int64_t uoffset = 0;
+ u_int64_t usize = 0;
+ u_int32_t i;
+
+ if (copy_from_user(&upart, argp,
+ sizeof(struct user_mtd_info))) {
+ ret = -EFAULT;
+ break;
+ }
+ ppart = kzalloc(sizeof(struct user_mtd)*
+ upart.num_partitions
+ , GFP_KERNEL);
+ pmtd = kzalloc(sizeof(struct mtd_partition)*
+ upart.num_partitions,
+ GFP_KERNEL);
+ pmtd1 = pmtd;
+ if (ppart == NULL) {
+ ret = -EFAULT;
+ break;
+ }
+ if (copy_from_user(ppart,
+ upart.pst_user_partitions,
+ sizeof(struct user_mtd)*
+ upart.num_partitions)) {
+ ret = -EFAULT;
+ break;
+ }
+ for (i = 0; i < upart.num_partitions; i++) {
+ pmtd->name = ppart->name;
+ pmtd->size =
+ ppart->partition_size;
+ usize += pmtd->size;
+ pmtd->offset =
+ ppart->partition_offset;
+ uoffset += pmtd->offset;
+ pmtd->mask_flags =
+ ppart->partition_mask;
+
+ ppart++;
+ pmtd++;
+ }
+ add_mtd_partitions(mtd, pmtd1,
+ upart.num_partitions);
+ if ((mtd->size - usize) > 0) {
+ free.name = "FREE";
+ free.size = mtd->size - usize;
+ free.offset = usize;
+ free.mask_flags = 0;
+ add_mtd_partitions(mtd, &free, 1);
+ }
+ kfree(pmtd1);
+ break;
+ }
+ case MTDPARTITIONDELETE:
+ {
+ u_int32_t mtd_num;
+
+ if (copy_from_user(&mtd_num, argp,
+ sizeof(mtd_num))) {
+ ret = -EFAULT;
+ break;
+ }
+ pinfo1 = get_mtd_device(NULL,
+ mtd_num);
+
+ if (pinfo1 != NULL) {
+ put_mtd_device(pinfo1);
+ del_mtd_device(pinfo1);
+ }
+ break;
+ }
+ case MTDPARTITIONSETPERMISSION:
+ {
+ u_int32_t flags;
+ int dev_num;
+
+ if (copy_from_user(&flags, argp,
+ sizeof(flags))) {
+ ret = -EFAULT;
+ break;
+ }
+ dev_num = (flags & MTD_PART_DEV_NUM);
+ flags = (flags & MTD_PART_FLAGS) >> 16;
+ pinfo1 = get_mtd_device(NULL, dev_num);
+ pinfo1->flags = flags;
+ break;
+ }
+ case MTDPARTITIONMERGE:
+ {
+ u_int8_t part_num[2];
+
+ if (copy_from_user(part_num, argp, 2)) {
+ ret = -EFAULT;
+ break;
+ }
+ pinfo1 = get_mtd_device(NULL, part_num[0]);
+ pinfo2 = get_mtd_device(NULL, part_num[1]);
+ if ((pinfo1 != NULL) &&
+ (pinfo2 != NULL)) {
+ pinfo1->size += pinfo2->size;
+ put_mtd_device(pinfo2);
+ del_mtd_device(pinfo2);
+ }
+ break;
+ }
+#endif
+
}
default:
@@ -30,6 +30,19 @@ struct mtd_oob_buf64 {
__u64 usr_ptr;
};
+struct user_mtd {
+ char name[32];
+ __u64 partition_size;
+ __u64 partition_offset;
+ __u32 partition_mask;
+};
+
+struct user_mtd_info {
+ struct user_mtd *pst_user_partitions;
+ __u32 num_partitions;
+};
+
+
#define MTD_ABSENT 0
#define MTD_RAM 1
#define MTD_ROM 2
@@ -110,7 +123,10 @@ struct otp_info {
#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64)
#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64)
-
+#define MTDPARTITIONCREATE _IOW('M', 23, int)
+#define MTDPARTITIONDELETE _IOW('M', 24, int)
+#define MTDPARTITIONSETPERMISSION _IOW('M', 26, int)
+#define MTDPARTITIONMERGE _IOW('M', 27, int)
/*
* Obsolete legacy interface. Keep it in order not to break userspace
* interfaces