ext4fs write support

Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c
index 3298fee..77094c4 100644
--- a/common/cmd_ext4.c
+++ b/common/cmd_ext4.c
@@ -62,6 +62,10 @@
 
 uint64_t total_sector;
 uint64_t part_offset;
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static uint64_t part_size;
+static uint16_t cur_part = 1;
+#endif
 
 #define DOS_PART_MAGIC_OFFSET		0x1fe
 #define DOS_FS_TYPE_OFFSET		0x36
@@ -84,6 +88,143 @@
 	return 0;
 }
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static int ext4_register_device(block_dev_desc_t *dev_desc, int part_no)
+{
+	unsigned char buffer[SECTOR_SIZE];
+	disk_partition_t info;
+
+	if (!dev_desc->block_read)
+		return -1;
+
+	/* check if we have a MBR (on floppies we have only a PBR) */
+	if (dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) buffer) != 1) {
+		printf("** Can't read from device %d **\n", dev_desc->dev);
+		return -1;
+	}
+	if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
+	    buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
+		/* no signature found */
+		return -1;
+	}
+
+	/* First we assume there is a MBR */
+	if (!get_partition_info(dev_desc, part_no, &info)) {
+		part_offset = info.start;
+		cur_part = part_no;
+		part_size = info.size;
+	} else if ((strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],
+			    "FAT", 3) == 0) || (strncmp((char *)&buffer
+							[DOS_FS32_TYPE_OFFSET],
+							"FAT32", 5) == 0)) {
+		/* ok, we assume we are on a PBR only */
+		cur_part = 1;
+		part_offset = 0;
+	} else {
+		printf("** Partition %d not valid on device %d **\n",
+		       part_no, dev_desc->dev);
+		return -1;
+	}
+
+	return 0;
+}
+
+int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc,
+				char *const argv[])
+{
+	const char *filename = "/";
+	int part_length;
+	unsigned long part = 1;
+	int dev;
+	char *ep;
+	unsigned long ram_address;
+	unsigned long file_size;
+	disk_partition_t info;
+	struct ext_filesystem *fs;
+
+	if (argc < 6)
+		return cmd_usage(cmdtp);
+
+	dev = (int)simple_strtoul(argv[2], &ep, 16);
+	ext4_dev_desc = get_dev(argv[1], dev);
+	if (ext4_dev_desc == NULL) {
+		printf("Block device %s %d not supported\n", argv[1], dev);
+		return 1;
+	}
+	if (init_fs(ext4_dev_desc))
+		return 1;
+
+	fs = get_fs();
+	if (*ep) {
+		if (*ep != ':') {
+			puts("Invalid boot device, use `dev[:part]'\n");
+			goto fail;
+		}
+		part = simple_strtoul(++ep, NULL, 16);
+	}
+
+	/* get the filename */
+	filename = argv[3];
+
+	/* get the address in hexadecimal format (string to int) */
+	ram_address = simple_strtoul(argv[4], NULL, 16);
+
+	/* get the filesize in base 10 format */
+	file_size = simple_strtoul(argv[5], NULL, 10);
+
+	/* set the device as block device */
+	part_length = ext4fs_set_blk_dev(fs->dev_desc, part);
+	if (part_length == 0) {
+		printf("Bad partition - %s %d:%lu\n", argv[1], dev, part);
+		goto fail;
+	}
+
+	/* register the device and partition */
+	if (ext4_register_device(fs->dev_desc, part) != 0) {
+		printf("Unable to use %s %d:%lu for fattable\n",
+		       argv[1], dev, part);
+		goto fail;
+	}
+
+	/* get the partition information */
+	if (!get_partition_info(fs->dev_desc, part, &info)) {
+		total_sector = (info.size * info.blksz) / SECTOR_SIZE;
+		fs->total_sect = total_sector;
+	} else {
+		printf("error : get partition info\n");
+		goto fail;
+	}
+
+	/* mount the filesystem */
+	if (!ext4fs_mount(part_length)) {
+		printf("Bad ext4 partition %s %d:%lu\n", argv[1], dev, part);
+		goto fail;
+	}
+
+	/* start write */
+	if (ext4fs_write(filename, (unsigned char *)ram_address, file_size)) {
+		printf("** Error ext4fs_write() **\n");
+		goto fail;
+	}
+	ext4fs_close();
+	deinit_fs(fs->dev_desc);
+
+	return 0;
+
+fail:
+	ext4fs_close();
+	deinit_fs(fs->dev_desc);
+
+	return 1;
+}
+
+U_BOOT_CMD(ext4write, 6, 1, do_ext4_write,
+	"create a file in the root directory",
+	"<interface> <dev[:part]> [Absolute filename path] [Address] [sizebytes]\n"
+	"	  - create a file in / directory");
+
+#endif
+
 U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
 	   "list files in a directory (default /)",
 	   "<interface> <dev[:part]> [directory]\n"