fs: add filesystem switch libary, implement ls and fsload commands

Implement "ls" and "fsload" commands that act like {fat,ext2}{ls,load},
and transparently handle either file-system. This scheme could easily be
extended to other filesystem types; I only didn't do it for zfs because
I don't have any filesystems of that type to test with.

Replace the implementation of {fat,ext[24]}{ls,load} with this new code
too.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
diff --git a/common/Makefile b/common/Makefile
index eac6360..9e43322 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -90,11 +90,6 @@
 COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o
 COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o
 COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
-ifdef CONFIG_CMD_EXT4
-COBJS-y	+= cmd_ext_common.o
-else
-COBJS-$(CONFIG_CMD_EXT2) += cmd_ext_common.o
-endif
 COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o
 COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o
 COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o
@@ -104,6 +99,7 @@
 ifdef CONFIG_FPGA
 COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o
 endif
+COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o
 COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o
 COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o
 COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o
diff --git a/common/cmd_ext2.c b/common/cmd_ext2.c
index c27d9c7..06d0234 100644
--- a/common/cmd_ext2.c
+++ b/common/cmd_ext2.c
@@ -37,15 +37,11 @@
 /*
  * Ext2fs support
  */
-#include <common.h>
-#include <ext_common.h>
+#include <fs.h>
 
 int do_ext2ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	if (do_ext_ls(cmdtp, flag, argc, argv))
-		return -1;
-
-	return 0;
+	return do_ls(cmdtp, flag, argc, argv, FS_TYPE_EXT);
 }
 
 /******************************************************************************
@@ -53,10 +49,7 @@
  */
 int do_ext2load (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	if (do_ext_load(cmdtp, flag, argc, argv))
-		return -1;
-
-	return 0;
+	return do_fsload(cmdtp, flag, argc, argv, FS_TYPE_EXT);
 }
 
 U_BOOT_CMD(
diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c
index ca46561..237bc19 100644
--- a/common/cmd_ext4.c
+++ b/common/cmd_ext4.c
@@ -47,10 +47,10 @@
 #include <image.h>
 #include <linux/ctype.h>
 #include <asm/byteorder.h>
-#include <ext_common.h>
 #include <ext4fs.h>
 #include <linux/stat.h>
 #include <malloc.h>
+#include <fs.h>
 
 #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
 #include <usb.h>
@@ -59,18 +59,12 @@
 int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc,
 						char *const argv[])
 {
-	if (do_ext_load(cmdtp, flag, argc, argv))
-		return -1;
-
-	return 0;
+	return do_fsload(cmdtp, flag, argc, argv, FS_TYPE_EXT);
 }
 
 int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
-	if (do_ext_ls(cmdtp, flag, argc, argv))
-		return -1;
-
-	return 0;
+	return do_ls(cmdtp, flag, argc, argv, FS_TYPE_EXT);
 }
 
 #if defined(CONFIG_CMD_EXT4_WRITE)
diff --git a/common/cmd_ext_common.c b/common/cmd_ext_common.c
deleted file mode 100644
index 1952f4d..0000000
--- a/common/cmd_ext_common.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * (C) Copyright 2011 - 2012 Samsung Electronics
- * EXT2/4 filesystem implementation in Uboot by
- * Uma Shankar <uma.shankar@samsung.com>
- * Manjunatha C Achar <a.manjunatha@samsung.com>
- *
- * Ext4fs support
- * made from existing cmd_ext2.c file of Uboot
- *
- * (C) Copyright 2004
- * esd gmbh <www.esd-electronics.com>
- * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
- *
- * made from cmd_reiserfs by
- *
- * (C) Copyright 2003 - 2004
- * Sysgo Real-Time Solutions, AG <www.elinos.com>
- * Pavel Bartusek <pba@sysgo.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- */
-
-/*
- * Changelog:
- *	0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c
- *	        file in uboot. Added ext4fs ls load and write support.
- */
-
-#include <common.h>
-#include <part.h>
-#include <config.h>
-#include <command.h>
-#include <image.h>
-#include <linux/ctype.h>
-#include <asm/byteorder.h>
-#include <ext_common.h>
-#include <ext4fs.h>
-#include <linux/stat.h>
-#include <malloc.h>
-
-#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
-#include <usb.h>
-#endif
-
-#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION)
-#error DOS or EFI partition support must be selected
-#endif
-
-#define DOS_PART_MAGIC_OFFSET		0x1fe
-#define DOS_FS_TYPE_OFFSET		0x36
-#define DOS_FS32_TYPE_OFFSET		0x52
-
-int do_ext_load(cmd_tbl_t *cmdtp, int flag, int argc,
-						char *const argv[])
-{
-	char *filename = NULL;
-	int dev, part;
-	ulong addr = 0;
-	int filelen;
-	disk_partition_t info;
-	block_dev_desc_t *dev_desc;
-	char buf[12];
-	unsigned long count;
-	const char *addr_str;
-
-	count = 0;
-	addr = simple_strtoul(argv[3], NULL, 16);
-	filename = getenv("bootfile");
-	switch (argc) {
-	case 3:
-		addr_str = getenv("loadaddr");
-		if (addr_str != NULL)
-			addr = simple_strtoul(addr_str, NULL, 16);
-		else
-			addr = CONFIG_SYS_LOAD_ADDR;
-
-		break;
-	case 4:
-		break;
-	case 5:
-		filename = argv[4];
-		break;
-	case 6:
-		filename = argv[4];
-		count = simple_strtoul(argv[5], NULL, 16);
-		break;
-
-	default:
-		return cmd_usage(cmdtp);
-	}
-
-	if (!filename) {
-		puts("** No boot file defined **\n");
-		return 1;
-	}
-
-	part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1);
-	if (part < 0)
-		return 1;
-
-	dev = dev_desc->dev;
-	printf("Loading file \"%s\" from %s device %d%c%c\n",
-		filename, argv[1], dev,
-		part ? ':' : ' ', part ? part + '0' : ' ');
-
-	ext4fs_set_blk_dev(dev_desc, &info);
-
-	if (!ext4fs_mount(info.size)) {
-		printf("** Bad ext2 partition or disk - %s %d:%d **\n",
-		       argv[1], dev, part);
-		ext4fs_close();
-		goto fail;
-	}
-
-	filelen = ext4fs_open(filename);
-	if (filelen < 0) {
-		printf("** File not found %s\n", filename);
-		ext4fs_close();
-		goto fail;
-	}
-	if ((count < filelen) && (count != 0))
-		filelen = count;
-
-	if (ext4fs_read((char *)addr, filelen) != filelen) {
-		printf("** Unable to read \"%s\" from %s %d:%d **\n",
-		       filename, argv[1], dev, part);
-		ext4fs_close();
-		goto fail;
-	}
-
-	ext4fs_close();
-	/* Loading ok, update default load address */
-	load_addr = addr;
-
-	printf("%d bytes read\n", filelen);
-	sprintf(buf, "%X", filelen);
-	setenv("filesize", buf);
-
-	return 0;
-fail:
-	return 1;
-}
-
-int do_ext_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
-{
-	const char *filename = "/";
-	int dev;
-	int part;
-	block_dev_desc_t *dev_desc;
-	disk_partition_t info;
-
-	if (argc < 2)
-		return cmd_usage(cmdtp);
-
-	part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1);
-	if (part < 0)
-		return 1;
-
-	if (argc == 4)
-		filename = argv[3];
-
-	dev = dev_desc->dev;
-	ext4fs_set_blk_dev(dev_desc, &info);
-
-	if (!ext4fs_mount(info.size)) {
-		printf("** Bad ext2 partition or disk - %s %d:%d **\n",
-		       argv[1], dev, part);
-		ext4fs_close();
-		goto fail;
-	}
-
-	if (ext4fs_ls(filename)) {
-		printf("** Error extfs_ls() **\n");
-		ext4fs_close();
-		goto fail;
-	};
-
-	ext4fs_close();
-	return 0;
-
-fail:
-	return 1;
-}
diff --git a/common/cmd_fat.c b/common/cmd_fat.c
index c38302d..c865d6d 100644
--- a/common/cmd_fat.c
+++ b/common/cmd_fat.c
@@ -31,54 +31,11 @@
 #include <ata.h>
 #include <part.h>
 #include <fat.h>
-
+#include <fs.h>
 
 int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	long size;
-	unsigned long offset;
-	unsigned long count = 0;
-	unsigned long pos = 0;
-	char buf [12];
-	block_dev_desc_t *dev_desc=NULL;
-	disk_partition_t info;
-	int part, dev;
-
-	if (argc < 5) {
-		printf("usage: fatload <interface> [<dev[:part]>] "
-			"<addr> <filename> [bytes [pos]]\n");
-		return 1;
-	}
-
-	part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1);
-	if (part < 0)
-		return 1;
-
-	dev = dev_desc->dev;
-	if (fat_set_blk_dev(dev_desc, &info) != 0) {
-		printf("\n** Unable to use %s %d:%d for fatload **\n",
-			argv[1], dev, part);
-		return 1;
-	}
-	offset = simple_strtoul(argv[3], NULL, 16);
-	if (argc >= 6)
-		count = simple_strtoul(argv[5], NULL, 16);
-	if (argc >= 7)
-		pos = simple_strtoul(argv[6], NULL, 16);
-	size = file_fat_read_at(argv[4], pos, (unsigned char *)offset, count);
-
-	if(size==-1) {
-		printf("\n** Unable to read \"%s\" from %s %d:%d **\n",
-			argv[4], argv[1], dev, part);
-		return 1;
-	}
-
-	printf("\n%ld bytes read\n", size);
-
-	sprintf(buf, "%lX", size);
-	setenv("filesize", buf);
-
-	return 0;
+	return do_fsload(cmdtp, flag, argc, argv, FS_TYPE_FAT);
 }
 
 
@@ -96,34 +53,7 @@
 
 int do_fat_ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	char *filename = "/";
-	int ret, dev, part;
-	block_dev_desc_t *dev_desc=NULL;
-	disk_partition_t info;
-
-	if (argc < 2) {
-		printf("usage: fatls <interface> [<dev[:part]>] [directory]\n");
-		return 0;
-	}
-
-	part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1);
-	if (part < 0)
-		return 1;
-
-	dev = dev_desc->dev;
-	if (fat_set_blk_dev(dev_desc, &info) != 0) {
-		printf("\n** Unable to use %s %d:%d for fatls **\n",
-			argv[1], dev, part);
-		return 1;
-	}
-	if (argc == 4)
-		ret = file_fat_ls(argv[3]);
-	else
-		ret = file_fat_ls(filename);
-
-	if(ret!=0)
-		printf("No Fat FS detected\n");
-	return ret;
+	return do_ls(cmdtp, flag, argc, argv, FS_TYPE_FAT);
 }
 
 U_BOOT_CMD(
diff --git a/common/cmd_fs.c b/common/cmd_fs.c
new file mode 100644
index 0000000..296124b
--- /dev/null
+++ b/common/cmd_fs.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Inspired by cmd_ext_common.c, cmd_fat.c.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <fs.h>
+
+int do_fsload_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	return do_fsload(cmdtp, flag, argc, argv, FS_TYPE_ANY);
+}
+
+U_BOOT_CMD(
+	fsload,	7,	0,	do_fsload_wrapper,
+	"load binary file from a filesystem",
+	"<interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]\n"
+	"    - Load binary file 'filename' from partition 'part' on device\n"
+	"       type 'interface' instance 'dev' to address 'addr' in memory.\n"
+	"      'bytes' gives the size to load in bytes.\n"
+	"      If 'bytes' is 0 or omitted, the file is read until the end.\n"
+	"      'pos' gives the file byte position to start reading from.\n"
+	"      If 'pos' is 0 or omitted, the file is read from the start."
+);
+
+int do_ls_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	return do_ls(cmdtp, flag, argc, argv, FS_TYPE_ANY);
+}
+
+U_BOOT_CMD(
+	ls,	4,	1,	do_ls_wrapper,
+	"list files in a directory (default /)",
+	"<interface> [<dev[:part]> [directory]]\n"
+	"    - List files in directory 'directory' of partition 'part' on\n"
+	"      device type 'interface' instance 'dev'."
+);