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>
This commit is contained in:
Stephen Warren 2012-10-22 06:43:51 +00:00 committed by Tom Rini
parent 03e2ecf6b8
commit 045fa1e114
11 changed files with 483 additions and 298 deletions

View file

@ -260,7 +260,8 @@ LIBS-y += drivers/net/npe/libnpe.o
endif
LIBS-$(CONFIG_OF_EMBED) += dts/libdts.o
LIBS-y += arch/$(ARCH)/lib/lib$(ARCH).o
LIBS-y += fs/cbfs/libcbfs.o \
LIBS-y += fs/libfs.o \
fs/cbfs/libcbfs.o \
fs/cramfs/libcramfs.o \
fs/ext4/libext4fs.o \
fs/fat/libfat.o \

View file

@ -90,11 +90,6 @@ COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
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 @@ COBJS-$(CONFIG_CMD_FLASH) += cmd_flash.o
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

View file

@ -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_ext2ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
*/
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(

View file

@ -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)

View file

@ -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;
}

View file

@ -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 @@ U_BOOT_CMD(
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(

51
common/cmd_fs.c Normal file
View file

@ -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'."
);

47
fs/Makefile Normal file
View file

@ -0,0 +1,47 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
# Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
#
# See file CREDITS for list of people who contributed to this
# project.
#
# 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
#
include $(TOPDIR)/config.mk
LIB = $(obj)libfs.o
COBJS-y += fs.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
all: $(LIB)
$(LIB): $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

308
fs/fs.c Normal file
View file

@ -0,0 +1,308 @@
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* 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 <config.h>
#include <common.h>
#include <part.h>
#include <ext4fs.h>
#include <fat.h>
#include <fs.h>
static block_dev_desc_t *fs_dev_desc;
static disk_partition_t fs_partition;
static int fs_type = FS_TYPE_ANY;
static inline int fs_ls_unsupported(const char *dirname)
{
printf("** Unrecognized filesystem type **\n");
return -1;
}
static inline int fs_read_unsupported(const char *filename, ulong addr,
int offset, int len)
{
printf("** Unrecognized filesystem type **\n");
return -1;
}
#ifdef CONFIG_FS_FAT
static int fs_probe_fat(void)
{
return fat_set_blk_dev(fs_dev_desc, &fs_partition);
}
static void fs_close_fat(void)
{
}
#define fs_ls_fat file_fat_ls
static int fs_read_fat(const char *filename, ulong addr, int offset, int len)
{
int len_read;
len_read = file_fat_read_at(filename, offset,
(unsigned char *)addr, len);
if (len_read == -1) {
printf("** Unable to read file %s **\n", filename);
return -1;
}
return len_read;
}
#else
static inline int fs_probe_fat(void)
{
return -1;
}
static inline void fs_close_fat(void)
{
}
#define fs_ls_fat fs_ls_unsupported
#define fs_read_fat fs_read_unsupported
#endif
#ifdef CONFIG_FS_EXT4
static int fs_probe_ext(void)
{
ext4fs_set_blk_dev(fs_dev_desc, &fs_partition);
if (!ext4fs_mount(fs_partition.size)) {
ext4fs_close();
return -1;
}
return 0;
}
static void fs_close_ext(void)
{
ext4fs_close();
}
#define fs_ls_ext ext4fs_ls
static int fs_read_ext(const char *filename, ulong addr, int offset, int len)
{
int file_len;
int len_read;
if (offset != 0) {
printf("** Cannot support non-zero offset **\n");
return -1;
}
file_len = ext4fs_open(filename);
if (file_len < 0) {
printf("** File not found %s **\n", filename);
ext4fs_close();
return -1;
}
if (len == 0)
len = file_len;
len_read = ext4fs_read((char *)addr, len);
ext4fs_close();
if (len_read != len) {
printf("** Unable to read file %s **\n", filename);
return -1;
}
return len_read;
}
#else
static inline int fs_probe_ext(void)
{
return -1;
}
static inline void fs_close_ext(void)
{
}
#define fs_ls_ext fs_ls_unsupported
#define fs_read_ext fs_read_unsupported
#endif
static const struct {
int fstype;
int (*probe)(void);
} fstypes[] = {
{
.fstype = FS_TYPE_FAT,
.probe = fs_probe_fat,
},
{
.fstype = FS_TYPE_EXT,
.probe = fs_probe_ext,
},
};
int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
{
int part, i;
part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
&fs_partition, 1);
if (part < 0)
return -1;
for (i = 0; i < ARRAY_SIZE(fstypes); i++) {
if ((fstype != FS_TYPE_ANY) && (fstype != fstypes[i].fstype))
continue;
if (!fstypes[i].probe()) {
fs_type = fstypes[i].fstype;
return 0;
}
}
printf("** Unrecognized filesystem type **\n");
return -1;
}
static void fs_close(void)
{
switch (fs_type) {
case FS_TYPE_FAT:
fs_close_fat();
break;
case FS_TYPE_EXT:
fs_close_ext();
break;
default:
break;
}
fs_type = FS_TYPE_ANY;
}
int fs_ls(const char *dirname)
{
int ret;
switch (fs_type) {
case FS_TYPE_FAT:
ret = fs_ls_fat(dirname);
break;
case FS_TYPE_EXT:
ret = fs_ls_ext(dirname);
break;
default:
ret = fs_ls_unsupported(dirname);
break;
}
fs_close();
return ret;
}
int fs_read(const char *filename, ulong addr, int offset, int len)
{
int ret;
switch (fs_type) {
case FS_TYPE_FAT:
ret = fs_read_fat(filename, addr, offset, len);
break;
case FS_TYPE_EXT:
ret = fs_read_ext(filename, addr, offset, len);
break;
default:
ret = fs_read_unsupported(filename, addr, offset, len);
break;
}
fs_close();
return ret;
}
int do_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype)
{
unsigned long addr;
const char *addr_str;
const char *filename;
unsigned long bytes;
unsigned long pos;
int len_read;
char buf[12];
if (argc < 5)
return CMD_RET_USAGE;
if (fs_set_blk_dev(argv[1], argv[2], fstype))
return 1;
if (argc >= 4) {
addr = simple_strtoul(argv[3], NULL, 0);
} else {
addr_str = getenv("loadaddr");
if (addr_str != NULL)
addr = simple_strtoul(addr_str, NULL, 16);
else
addr = CONFIG_SYS_LOAD_ADDR;
}
if (argc >= 5) {
filename = argv[4];
} else {
filename = getenv("bootfile");
if (!filename) {
puts("** No boot file defined **\n");
return 1;
}
}
if (argc >= 6)
bytes = simple_strtoul(argv[5], NULL, 0);
else
bytes = 0;
if (argc >= 7)
pos = simple_strtoul(argv[6], NULL, 0);
else
pos = 0;
len_read = fs_read(filename, addr, pos, bytes);
if (len_read <= 0)
return 1;
printf("%d bytes read\n", len_read);
sprintf(buf, "0x%x", len_read);
setenv("filesize", buf);
return 0;
}
int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype)
{
if (argc < 2)
return CMD_RET_USAGE;
if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
return 1;
if (fs_ls(argc == 4 ? argv[3] : "/"))
return 1;
return 0;
}

View file

@ -195,7 +195,4 @@ int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc,
int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[]);
int do_ext_load(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[]);
int do_ext_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
#endif

65
include/fs.h Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* 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/>.
*/
#ifndef _FS_H
#define _FS_H
#include <common.h>
#define FS_TYPE_ANY 0
#define FS_TYPE_FAT 1
#define FS_TYPE_EXT 2
/*
* Tell the fs layer which block device an partition to use for future
* commands. This also internally identifies the filesystem that is present
* within the partition. The identification process may be limited to a
* specific filesystem type by passing FS_* in the fstype parameter.
*
* Returns 0 on success.
* Returns non-zero if there is an error accessing the disk or partition, or
* no known filesystem type could be recognized on it.
*/
int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype);
/*
* Print the list of files on the partition previously set by fs_set_blk_dev(),
* in directory "dirname".
*
* Returns 0 on success. Returns non-zero on error.
*/
int fs_ls(const char *dirname);
/*
* Read file "filename" from the partition previously set by fs_set_blk_dev(),
* to address "addr", starting at byte offset "offset", and reading "len"
* bytes. "offset" may be 0 to read from the start of the file. "len" may be
* 0 to read the entire file. Note that not all filesystem types support
* either/both offset!=0 or len!=0.
*
* Returns number of bytes read on success. Returns <= 0 on error.
*/
int fs_read(const char *filename, ulong addr, int offset, int len);
/*
* Common implementation for various filesystem commands, optionally limited
* to a specific filesystem type via the fstype parameter.
*/
int do_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype);
int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype);
#endif /* _FS_H */