summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Nikolaus Schaller <hns@goldelico.com>2013-01-10 16:42:11 +0100
committerH. Nikolaus Schaller <hns@goldelico.com>2013-01-10 16:42:11 +0100
commit1d18c95643416cc9f1577755922e6593b508e8da (patch)
tree3d30910058cbfbddc388357d29307aaa0a615e90
parent2f7f1bd2415b74d98cfb8e0a0cd5e6436261de4a (diff)
downloadbootable_bootloader_goldelico_gta04-1d18c95643416cc9f1577755922e6593b508e8da.zip
bootable_bootloader_goldelico_gta04-1d18c95643416cc9f1577755922e6593b508e8da.tar.gz
bootable_bootloader_goldelico_gta04-1d18c95643416cc9f1577755922e6593b508e8da.tar.bz2
made ext4 and new general ls/load commands work
-rw-r--r--u-boot/Makefile3
-rw-r--r--u-boot/common/Makefile2
-rwxr-xr-x[-rw-r--r--]u-boot/common/cmd_fat.c193
-rwxr-xr-xu-boot/common/cmd_fs.c53
-rw-r--r--u-boot/common/cmd_jffs2.c12
-rwxr-xr-x[-rw-r--r--]u-boot/disk/part.c365
-rwxr-xr-x[-rw-r--r--]u-boot/disk/part_dos.c80
-rwxr-xr-x[-rw-r--r--]u-boot/disk/part_dos.h9
-rw-r--r--u-boot/fs/Makefile27
-rwxr-xr-x[-rw-r--r--]u-boot/fs/fat/fat.c531
-rwxr-xr-xu-boot/fs/fat/fat_write.c1098
-rwxr-xr-x[-rw-r--r--]u-boot/fs/fat/file.c0
-rwxr-xr-xu-boot/fs/fs.c334
-rw-r--r--u-boot/include/common.h87
-rw-r--r--u-boot/include/config_defaults.h1
-rw-r--r--u-boot/include/configs/omap3_beagle.h2
-rw-r--r--u-boot/include/configs/omap3_gta04.h14
-rwxr-xr-x[-rw-r--r--]u-boot/include/fat.h32
-rwxr-xr-xu-boot/include/fs.h65
-rwxr-xr-x[-rw-r--r--]u-boot/include/part.h44
20 files changed, 2459 insertions, 493 deletions
diff --git a/u-boot/Makefile b/u-boot/Makefile
index dc2e3d8..ca4b915 100644
--- a/u-boot/Makefile
+++ b/u-boot/Makefile
@@ -193,8 +193,9 @@ ifeq ($(CPU),ixp)
LIBS += arch/arm/cpu/ixp/npe/libnpe.o
endif
LIBS += arch/$(ARCH)/lib/lib$(ARCH).o
+LIBS += fs/fs.o
LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \
- fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \
+ fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/ext4/libext4fs.o fs/yaffs2/libyaffs2.o \
fs/ubifs/libubifs.o
LIBS += net/libnet.o
LIBS += disk/libdisk.o
diff --git a/u-boot/common/Makefile b/u-boot/common/Makefile
index 048df0c..121a47f 100644
--- a/u-boot/common/Makefile
+++ b/u-boot/common/Makefile
@@ -89,7 +89,9 @@ COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o
COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o
COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o
+COBJS-$(CONFIG_CMD_FS) += cmd_fs.o
COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
+COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o
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
diff --git a/u-boot/common/cmd_fat.c b/u-boot/common/cmd_fat.c
index 0220494..86be044 100644..100755
--- a/u-boot/common/cmd_fat.c
+++ b/u-boot/common/cmd_fat.c
@@ -31,146 +31,57 @@
#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;
- char buf [12];
- block_dev_desc_t *dev_desc=NULL;
- int dev=0;
- int part=1;
- char *ep;
-
- if (argc < 5) {
- printf( "usage: fatload <interface> <dev[:part]> "
- "<addr> <filename> [bytes]\n");
- return 1;
- }
-
- dev = (int)simple_strtoul(argv[2], &ep, 16);
- dev_desc = get_dev(argv[1],dev);
- if (dev_desc == NULL) {
- puts("\n** Invalid boot device **\n");
- return 1;
- }
- if (*ep) {
- if (*ep != ':') {
- puts("\n** Invalid boot device, use `dev[:part]' **\n");
- return 1;
- }
- part = (int)simple_strtoul(++ep, NULL, 16);
- }
- if (fat_register_device(dev_desc,part)!=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);
- else
- count = 0;
- size = file_fat_read(argv[4], (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_load(cmdtp, flag, argc, argv, FS_TYPE_FAT, 16);
}
U_BOOT_CMD(
- fatload, 6, 0, do_fat_fsload,
+ fatload, 7, 0, do_fat_fsload,
"load binary file from a dos filesystem",
- "<interface> <dev[:part]> <addr> <filename> [bytes]\n"
- " - load binary file 'filename' from 'dev' on 'interface'\n"
- " to address 'addr' from dos filesystem"
+ "<interface> [<dev[:part]>] <addr> <filename> [bytes [pos]]\n"
+ " - Load binary file 'filename' from 'dev' on 'interface'\n"
+ " to address 'addr' from dos filesystem.\n"
+ " 'pos' gives the file position to start loading from.\n"
+ " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
+ " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
+ " the load stops on end of file.\n"
+ " All numeric parameters are assumed to be hex."
);
-int do_fat_ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *filename = "/";
- int ret;
- int dev=0;
- int part=1;
- char *ep;
- block_dev_desc_t *dev_desc=NULL;
-
- if (argc < 3) {
- printf("usage: fatls <interface> <dev[:part]> [directory]\n");
- return 0;
- }
- dev = (int)simple_strtoul(argv[2], &ep, 16);
- dev_desc = get_dev(argv[1],dev);
- if (dev_desc == NULL) {
- puts("\n** Invalid boot device **\n");
- return 1;
- }
- if (*ep) {
- if (*ep != ':') {
- puts("\n** Invalid boot device, use `dev[:part]' **\n");
- return 1;
- }
- part = (int)simple_strtoul(++ep, NULL, 16);
- }
- if (fat_register_device(dev_desc,part)!=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(
fatls, 4, 1, do_fat_ls,
"list files in a directory (default /)",
- "<interface> <dev[:part]> [directory]\n"
+ "<interface> [<dev[:part]>] [directory]\n"
" - list files from 'dev' on 'interface' in a 'directory'"
);
-int do_fat_fsinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_fat_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
{
- int dev=0;
- int part=1;
- char *ep;
- block_dev_desc_t *dev_desc=NULL;
+ int dev, part;
+ block_dev_desc_t *dev_desc;
+ disk_partition_t info;
if (argc < 2) {
- printf("usage: fatinfo <interface> <dev[:part]>\n");
+ printf("usage: fatinfo <interface> [<dev[:part]>]\n");
return 0;
}
- dev = (int)simple_strtoul(argv[2], &ep, 16);
- dev_desc = get_dev(argv[1],dev);
- if (dev_desc == NULL) {
- puts("\n** Invalid boot device **\n");
+
+ part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1);
+ if (part < 0)
return 1;
- }
- if (*ep) {
- if (*ep != ':') {
- puts("\n** Invalid boot device, use `dev[:part]' **\n");
- return 1;
- }
- part = (int)simple_strtoul(++ep, NULL, 16);
- }
- if (fat_register_device(dev_desc,part)!=0) {
+
+ dev = dev_desc->dev;
+ if (fat_set_blk_dev(dev_desc, &info) != 0) {
printf("\n** Unable to use %s %d:%d for fatinfo **\n",
argv[1], dev, part);
return 1;
@@ -181,6 +92,56 @@ int do_fat_fsinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
U_BOOT_CMD(
fatinfo, 3, 1, do_fat_fsinfo,
"print information about filesystem",
- "<interface> <dev[:part]>\n"
+ "<interface> [<dev[:part]>]\n"
" - print information about filesystem from 'dev' on 'interface'"
);
+
+#ifdef CONFIG_FAT_WRITE
+static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ long size;
+ unsigned long addr;
+ unsigned long count;
+ block_dev_desc_t *dev_desc = NULL;
+ disk_partition_t info;
+ int dev = 0;
+ int part = 1;
+
+ if (argc < 5)
+ return cmd_usage(cmdtp);
+
+ 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 fatwrite **\n",
+ argv[1], dev, part);
+ return 1;
+ }
+ addr = simple_strtoul(argv[3], NULL, 16);
+ count = simple_strtoul(argv[5], NULL, 16);
+
+ size = file_fat_write(argv[4], (void *)addr, count);
+ if (size == -1) {
+ printf("\n** Unable to write \"%s\" from %s %d:%d **\n",
+ argv[4], argv[1], dev, part);
+ return 1;
+ }
+
+ printf("%ld bytes written\n", size);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ fatwrite, 6, 0, do_fat_fswrite,
+ "write file into a dos filesystem",
+ "<interface> <dev[:part]> <addr> <filename> <bytes>\n"
+ " - write file 'filename' from the address 'addr' in RAM\n"
+ " to 'dev' on 'interface'"
+);
+#endif
diff --git a/u-boot/common/cmd_fs.c b/u-boot/common/cmd_fs.c
new file mode 100755
index 0000000..a681d03
--- /dev/null
+++ b/u-boot/common/cmd_fs.c
@@ -0,0 +1,53 @@
+/*
+ * 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_load_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return do_load(cmdtp, flag, argc, argv, FS_TYPE_ANY, 0);
+}
+
+U_BOOT_CMD(
+ load, 7, 0, do_load_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.\n"
+ " All numeric parameters are assumed to be decimal,\n"
+ " unless specified otherwise using a leading \"0x\"."
+);
+
+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'."
+);
diff --git a/u-boot/common/cmd_jffs2.c b/u-boot/common/cmd_jffs2.c
index 27296dd..5843de8 100644
--- a/u-boot/common/cmd_jffs2.c
+++ b/u-boot/common/cmd_jffs2.c
@@ -617,21 +617,21 @@ int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/***************************************************/
U_BOOT_CMD(
- fsload, 3, 0, do_jffs2_fsload,
- "load binary file from a filesystem image",
+ jcload, 3, 0, do_jffs2_fsload,
+ "load binary file from a JFFS2/CRAMFS filesystem image",
"[ off ] [ filename ]\n"
" - load binary file from flash bank\n"
" with offset 'off'"
);
U_BOOT_CMD(
- ls, 2, 1, do_jffs2_ls,
- "list files in a directory (default /)",
+ jcls, 2, 1, do_jffs2_ls,
+ "list files in a JFFS2/CRAMFS directory (default /)",
"[ directory ]"
);
U_BOOT_CMD(
- fsinfo, 1, 1, do_jffs2_fsinfo,
- "print information about filesystems",
+ jcinfo, 1, 1, do_jffs2_fsinfo,
+ "print information about JFFS2/CRAMFS filesystems",
""
);
/***************************************************/
diff --git a/u-boot/disk/part.c b/u-boot/disk/part.c
index 13723f2..4646f68 100644..100755
--- a/u-boot/disk/part.c
+++ b/u-boot/disk/part.c
@@ -24,6 +24,7 @@
#include <common.h>
#include <command.h>
#include <ide.h>
+#include <malloc.h>
#include <part.h>
#undef PART_DEBUG
@@ -34,13 +35,15 @@
#define PRINTF(fmt,args...)
#endif
+/* Rather than repeat this expression each time, add a define for it */
#if (defined(CONFIG_CMD_IDE) || \
- defined(CONFIG_CMD_MG_DISK) || \
defined(CONFIG_CMD_SATA) || \
defined(CONFIG_CMD_SCSI) || \
defined(CONFIG_CMD_USB) || \
defined(CONFIG_MMC) || \
defined(CONFIG_SYSTEMACE) )
+#define HAVE_BLOCK_DEVICE
+#endif
struct block_drvr {
char *name;
@@ -66,25 +69,26 @@ static const struct block_drvr block_drvr[] = {
#if defined(CONFIG_SYSTEMACE)
{ .name = "ace", .get_dev = systemace_get_dev, },
#endif
-#if defined(CONFIG_CMD_MG_DISK)
- { .name = "mgd", .get_dev = mg_disk_get_dev, },
-#endif
{ },
};
DECLARE_GLOBAL_DATA_PTR;
-block_dev_desc_t *get_dev(char* ifname, int dev)
+#ifdef HAVE_BLOCK_DEVICE
+block_dev_desc_t *get_dev(const char *ifname, int dev)
{
const struct block_drvr *drvr = block_drvr;
block_dev_desc_t* (*reloc_get_dev)(int dev);
char *name;
+ if (!ifname)
+ return NULL;
+
name = drvr->name;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
name += gd->reloc_off;
#endif
- while (name) {
+ while (drvr->name) {
name = drvr->name;
reloc_get_dev = drvr->get_dev;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
@@ -98,19 +102,13 @@ block_dev_desc_t *get_dev(char* ifname, int dev)
return NULL;
}
#else
-block_dev_desc_t *get_dev(char* ifname, int dev)
+block_dev_desc_t *get_dev(const char *ifname, int dev)
{
return NULL;
}
#endif
-#if (defined(CONFIG_CMD_IDE) || \
- defined(CONFIG_CMD_MG_DISK) || \
- defined(CONFIG_CMD_SATA) || \
- defined(CONFIG_CMD_SCSI) || \
- defined(CONFIG_CMD_USB) || \
- defined(CONFIG_MMC) || \
- defined(CONFIG_SYSTEMACE) )
+#ifdef HAVE_BLOCK_DEVICE
/* ------------------------------------------------------------------------- */
/*
@@ -240,19 +238,7 @@ void dev_print (block_dev_desc_t *dev_desc)
}
#endif
-#if (defined(CONFIG_CMD_IDE) || \
- defined(CONFIG_CMD_MG_DISK) || \
- defined(CONFIG_CMD_SATA) || \
- defined(CONFIG_CMD_SCSI) || \
- defined(CONFIG_CMD_USB) || \
- defined(CONFIG_MMC) || \
- defined(CONFIG_SYSTEMACE) )
-
-#if defined(CONFIG_MAC_PARTITION) || \
- defined(CONFIG_DOS_PARTITION) || \
- defined(CONFIG_ISO_PARTITION) || \
- defined(CONFIG_AMIGA_PARTITION) || \
- defined(CONFIG_EFI_PARTITION)
+#ifdef HAVE_BLOCK_DEVICE
void init_part (block_dev_desc_t * dev_desc)
{
@@ -291,63 +277,15 @@ void init_part (block_dev_desc_t * dev_desc)
return;
}
#endif
+ dev_desc->part_type = PART_TYPE_UNKNOWN;
}
-int get_partition_info (block_dev_desc_t *dev_desc, int part
- , disk_partition_t *info)
-{
- switch (dev_desc->part_type) {
-#ifdef CONFIG_MAC_PARTITION
- case PART_TYPE_MAC:
- if (get_partition_info_mac(dev_desc,part,info) == 0) {
- PRINTF ("## Valid MAC partition found ##\n");
- return (0);
- }
- break;
-#endif
-
-#ifdef CONFIG_DOS_PARTITION
- case PART_TYPE_DOS:
- if (get_partition_info_dos(dev_desc,part,info) == 0) {
- PRINTF ("## Valid DOS partition found ##\n");
- return (0);
- }
- break;
-#endif
-
-#ifdef CONFIG_ISO_PARTITION
- case PART_TYPE_ISO:
- if (get_partition_info_iso(dev_desc,part,info) == 0) {
- PRINTF ("## Valid ISO boot partition found ##\n");
- return (0);
- }
- break;
-#endif
-
-#ifdef CONFIG_AMIGA_PARTITION
- case PART_TYPE_AMIGA:
- if (get_partition_info_amiga(dev_desc, part, info) == 0)
- {
- PRINTF ("## Valid Amiga partition found ##\n");
- return (0);
- }
- break;
-#endif
-
-#ifdef CONFIG_EFI_PARTITION
- case PART_TYPE_EFI:
- if (get_partition_info_efi(dev_desc,part,info) == 0) {
- PRINTF ("## Valid EFI partition found ##\n");
- return (0);
- }
- break;
-#endif
- default:
- break;
- }
- return (-1);
-}
+#if defined(CONFIG_MAC_PARTITION) || \
+ defined(CONFIG_DOS_PARTITION) || \
+ defined(CONFIG_ISO_PARTITION) || \
+ defined(CONFIG_AMIGA_PARTITION) || \
+ defined(CONFIG_EFI_PARTITION)
static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
{
@@ -382,6 +320,8 @@ static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
dev_desc->dev, type);
}
+#endif /* any CONFIG_..._PARTITION */
+
void print_part (block_dev_desc_t * dev_desc)
{
@@ -428,11 +368,266 @@ void print_part (block_dev_desc_t * dev_desc)
puts ("## Unknown partition table\n");
}
+#endif /* HAVE_BLOCK_DEVICE */
-#else /* neither MAC nor DOS nor ISO nor AMIGA nor EFI partition configured */
-# error neither CONFIG_MAC_PARTITION nor CONFIG_DOS_PARTITION
-# error nor CONFIG_ISO_PARTITION nor CONFIG_AMIGA_PARTITION
-# error nor CONFIG_EFI_PARTITION configured!
+int get_partition_info(block_dev_desc_t *dev_desc, int part
+ , disk_partition_t *info)
+{
+#ifdef HAVE_BLOCK_DEVICE
+
+#ifdef CONFIG_PARTITION_UUIDS
+ /* The common case is no UUID support */
+ info->uuid[0] = 0;
#endif
+ switch (dev_desc->part_type) {
+#ifdef CONFIG_MAC_PARTITION
+ case PART_TYPE_MAC:
+ if (get_partition_info_mac(dev_desc, part, info) == 0) {
+ PRINTF("## Valid MAC partition found ##\n");
+ return 0;
+ }
+ break;
#endif
+
+#ifdef CONFIG_DOS_PARTITION
+ case PART_TYPE_DOS:
+ if (get_partition_info_dos(dev_desc, part, info) == 0) {
+ PRINTF("## Valid DOS partition found ##\n");
+ return 0;
+ }
+ break;
+#endif
+
+#ifdef CONFIG_ISO_PARTITION
+ case PART_TYPE_ISO:
+ if (get_partition_info_iso(dev_desc, part, info) == 0) {
+ PRINTF("## Valid ISO boot partition found ##\n");
+ return 0;
+ }
+ break;
+#endif
+
+#ifdef CONFIG_AMIGA_PARTITION
+ case PART_TYPE_AMIGA:
+ if (get_partition_info_amiga(dev_desc, part, info) == 0) {
+ PRINTF("## Valid Amiga partition found ##\n");
+ return 0;
+ }
+ break;
+#endif
+
+#ifdef CONFIG_EFI_PARTITION
+ case PART_TYPE_EFI:
+ if (get_partition_info_efi(dev_desc, part, info) == 0) {
+ PRINTF("## Valid EFI partition found ##\n");
+ return 0;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+#endif /* HAVE_BLOCK_DEVICE */
+
+ return -1;
+}
+
+int get_device(const char *ifname, const char *dev_str,
+ block_dev_desc_t **dev_desc)
+{
+ char *ep;
+ int dev;
+
+ dev = simple_strtoul(dev_str, &ep, 16);
+ if (*ep) {
+ printf("** Bad device specification %s %s **\n",
+ ifname, dev_str);
+ return -1;
+ }
+
+ *dev_desc = get_dev(ifname, dev);
+ if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
+ printf("** Bad device %s %s **\n", ifname, dev_str);
+ return -1;
+ }
+
+ return dev;
+}
+
+#define PART_UNSPECIFIED -2
+#define PART_AUTO -1
+#define MAX_SEARCH_PARTITIONS 16
+int get_device_and_partition(const char *ifname, const char *dev_part_str,
+ block_dev_desc_t **dev_desc,
+ disk_partition_t *info, int allow_whole_dev)
+{
+ int ret = -1;
+ const char *part_str;
+ char *dup_str = NULL;
+ const char *dev_str;
+ int dev;
+ char *ep;
+ int p;
+ int part;
+ disk_partition_t tmpinfo;
+
+ /* If no dev_part_str, use bootdevice environment variable */
+ if (!dev_part_str || !strlen(dev_part_str) ||
+ !strcmp(dev_part_str, "-"))
+ dev_part_str = getenv("bootdevice");
+
+ /* If still no dev_part_str, it's an error */
+ if (!dev_part_str) {
+ printf("** No device specified **\n");
+ goto cleanup;
+ }
+
+ /* Separate device and partition ID specification */
+ part_str = strchr(dev_part_str, ':');
+ if (part_str) {
+ dup_str = strdup(dev_part_str);
+ dup_str[part_str - dev_part_str] = 0;
+ dev_str = dup_str;
+ part_str++;
+ } else {
+ dev_str = dev_part_str;
+ }
+
+ /* Look up the device */
+ dev = get_device(ifname, dev_str, dev_desc);
+ if (dev < 0)
+ goto cleanup;
+
+ /* Convert partition ID string to number */
+ if (!part_str || !*part_str) {
+ part = PART_UNSPECIFIED;
+ } else if (!strcmp(part_str, "auto")) {
+ part = PART_AUTO;
+ } else {
+ /* Something specified -> use exactly that */
+ part = (int)simple_strtoul(part_str, &ep, 16);
+ /*
+ * Less than whole string converted,
+ * or request for whole device, but caller requires partition.
+ */
+ if (*ep || (part == 0 && !allow_whole_dev)) {
+ printf("** Bad partition specification %s %s **\n",
+ ifname, dev_part_str);
+ goto cleanup;
+ }
+ }
+
+ /*
+ * No partition table on device,
+ * or user requested partition 0 (entire device).
+ */
+ if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
+ (part == 0)) {
+ if (!(*dev_desc)->lba) {
+ printf("** Bad device size - %s %s **\n", ifname,
+ dev_str);
+ goto cleanup;
+ }
+
+ /*
+ * If user specified a partition ID other than 0,
+ * or the calling command only accepts partitions,
+ * it's an error.
+ */
+ if ((part > 0) || (!allow_whole_dev)) {
+ printf("** No partition table - %s %s **\n", ifname,
+ dev_str);
+ goto cleanup;
+ }
+
+ info->start = 0;
+ info->size = (*dev_desc)->lba;
+ info->blksz = (*dev_desc)->blksz;
+ info->bootable = 0;
+ strcpy((char *)info->type, BOOT_PART_TYPE);
+ strcpy((char *)info->name, "Whole Disk");
+#ifdef CONFIG_PARTITION_UUIDS
+ info->uuid[0] = 0;
+#endif
+
+ ret = 0;
+ goto cleanup;
+ }
+
+ /*
+ * Now there's known to be a partition table,
+ * not specifying a partition means to pick partition 1.
+ */
+ if (part == PART_UNSPECIFIED)
+ part = 1;
+
+ /*
+ * If user didn't specify a partition number, or did specify something
+ * other than "auto", use that partition number directly.
+ */
+ if (part != PART_AUTO) {
+ ret = get_partition_info(*dev_desc, part, info);
+ if (ret) {
+ printf("** Invalid partition %d **\n", part);
+ goto cleanup;
+ }
+ } else {
+ /*
+ * Find the first bootable partition.
+ * If none are bootable, fall back to the first valid partition.
+ */
+ part = 0;
+ for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+ ret = get_partition_info(*dev_desc, p, info);
+ if (ret)
+ continue;
+
+ /*
+ * First valid partition, or new better partition?
+ * If so, save partition ID.
+ */
+ if (!part || info->bootable)
+ part = p;
+
+ /* Best possible partition? Stop searching. */
+ if (info->bootable)
+ break;
+
+ /*
+ * We now need to search further for best possible.
+ * If we what we just queried was the best so far,
+ * save the info since we over-write it next loop.
+ */
+ if (part == p)
+ tmpinfo = *info;
+ }
+ /* If we found any acceptable partition */
+ if (part) {
+ /*
+ * If we searched all possible partition IDs,
+ * return the first valid partition we found.
+ */
+ if (p == MAX_SEARCH_PARTITIONS + 1)
+ *info = tmpinfo;
+ } else {
+ printf("** No valid partitions found **\n");
+ ret = -1;
+ goto cleanup;
+ }
+ }
+ if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
+ printf("** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n",
+ info->type);
+ ret = -1;
+ goto cleanup;
+ }
+
+ ret = part;
+ goto cleanup;
+
+cleanup:
+ free(dup_str);
+ return ret;
+}
diff --git a/u-boot/disk/part_dos.c b/u-boot/disk/part_dos.c
index 2de1bb8..3fe901b 100644..100755
--- a/u-boot/disk/part_dos.c
+++ b/u-boot/disk/part_dos.c
@@ -36,7 +36,6 @@
#include "part_dos.h"
#if defined(CONFIG_CMD_IDE) || \
- defined(CONFIG_CMD_MG_DISK) || \
defined(CONFIG_CMD_SATA) || \
defined(CONFIG_CMD_SCSI) || \
defined(CONFIG_CMD_USB) || \
@@ -61,14 +60,21 @@ static inline int is_extended(int part_type)
part_type == 0x85);
}
-static void print_one_part (dos_partition_t *p, int ext_part_sector, int part_num)
+static inline int is_bootable(dos_partition_t *p)
+{
+ return p->boot_ind == 0x80;
+}
+
+static void print_one_part(dos_partition_t *p, int ext_part_sector,
+ int part_num, unsigned int disksig)
{
int lba_start = ext_part_sector + le32_to_int (p->start4);
int lba_size = le32_to_int (p->size4);
- printf ("%5d\t\t%10d\t%10d\t%2x%s\n",
- part_num, lba_start, lba_size, p->sys_ind,
- (is_extended (p->sys_ind) ? " Extd" : ""));
+ printf("%3d\t%-10d\t%-10d\t%08x-%02x\t%02x%s%s\n",
+ part_num, lba_start, lba_size, disksig, part_num, p->sys_ind,
+ (is_extended(p->sys_ind) ? " Extd" : ""),
+ (is_bootable(p) ? " Boot" : ""));
}
static int test_block_type(unsigned char *buffer)
@@ -87,22 +93,24 @@ static int test_block_type(unsigned char *buffer)
int test_part_dos (block_dev_desc_t *dev_desc)
{
- unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
- if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) buffer) != 1) ||
- (buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) ||
- (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) {
- return (-1);
- }
- return (0);
+ if (dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) buffer) != 1)
+ return -1;
+
+ if (test_block_type(buffer) != DOS_MBR)
+ return -1;
+
+ return 0;
}
/* Print a partition that is relative to its Extended partition table
*/
-static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_sector, int relative,
- int part_num)
+static void print_partition_extended(block_dev_desc_t *dev_desc,
+ int ext_part_sector, int relative,
+ int part_num, unsigned int disksig)
{
- unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
dos_partition_t *pt;
int i;
@@ -112,17 +120,16 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s
return;
}
i=test_block_type(buffer);
- if(i==-1) {
+ if (i != DOS_MBR) {
printf ("bad MBR sector signature 0x%02x%02x\n",
buffer[DOS_PART_MAGIC_OFFSET],
buffer[DOS_PART_MAGIC_OFFSET + 1]);
return;
}
- if(i==DOS_PBR) {
- printf (" 1\t\t 0\t%10ld\t%2x\n",
- dev_desc->lba, buffer[DOS_PBR_MEDIA_TYPE_OFFSET]);
- return;
- }
+
+ if (!ext_part_sector)
+ disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]);
+
/* Print all primary/logical partitions */
pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
for (i = 0; i < 4; i++, pt++) {
@@ -133,7 +140,7 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s
if ((pt->sys_ind != 0) &&
(ext_part_sector == 0 || !is_extended (pt->sys_ind)) ) {
- print_one_part (pt, ext_part_sector, part_num);
+ print_one_part(pt, ext_part_sector, part_num, disksig);
}
/* Reverse engr the fdisk part# assignment rule! */
@@ -149,10 +156,9 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s
if (is_extended (pt->sys_ind)) {
int lba_start = le32_to_int (pt->start4) + relative;
- print_partition_extended (dev_desc, lba_start,
- ext_part_sector == 0 ? lba_start
- : relative,
- part_num);
+ print_partition_extended(dev_desc, lba_start,
+ ext_part_sector == 0 ? lba_start : relative,
+ part_num, disksig);
}
}
@@ -164,9 +170,10 @@ static void print_partition_extended (block_dev_desc_t *dev_desc, int ext_part_s
*/
static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part_sector,
int relative, int part_num,
- int which_part, disk_partition_t *info)
+ int which_part, disk_partition_t *info,
+ unsigned int disksig)
{
- unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
dos_partition_t *pt;
int i;
@@ -183,6 +190,11 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part
return -1;
}
+#ifdef CONFIG_PARTITION_UUIDS
+ if (!ext_part_sector)
+ disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]);
+#endif
+
/* Print all primary/logical partitions */
pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
for (i = 0; i < 4; i++, pt++) {
@@ -223,6 +235,10 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part
}
/* sprintf(info->type, "%d, pt->sys_ind); */
sprintf ((char *)info->type, "U-Boot");
+ info->bootable = is_bootable(pt);
+#ifdef CONFIG_PARTITION_UUIDS
+ sprintf(info->uuid, "%08x-%02x", disksig, part_num);
+#endif
return 0;
}
@@ -241,7 +257,7 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part
return get_partition_info_extended (dev_desc, lba_start,
ext_part_sector == 0 ? lba_start : relative,
- part_num, which_part, info);
+ part_num, which_part, info, disksig);
}
}
return -1;
@@ -249,13 +265,13 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part
void print_part_dos (block_dev_desc_t *dev_desc)
{
- printf ("Partition Start Sector Num Sectors Type\n");
- print_partition_extended (dev_desc, 0, 0, 1);
+ printf("Part\tStart Sector\tNum Sectors\tUUID\t\tType\n");
+ print_partition_extended(dev_desc, 0, 0, 1, 0);
}
int get_partition_info_dos (block_dev_desc_t *dev_desc, int part, disk_partition_t * info)
{
- return get_partition_info_extended (dev_desc, 0, 0, 1, part, info);
+ return get_partition_info_extended(dev_desc, 0, 0, 1, part, info, 0);
}
diff --git a/u-boot/disk/part_dos.h b/u-boot/disk/part_dos.h
index 195a32c..7b77c1d 100644..100755
--- a/u-boot/disk/part_dos.h
+++ b/u-boot/disk/part_dos.h
@@ -24,14 +24,7 @@
#ifndef _DISK_PART_DOS_H
#define _DISK_PART_DOS_H
-
-#ifdef CONFIG_ISO_PARTITION
-/* Make the buffers bigger if ISO partition support is enabled -- CD-ROMS
- have 2048 byte blocks */
-#define DEFAULT_SECTOR_SIZE 2048
-#else
-#define DEFAULT_SECTOR_SIZE 512
-#endif
+#define DOS_PART_DISKSIG_OFFSET 0x1b8
#define DOS_PART_TBL_OFFSET 0x1be
#define DOS_PART_MAGIC_OFFSET 0x1fe
#define DOS_PBR_FSTYPE_OFFSET 0x36
diff --git a/u-boot/fs/Makefile b/u-boot/fs/Makefile
index 22aad12..bd72111 100644
--- a/u-boot/fs/Makefile
+++ b/u-boot/fs/Makefile
@@ -22,8 +22,21 @@
#
#
+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)
+
subdirs-$(CONFIG_CMD_CRAMFS) := cramfs
subdirs-$(CONFIG_CMD_EXT2) += ext2
+subdirs-$(CONFIG_CMD_EXT4) += ext4
subdirs-$(CONFIG_CMD_FAT) += fat
subdirs-$(CONFIG_CMD_FDOS) += fdos
subdirs-$(CONFIG_CMD_JFFS2) += jffs2
@@ -31,8 +44,16 @@ subdirs-$(CONFIG_CMD_REISER) += reiserfs
subdirs-$(CONFIG_YAFFS2) += yaffs2
subdirs-$(CONFIG_CMD_UBIFS) += ubifs
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
SUBDIRS := $(subdirs-y)
-$(obj).depend all:
- @for dir in $(SUBDIRS) ; do \
- $(MAKE) -C $$dir $@ ; done
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/u-boot/fs/fat/fat.c b/u-boot/fs/fat/fat.c
index a75e4f2..393c378 100644..100755
--- a/u-boot/fs/fat/fat.c
+++ b/u-boot/fs/fat/fat.c
@@ -27,14 +27,17 @@
#include <common.h>
#include <config.h>
+#include <exports.h>
#include <fat.h>
#include <asm/byteorder.h>
#include <part.h>
+#include <malloc.h>
+#include <linux/compiler.h>
/*
* Convert a string to lowercase.
*/
-static void downcase (char *str)
+static void downcase(char *str)
{
while (*str != '\0') {
TOLOWER(*str);
@@ -42,99 +45,85 @@ static void downcase (char *str)
}
}
-static block_dev_desc_t *cur_dev = NULL;
+static block_dev_desc_t *cur_dev;
+static disk_partition_t cur_part_info;
-static unsigned long part_offset = 0;
-
-static int cur_part = 1;
-
-#define DOS_PART_TBL_OFFSET 0x1be
-#define DOS_PART_MAGIC_OFFSET 0x1fe
+#define DOS_BOOT_MAGIC_OFFSET 0x1fe
#define DOS_FS_TYPE_OFFSET 0x36
#define DOS_FS32_TYPE_OFFSET 0x52
-static int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr)
+static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
{
- if (cur_dev == NULL)
+ if (!cur_dev || !cur_dev->block_read)
return -1;
- startblock += part_offset;
-
- if (cur_dev->block_read) {
- return cur_dev->block_read(cur_dev->dev, startblock, getsize,
- (unsigned long *) bufptr);
- }
- return -1;
+ return cur_dev->block_read(cur_dev->dev,
+ cur_part_info.start + block, nr_blocks, buf);
}
-int fat_register_device (block_dev_desc_t * dev_desc, int part_no)
+int fat_set_blk_dev(block_dev_desc_t *dev_desc, disk_partition_t *info)
{
- unsigned char buffer[SECTOR_SIZE];
-
- disk_partition_t info;
-
- if (!dev_desc->block_read)
- return -1;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
cur_dev = dev_desc;
- /* 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 */
+ cur_part_info = *info;
+
+ /* Make sure it has a valid FAT header */
+ if (disk_read(0, 1, buffer) != 1) {
+ cur_dev = NULL;
return -1;
}
-#if (defined(CONFIG_CMD_IDE) || \
- defined(CONFIG_CMD_MG_DISK) || \
- defined(CONFIG_CMD_SATA) || \
- defined(CONFIG_CMD_SCSI) || \
- defined(CONFIG_CMD_USB) || \
- defined(CONFIG_MMC) || \
- defined(CONFIG_SYSTEMACE) )
- /* First we assume there is a MBR */
- if (!get_partition_info(dev_desc, part_no, &info)) {
- part_offset = info.start;
- cur_part = part_no;
- } 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);
+
+ /* Check if it's actually a DOS volume */
+ if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) {
+ cur_dev = NULL;
return -1;
}
-#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;
- info.start = part_offset;
- } else {
- /* FIXME we need to determine the start block of the
- * partition where the DOS FS resides. This can be done
- * by using the get_partition_info routine. For this
- * purpose the libpart must be included.
- */
- part_offset = 32;
- cur_part = 1;
- }
+ /* Check for FAT12/FAT16/FAT32 filesystem */
+ if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3))
+ return 0;
+ if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5))
+ return 0;
+
+ cur_dev = NULL;
+ return -1;
+}
+
+int fat_register_device(block_dev_desc_t *dev_desc, int part_no)
+{
+ disk_partition_t info;
+
+ /* First close any currently found FAT filesystem */
+ cur_dev = NULL;
+
+ /* Read the partition table, if present */
+ if (get_partition_info(dev_desc, part_no, &info)) {
+ if (part_no != 0) {
+ printf("** Partition %d not valid on device %d **\n",
+ part_no, dev_desc->dev);
+ return -1;
+ }
+
+ info.start = 0;
+ info.size = dev_desc->lba;
+ info.blksz = dev_desc->blksz;
+ info.name[0] = 0;
+ info.type[0] = 0;
+ info.bootable = 0;
+#ifdef CONFIG_PARTITION_UUIDS
+ info.uuid[0] = 0;
#endif
- return 0;
+ }
+
+ return fat_set_blk_dev(dev_desc, &info);
}
/*
* Get the first occurence of a directory delimiter ('/' or '\') in a string.
* Return index into string if found, -1 otherwise.
*/
-static int dirdelim (char *str)
+static int dirdelim(char *str)
{
char *start = str;
@@ -149,7 +138,7 @@ static int dirdelim (char *str)
/*
* Extract zero terminated short name from a directory entry.
*/
-static void get_name (dir_entry *dirent, char *s_name)
+static void get_name(dir_entry *dirent, char *s_name)
{
char *ptr;
@@ -178,7 +167,7 @@ static void get_name (dir_entry *dirent, char *s_name)
* Get the entry at index 'entry' in a FAT (12/16/32) table.
* On failure 0x00 is returned.
*/
-static __u32 get_fatent (fsdata *mydata, __u32 entry)
+static __u32 get_fatent(fsdata *mydata, __u32 entry)
{
__u32 bufnum;
__u32 off16, offset;
@@ -209,16 +198,16 @@ static __u32 get_fatent (fsdata *mydata, __u32 entry)
/* Read a new block of FAT entries into the cache. */
if (bufnum != mydata->fatbufnum) {
- int getsize = FATBUFSIZE / FS_BLOCK_SIZE;
+ __u32 getsize = FATBUFBLOCKS;
__u8 *bufptr = mydata->fatbuf;
__u32 fatlength = mydata->fatlength;
__u32 startblock = bufnum * FATBUFBLOCKS;
- fatlength *= SECTOR_SIZE; /* We want it in bytes now */
+ if (startblock + getsize > fatlength)
+ getsize = fatlength - startblock;
+
startblock += mydata->fat_sect; /* Offset from start of disk */
- if (getsize > fatlength)
- getsize = fatlength;
if (disk_read(startblock, getsize, bufptr) < 0) {
debug("Error reading FAT blocks\n");
return ret;
@@ -276,11 +265,11 @@ static __u32 get_fatent (fsdata *mydata, __u32 entry)
* Return 0 on success, -1 otherwise.
*/
static int
-get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer,
- unsigned long size)
+get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
{
- int idx = 0;
+ __u32 idx = 0;
__u32 startsect;
+ int ret;
if (clustnum > 0) {
startsect = mydata->data_begin +
@@ -291,50 +280,122 @@ get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer,
debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
- if (disk_read(startsect, size / FS_BLOCK_SIZE, buffer) < 0) {
- debug("Error reading data\n");
- return -1;
+ if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
+ ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
+
+ printf("FAT: Misaligned buffer address (%p)\n", buffer);
+
+ while (size >= mydata->sect_size) {
+ ret = disk_read(startsect++, 1, tmpbuf);
+ if (ret != 1) {
+ debug("Error reading data (got %d)\n", ret);
+ return -1;
+ }
+
+ memcpy(buffer, tmpbuf, mydata->sect_size);
+ buffer += mydata->sect_size;
+ size -= mydata->sect_size;
+ }
+ } else {
+ idx = size / mydata->sect_size;
+ ret = disk_read(startsect, idx, buffer);
+ if (ret != idx) {
+ debug("Error reading data (got %d)\n", ret);
+ return -1;
+ }
+ startsect += idx;
+ idx *= mydata->sect_size;
+ buffer += idx;
+ size -= idx;
}
- if (size % FS_BLOCK_SIZE) {
- __u8 tmpbuf[FS_BLOCK_SIZE];
+ if (size) {
+ ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
- idx = size / FS_BLOCK_SIZE;
- if (disk_read(startsect + idx, 1, tmpbuf) < 0) {
- debug("Error reading data\n");
+ ret = disk_read(startsect, 1, tmpbuf);
+ if (ret != 1) {
+ debug("Error reading data (got %d)\n", ret);
return -1;
}
- buffer += idx * FS_BLOCK_SIZE;
- memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE);
- return 0;
+ memcpy(buffer, tmpbuf, size);
}
return 0;
}
/*
- * Read at most 'maxsize' bytes from the file associated with 'dentptr'
+ * Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr'
* into 'buffer'.
* Return the number of bytes read or -1 on fatal errors.
*/
+__u8 get_contents_vfatname_block[MAX_CLUSTSIZE]
+ __aligned(ARCH_DMA_MINALIGN);
+
static long
-get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
- unsigned long maxsize)
+get_contents(fsdata *mydata, dir_entry *dentptr, unsigned long pos,
+ __u8 *buffer, unsigned long maxsize)
{
unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
- unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE;
+ unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
__u32 curclust = START(dentptr);
__u32 endclust, newclust;
unsigned long actsize;
debug("Filesize: %ld bytes\n", filesize);
- if (maxsize > 0 && filesize > maxsize)
- filesize = maxsize;
+ if (pos >= filesize) {
+ debug("Read position past EOF: %lu\n", pos);
+ return gotsize;
+ }
+
+ if (maxsize > 0 && filesize > pos + maxsize)
+ filesize = pos + maxsize;
debug("%ld bytes\n", filesize);
actsize = bytesperclust;
+
+ /* go to cluster at pos */
+ while (actsize <= pos) {
+ curclust = get_fatent(mydata, curclust);
+ if (CHECK_CLUST(curclust, mydata->fatsize)) {
+ debug("curclust: 0x%x\n", curclust);
+ debug("Invalid FAT entry\n");
+ return gotsize;
+ }
+ actsize += bytesperclust;
+ }
+
+ /* actsize > pos */
+ actsize -= bytesperclust;
+ filesize -= actsize;
+ pos -= actsize;
+
+ /* align to beginning of next cluster if any */
+ if (pos) {
+ actsize = min(filesize, bytesperclust);
+ if (get_cluster(mydata, curclust, get_contents_vfatname_block,
+ (int)actsize) != 0) {
+ printf("Error reading cluster\n");
+ return -1;
+ }
+ filesize -= actsize;
+ actsize -= pos;
+ memcpy(buffer, get_contents_vfatname_block + pos, actsize);
+ gotsize += actsize;
+ if (!filesize)
+ return gotsize;
+ buffer += actsize;
+
+ curclust = get_fatent(mydata, curclust);
+ if (CHECK_CLUST(curclust, mydata->fatsize)) {
+ debug("curclust: 0x%x\n", curclust);
+ debug("Invalid FAT entry\n");
+ return gotsize;
+ }
+ }
+
+ actsize = bytesperclust;
endclust = curclust;
do {
@@ -352,21 +413,9 @@ get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
actsize += bytesperclust;
}
- /* actsize >= file size */
- actsize -= bytesperclust;
-
- /* get remaining clusters */
- if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
- printf("Error reading cluster\n");
- return -1;
- }
-
/* get remaining bytes */
- gotsize += (int)actsize;
- filesize -= actsize;
- buffer += actsize;
actsize = filesize;
- if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
+ if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
printf("Error reading cluster\n");
return -1;
}
@@ -398,7 +447,7 @@ getit:
* starting at l_name[*idx].
* Return 1 if terminator (zero byte) is found, 0 otherwise.
*/
-static int slot2str (dir_slot *slotptr, char *l_name, int *idx)
+static int slot2str(dir_slot *slotptr, char *l_name, int *idx)
{
int j;
@@ -430,19 +479,15 @@ static int slot2str (dir_slot *slotptr, char *l_name, int *idx)
* into 'retdent'
* Return 0 on success, -1 otherwise.
*/
-__attribute__ ((__aligned__ (__alignof__ (dir_entry))))
-__u8 get_vfatname_block[MAX_CLUSTSIZE];
-
static int
-get_vfatname (fsdata *mydata, int curclust, __u8 *cluster,
- dir_entry *retdent, char *l_name)
+get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
+ dir_entry *retdent, char *l_name)
{
dir_entry *realdent;
dir_slot *slotptr = (dir_slot *)retdent;
- __u8 *buflimit = cluster + ((curclust == 0) ?
- LINEAR_PREFETCH_SIZE :
- (mydata->clust_size * SECTOR_SIZE)
- );
+ __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
+ PREFETCH_BLOCKS :
+ mydata->clust_size);
__u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
int idx = 0;
@@ -472,13 +517,13 @@ get_vfatname (fsdata *mydata, int curclust, __u8 *cluster,
return -1;
}
- if (get_cluster(mydata, curclust, get_vfatname_block,
- mydata->clust_size * SECTOR_SIZE) != 0) {
+ if (get_cluster(mydata, curclust, get_contents_vfatname_block,
+ mydata->clust_size * mydata->sect_size) != 0) {
debug("Error: reading directory block\n");
return -1;
}
- slotptr2 = (dir_slot *)get_vfatname_block;
+ slotptr2 = (dir_slot *)get_contents_vfatname_block;
while (counter > 0) {
if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
& 0xff) != counter)
@@ -489,7 +534,7 @@ get_vfatname (fsdata *mydata, int curclust, __u8 *cluster,
/* Save the real directory entry */
realdent = (dir_entry *)slotptr2;
- while ((__u8 *)slotptr2 > get_vfatname_block) {
+ while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
slotptr2--;
slot2str(slotptr2, l_name, &idx);
}
@@ -518,15 +563,16 @@ get_vfatname (fsdata *mydata, int curclust, __u8 *cluster,
}
/* Calculate short name checksum */
-static __u8 mkcksum (const char *str)
+static __u8 mkcksum(const char name[8], const char ext[3])
{
int i;
__u8 ret = 0;
- for (i = 0; i < 11; i++) {
- ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + str[i];
- }
+ for (i = 0; i < sizeof(name); i++)
+ ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i];
+ for (i = 0; i < sizeof(ext); i++)
+ ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i];
return ret;
}
@@ -536,12 +582,12 @@ static __u8 mkcksum (const char *str)
* Get the directory entry associated with 'filename' from the directory
* starting at 'startsect'
*/
-__attribute__ ((__aligned__ (__alignof__ (dir_entry))))
-__u8 get_dentfromdir_block[MAX_CLUSTSIZE];
+__u8 get_dentfromdir_block[MAX_CLUSTSIZE]
+ __aligned(ARCH_DMA_MINALIGN);
-static dir_entry *get_dentfromdir (fsdata *mydata, int startsect,
- char *filename, dir_entry *retdent,
- int dols)
+static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
+ char *filename, dir_entry *retdent,
+ int dols)
{
__u16 prevcksum = 0xffff;
__u32 curclust = START(retdent);
@@ -555,7 +601,7 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect,
int i;
if (get_cluster(mydata, curclust, get_dentfromdir_block,
- mydata->clust_size * SECTOR_SIZE) != 0) {
+ mydata->clust_size * mydata->sect_size) != 0) {
debug("Error: reading directory block\n");
return NULL;
}
@@ -572,8 +618,8 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect,
}
if ((dentptr->attr & ATTR_VOLUME)) {
#ifdef CONFIG_SUPPORT_VFAT
- if ((dentptr->attr & ATTR_VFAT) &&
- (dentptr-> name[0] & LAST_LONG_ENTRY_MASK)) {
+ if ((dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
+ (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
prevcksum = ((dir_slot *)dentptr)->alias_checksum;
get_vfatname(mydata, curclust,
get_dentfromdir_block,
@@ -629,7 +675,9 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect,
return NULL;
}
#ifdef CONFIG_SUPPORT_VFAT
- if (dols && mkcksum(dentptr->name) == prevcksum) {
+ __u8 csum = mkcksum(dentptr->name, dentptr->ext);
+ if (dols && csum == prevcksum) {
+ prevcksum = 0xffff;
dentptr++;
continue;
}
@@ -700,17 +748,28 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect,
* Read boot sector and volume info from a FAT filesystem
*/
static int
-read_bootsectandvi (boot_sector *bs, volume_info *volinfo, int *fatsize)
+read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
{
- __u8 block[FS_BLOCK_SIZE];
-
+ __u8 *block;
volume_info *vistart;
+ int ret = 0;
- if (disk_read (0, 1, block) < 0) {
- debug("Error: reading block\n");
+ if (cur_dev == NULL) {
+ debug("Error: no device selected\n");
+ return -1;
+ }
+
+ block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz);
+ if (block == NULL) {
+ debug("Error: allocating block\n");
return -1;
}
+ if (disk_read(0, 1, block) < 0) {
+ debug("Error: reading block\n");
+ goto fail;
+ }
+
memcpy(bs, block, sizeof(boot_sector));
bs->reserved = FAT2CPU16(bs->reserved);
bs->fat_length = FAT2CPU16(bs->fat_length);
@@ -736,43 +795,48 @@ read_bootsectandvi (boot_sector *bs, volume_info *volinfo, int *fatsize)
if (*fatsize == 32) {
if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0)
- return 0;
+ goto exit;
} else {
if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) {
*fatsize = 12;
- return 0;
+ goto exit;
}
if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) {
*fatsize = 16;
- return 0;
+ goto exit;
}
}
debug("Error: broken fs_type sign\n");
- return -1;
+fail:
+ ret = -1;
+exit:
+ free(block);
+ return ret;
}
-__attribute__ ((__aligned__ (__alignof__ (dir_entry))))
-__u8 do_fat_read_block[MAX_CLUSTSIZE];
+__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
+ __aligned(ARCH_DMA_MINALIGN);
long
-do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
- int dols)
+do_fat_read_at(const char *filename, unsigned long pos, void *buffer,
+ unsigned long maxsize, int dols)
{
char fnamecopy[2048];
boot_sector bs;
volume_info volinfo;
fsdata datablock;
fsdata *mydata = &datablock;
- dir_entry *dentptr;
+ dir_entry *dentptr = NULL;
__u16 prevcksum = 0xffff;
char *subname = "";
- int cursect;
+ __u32 cursect;
int idx, isdir = 0;
int files = 0, dirs = 0;
- long ret = 0;
+ long ret = -1;
int firsttime;
- int root_cluster;
+ __u32 root_cluster = 0;
+ int rootdir_size = 0;
int j;
if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
@@ -780,36 +844,45 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
return -1;
}
- root_cluster = bs.root_cluster;
-
- if (mydata->fatsize == 32)
+ if (mydata->fatsize == 32) {
+ root_cluster = bs.root_cluster;
mydata->fatlength = bs.fat32_length;
- else
+ } else {
mydata->fatlength = bs.fat_length;
+ }
mydata->fat_sect = bs.reserved;
cursect = mydata->rootdir_sect
= mydata->fat_sect + mydata->fatlength * bs.fats;
+ mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
mydata->clust_size = bs.cluster_size;
+ if (mydata->sect_size != cur_part_info.blksz) {
+ printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n",
+ mydata->sect_size, cur_part_info.blksz);
+ return -1;
+ }
if (mydata->fatsize == 32) {
mydata->data_begin = mydata->rootdir_sect -
(mydata->clust_size * 2);
} else {
- int rootdir_size;
-
rootdir_size = ((bs.dir_entries[1] * (int)256 +
bs.dir_entries[0]) *
sizeof(dir_entry)) /
- SECTOR_SIZE;
+ mydata->sect_size;
mydata->data_begin = mydata->rootdir_sect +
rootdir_size -
(mydata->clust_size * 2);
}
mydata->fatbufnum = -1;
+ mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
+ if (mydata->fatbuf == NULL) {
+ debug("Error: allocating memory\n");
+ return -1;
+ }
#ifdef CONFIG_SUPPORT_VFAT
debug("VFAT Support enabled\n");
@@ -820,8 +893,9 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
"Data begins at: %d\n",
root_cluster,
mydata->rootdir_sect,
- mydata->rootdir_sect * SECTOR_SIZE, mydata->data_begin);
- debug("Cluster size: %d\n", mydata->clust_size);
+ mydata->rootdir_sect * mydata->sect_size, mydata->data_begin);
+ debug("Sector size: %d, cluster size: %d\n", mydata->sect_size,
+ mydata->clust_size);
/* "cwd" is always the root... */
while (ISDIRDELIM(*filename))
@@ -833,7 +907,7 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
if (*fnamecopy == '\0') {
if (!dols)
- return -1;
+ goto exit;
dols = LS_ROOT;
} else if ((idx = dirdelim(fnamecopy)) >= 0) {
@@ -852,40 +926,43 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
while (1) {
int i;
- debug("FAT read sect=%d, clust_size=%d, DIRENTSPERBLOCK=%d\n",
- cursect, mydata->clust_size, DIRENTSPERBLOCK);
+ if (j == 0) {
+ debug("FAT read sect=%d, clust_size=%d, DIRENTSPERBLOCK=%zd\n",
+ cursect, mydata->clust_size, DIRENTSPERBLOCK);
+
+ if (disk_read(cursect,
+ (mydata->fatsize == 32) ?
+ (mydata->clust_size) :
+ PREFETCH_BLOCKS,
+ do_fat_read_at_block) < 0) {
+ debug("Error: reading rootdir block\n");
+ goto exit;
+ }
- if (disk_read(cursect,
- (mydata->fatsize == 32) ?
- (mydata->clust_size) :
- LINEAR_PREFETCH_SIZE / SECTOR_SIZE,
- do_fat_read_block) < 0) {
- debug("Error: reading rootdir block\n");
- return -1;
+ dentptr = (dir_entry *) do_fat_read_at_block;
}
- dentptr = (dir_entry *) do_fat_read_block;
-
for (i = 0; i < DIRENTSPERBLOCK; i++) {
char s_name[14], l_name[VFAT_MAXLEN_BYTES];
+ __u8 csum;
l_name[0] = '\0';
if (dentptr->name[0] == DELETED_FLAG) {
dentptr++;
continue;
}
- if ((dentptr->attr & ATTR_VOLUME)) {
+
+ csum = mkcksum(dentptr->name, dentptr->ext);
+ if (dentptr->attr & ATTR_VOLUME) {
#ifdef CONFIG_SUPPORT_VFAT
- if ((dentptr->attr & ATTR_VFAT) &&
+ if ((dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
(dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
prevcksum =
((dir_slot *)dentptr)->alias_checksum;
get_vfatname(mydata,
- (mydata->fatsize == 32) ?
- root_cluster :
- 0,
- do_fat_read_block,
+ root_cluster,
+ do_fat_read_at_block,
dentptr, l_name);
if (dols == LS_ROOT) {
@@ -934,13 +1011,13 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
if (dols == LS_ROOT) {
printf("\n%d file(s), %d dir(s)\n\n",
files, dirs);
- return 0;
+ ret = 0;
}
- return -1;
+ goto exit;
}
#ifdef CONFIG_SUPPORT_VFAT
- else if (dols == LS_ROOT &&
- mkcksum(dentptr->name) == prevcksum) {
+ else if (dols == LS_ROOT && csum == prevcksum) {
+ prevcksum = 0xffff;
dentptr++;
continue;
}
@@ -988,7 +1065,7 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
}
if (isdir && !(dentptr->attr & ATTR_DIR))
- return -1;
+ goto exit;
debug("RootName: %s", s_name);
debug(", start: 0x%x", START(dentptr));
@@ -1006,26 +1083,40 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
* root directory clusters when a cluster has been
* completely processed.
*/
- if ((mydata->fatsize == 32) && (++j == mydata->clust_size)) {
- int nxtsect;
- int nxt_clust;
-
- nxt_clust = get_fatent(mydata, root_cluster);
+ ++j;
+ int rootdir_end = 0;
+ if (mydata->fatsize == 32) {
+ if (j == mydata->clust_size) {
+ int nxtsect = 0;
+ int nxt_clust = 0;
- nxtsect = mydata->data_begin +
- (nxt_clust * mydata->clust_size);
+ nxt_clust = get_fatent(mydata, root_cluster);
+ rootdir_end = CHECK_CLUST(nxt_clust, 32);
- debug("END LOOP: sect=%d, root_clust=%d, "
- "n_sect=%d, n_clust=%d\n",
- cursect, root_cluster,
- nxtsect, nxt_clust);
+ nxtsect = mydata->data_begin +
+ (nxt_clust * mydata->clust_size);
- root_cluster = nxt_clust;
+ root_cluster = nxt_clust;
- cursect = nxtsect;
- j = 0;
+ cursect = nxtsect;
+ j = 0;
+ }
} else {
- cursect++;
+ if (j == PREFETCH_BLOCKS)
+ j = 0;
+
+ rootdir_end = (++cursect - mydata->rootdir_sect >=
+ rootdir_size);
+ }
+
+ /* If end of rootdir reached */
+ if (rootdir_end) {
+ if (dols == LS_ROOT) {
+ printf("\n%d file(s), %d dir(s)\n\n",
+ files, dirs);
+ ret = 0;
+ }
+ goto exit;
}
}
rootdir_done:
@@ -1062,24 +1153,32 @@ rootdir_done:
if (get_dentfromdir(mydata, startsect, subname, dentptr,
isdir ? 0 : dols) == NULL) {
if (dols && !isdir)
- return 0;
- return -1;
+ ret = 0;
+ goto exit;
}
- if (idx >= 0) {
- if (!(dentptr->attr & ATTR_DIR))
- return -1;
+ if (isdir && !(dentptr->attr & ATTR_DIR))
+ goto exit;
+
+ if (idx >= 0)
subname = nextname;
- }
}
- ret = get_contents(mydata, dentptr, buffer, maxsize);
+ ret = get_contents(mydata, dentptr, pos, buffer, maxsize);
debug("Size: %d, got: %ld\n", FAT2CPU32(dentptr->size), ret);
+exit:
+ free(mydata->fatbuf);
return ret;
}
-int file_fat_detectfs (void)
+long
+do_fat_read(const char *filename, void *buffer, unsigned long maxsize, int dols)
+{
+ return do_fat_read_at(filename, 0, buffer, maxsize, dols);
+}
+
+int file_fat_detectfs(void)
{
boot_sector bs;
volume_info volinfo;
@@ -1092,7 +1191,6 @@ int file_fat_detectfs (void)
}
#if defined(CONFIG_CMD_IDE) || \
- defined(CONFIG_CMD_MG_DISK) || \
defined(CONFIG_CMD_SATA) || \
defined(CONFIG_CMD_SCSI) || \
defined(CONFIG_CMD_USB) || \
@@ -1137,19 +1235,24 @@ int file_fat_detectfs (void)
vol_label[11] = '\0';
volinfo.fs_type[5] = '\0';
- printf("Partition %d: Filesystem: %s \"%s\"\n", cur_part,
- volinfo.fs_type, vol_label);
+ printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label);
return 0;
}
-int file_fat_ls (const char *dir)
+int file_fat_ls(const char *dir)
{
return do_fat_read(dir, NULL, 0, LS_YES);
}
-long file_fat_read (const char *filename, void *buffer, unsigned long maxsize)
+long file_fat_read_at(const char *filename, unsigned long pos, void *buffer,
+ unsigned long maxsize)
{
printf("reading %s\n", filename);
- return do_fat_read(filename, buffer, maxsize, LS_NO);
+ return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO);
+}
+
+long file_fat_read(const char *filename, void *buffer, unsigned long maxsize)
+{
+ return file_fat_read_at(filename, 0, buffer, maxsize);
}
diff --git a/u-boot/fs/fat/fat_write.c b/u-boot/fs/fat/fat_write.c
new file mode 100755
index 0000000..4a1bda0
--- /dev/null
+++ b/u-boot/fs/fat/fat_write.c
@@ -0,0 +1,1098 @@
+/*
+ * fat_write.c
+ *
+ * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
+ *
+ * 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 <common.h>
+#include <command.h>
+#include <config.h>
+#include <fat.h>
+#include <asm/byteorder.h>
+#include <part.h>
+#include "fat.c"
+
+static void uppercase(char *str, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ TOUPPER(*str);
+ str++;
+ }
+}
+
+static int total_sector;
+static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
+{
+ if (!cur_dev || !cur_dev->block_write)
+ return -1;
+
+ if (cur_part_info.start + block + nr_blocks >
+ cur_part_info.start + total_sector) {
+ printf("error: overflow occurs\n");
+ return -1;
+ }
+
+ return cur_dev->block_write(cur_dev->dev,
+ cur_part_info.start + block, nr_blocks, buf);
+}
+
+/*
+ * Set short name in directory entry
+ */
+static void set_name(dir_entry *dirent, const char *filename)
+{
+ char s_name[VFAT_MAXLEN_BYTES];
+ char *period;
+ int period_location, len, i, ext_num;
+
+ if (filename == NULL)
+ return;
+
+ len = strlen(filename);
+ if (len == 0)
+ return;
+
+ memcpy(s_name, filename, len);
+ uppercase(s_name, len);
+
+ period = strchr(s_name, '.');
+ if (period == NULL) {
+ period_location = len;
+ ext_num = 0;
+ } else {
+ period_location = period - s_name;
+ ext_num = len - period_location - 1;
+ }
+
+ /* Pad spaces when the length of file name is shorter than eight */
+ if (period_location < 8) {
+ memcpy(dirent->name, s_name, period_location);
+ for (i = period_location; i < 8; i++)
+ dirent->name[i] = ' ';
+ } else if (period_location == 8) {
+ memcpy(dirent->name, s_name, period_location);
+ } else {
+ memcpy(dirent->name, s_name, 6);
+ dirent->name[6] = '~';
+ dirent->name[7] = '1';
+ }
+
+ if (ext_num < 3) {
+ memcpy(dirent->ext, s_name + period_location + 1, ext_num);
+ for (i = ext_num; i < 3; i++)
+ dirent->ext[i] = ' ';
+ } else
+ memcpy(dirent->ext, s_name + period_location + 1, 3);
+
+ debug("name : %s\n", dirent->name);
+ debug("ext : %s\n", dirent->ext);
+}
+
+static __u8 num_of_fats;
+/*
+ * Write fat buffer into block device
+ */
+static int flush_fat_buffer(fsdata *mydata)
+{
+ int getsize = FATBUFBLOCKS;
+ __u32 fatlength = mydata->fatlength;
+ __u8 *bufptr = mydata->fatbuf;
+ __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
+
+ fatlength *= mydata->sect_size;
+ startblock += mydata->fat_sect;
+
+ if (getsize > fatlength)
+ getsize = fatlength;
+
+ /* Write FAT buf */
+ if (disk_write(startblock, getsize, bufptr) < 0) {
+ debug("error: writing FAT blocks\n");
+ return -1;
+ }
+
+ if (num_of_fats == 2) {
+ /* Update corresponding second FAT blocks */
+ startblock += mydata->fatlength;
+ if (disk_write(startblock, getsize, bufptr) < 0) {
+ debug("error: writing second FAT blocks\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Get the entry at index 'entry' in a FAT (12/16/32) table.
+ * On failure 0x00 is returned.
+ * When bufnum is changed, write back the previous fatbuf to the disk.
+ */
+static __u32 get_fatent_value(fsdata *mydata, __u32 entry)
+{
+ __u32 bufnum;
+ __u32 off16, offset;
+ __u32 ret = 0x00;
+ __u16 val1, val2;
+
+ switch (mydata->fatsize) {
+ case 32:
+ bufnum = entry / FAT32BUFSIZE;
+ offset = entry - bufnum * FAT32BUFSIZE;
+ break;
+ case 16:
+ bufnum = entry / FAT16BUFSIZE;
+ offset = entry - bufnum * FAT16BUFSIZE;
+ break;
+ case 12:
+ bufnum = entry / FAT12BUFSIZE;
+ offset = entry - bufnum * FAT12BUFSIZE;
+ break;
+
+ default:
+ /* Unsupported FAT size */
+ return ret;
+ }
+
+ debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
+ mydata->fatsize, entry, entry, offset, offset);
+
+ /* Read a new block of FAT entries into the cache. */
+ if (bufnum != mydata->fatbufnum) {
+ int getsize = FATBUFBLOCKS;
+ __u8 *bufptr = mydata->fatbuf;
+ __u32 fatlength = mydata->fatlength;
+ __u32 startblock = bufnum * FATBUFBLOCKS;
+
+ if (getsize > fatlength)
+ getsize = fatlength;
+
+ fatlength *= mydata->sect_size; /* We want it in bytes now */
+ startblock += mydata->fat_sect; /* Offset from start of disk */
+
+ /* Write back the fatbuf to the disk */
+ if (mydata->fatbufnum != -1) {
+ if (flush_fat_buffer(mydata) < 0)
+ return -1;
+ }
+
+ if (disk_read(startblock, getsize, bufptr) < 0) {
+ debug("Error reading FAT blocks\n");
+ return ret;
+ }
+ mydata->fatbufnum = bufnum;
+ }
+
+ /* Get the actual entry from the table */
+ switch (mydata->fatsize) {
+ case 32:
+ ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
+ break;
+ case 16:
+ ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]);
+ break;
+ case 12:
+ off16 = (offset * 3) / 4;
+
+ switch (offset & 0x3) {
+ case 0:
+ ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]);
+ ret &= 0xfff;
+ break;
+ case 1:
+ val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
+ val1 &= 0xf000;
+ val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
+ val2 &= 0x00ff;
+ ret = (val2 << 4) | (val1 >> 12);
+ break;
+ case 2:
+ val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
+ val1 &= 0xff00;
+ val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
+ val2 &= 0x000f;
+ ret = (val2 << 8) | (val1 >> 8);
+ break;
+ case 3:
+ ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
+ ret = (ret & 0xfff0) >> 4;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ debug("FAT%d: ret: %08x, entry: %08x, offset: %04x\n",
+ mydata->fatsize, ret, entry, offset);
+
+ return ret;
+}
+
+#ifdef CONFIG_SUPPORT_VFAT
+/*
+ * Set the file name information from 'name' into 'slotptr',
+ */
+static int str2slot(dir_slot *slotptr, const char *name, int *idx)
+{
+ int j, end_idx = 0;
+
+ for (j = 0; j <= 8; j += 2) {
+ if (name[*idx] == 0x00) {
+ slotptr->name0_4[j] = 0;
+ slotptr->name0_4[j + 1] = 0;
+ end_idx++;
+ goto name0_4;
+ }
+ slotptr->name0_4[j] = name[*idx];
+ (*idx)++;
+ end_idx++;
+ }
+ for (j = 0; j <= 10; j += 2) {
+ if (name[*idx] == 0x00) {
+ slotptr->name5_10[j] = 0;
+ slotptr->name5_10[j + 1] = 0;
+ end_idx++;
+ goto name5_10;
+ }
+ slotptr->name5_10[j] = name[*idx];
+ (*idx)++;
+ end_idx++;
+ }
+ for (j = 0; j <= 2; j += 2) {
+ if (name[*idx] == 0x00) {
+ slotptr->name11_12[j] = 0;
+ slotptr->name11_12[j + 1] = 0;
+ end_idx++;
+ goto name11_12;
+ }
+ slotptr->name11_12[j] = name[*idx];
+ (*idx)++;
+ end_idx++;
+ }
+
+ if (name[*idx] == 0x00)
+ return 1;
+
+ return 0;
+/* Not used characters are filled with 0xff 0xff */
+name0_4:
+ for (; end_idx < 5; end_idx++) {
+ slotptr->name0_4[end_idx * 2] = 0xff;
+ slotptr->name0_4[end_idx * 2 + 1] = 0xff;
+ }
+ end_idx = 5;
+name5_10:
+ end_idx -= 5;
+ for (; end_idx < 6; end_idx++) {
+ slotptr->name5_10[end_idx * 2] = 0xff;
+ slotptr->name5_10[end_idx * 2 + 1] = 0xff;
+ }
+ end_idx = 11;
+name11_12:
+ end_idx -= 11;
+ for (; end_idx < 2; end_idx++) {
+ slotptr->name11_12[end_idx * 2] = 0xff;
+ slotptr->name11_12[end_idx * 2 + 1] = 0xff;
+ }
+
+ return 1;
+}
+
+static int is_next_clust(fsdata *mydata, dir_entry *dentptr);
+static void flush_dir_table(fsdata *mydata, dir_entry **dentptr);
+
+/*
+ * Fill dir_slot entries with appropriate name, id, and attr
+ * The real directory entry is returned by 'dentptr'
+ */
+static void
+fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name)
+{
+ dir_slot *slotptr = (dir_slot *)get_contents_vfatname_block;
+ __u8 counter = 0, checksum;
+ int idx = 0, ret;
+ char s_name[16];
+
+ /* Get short file name and checksum value */
+ strncpy(s_name, (*dentptr)->name, 16);
+ checksum = mkcksum((*dentptr)->name, (*dentptr)->ext);
+
+ do {
+ memset(slotptr, 0x00, sizeof(dir_slot));
+ ret = str2slot(slotptr, l_name, &idx);
+ slotptr->id = ++counter;
+ slotptr->attr = ATTR_VFAT;
+ slotptr->alias_checksum = checksum;
+ slotptr++;
+ } while (ret == 0);
+
+ slotptr--;
+ slotptr->id |= LAST_LONG_ENTRY_MASK;
+
+ while (counter >= 1) {
+ if (is_next_clust(mydata, *dentptr)) {
+ /* A new cluster is allocated for directory table */
+ flush_dir_table(mydata, dentptr);
+ }
+ memcpy(*dentptr, slotptr, sizeof(dir_slot));
+ (*dentptr)++;
+ slotptr--;
+ counter--;
+ }
+
+ if (is_next_clust(mydata, *dentptr)) {
+ /* A new cluster is allocated for directory table */
+ flush_dir_table(mydata, dentptr);
+ }
+}
+
+static __u32 dir_curclust;
+
+/*
+ * Extract the full long filename starting at 'retdent' (which is really
+ * a slot) into 'l_name'. If successful also copy the real directory entry
+ * into 'retdent'
+ * If additional adjacent cluster for directory entries is read into memory,
+ * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and
+ * the location of the real directory entry is returned by 'retdent'
+ * Return 0 on success, -1 otherwise.
+ */
+static int
+get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
+ dir_entry **retdent, char *l_name)
+{
+ dir_entry *realdent;
+ dir_slot *slotptr = (dir_slot *)(*retdent);
+ dir_slot *slotptr2 = NULL;
+ __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
+ PREFETCH_BLOCKS :
+ mydata->clust_size);
+ __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
+ int idx = 0, cur_position = 0;
+
+ if (counter > VFAT_MAXSEQ) {
+ debug("Error: VFAT name is too long\n");
+ return -1;
+ }
+
+ while ((__u8 *)slotptr < buflimit) {
+ if (counter == 0)
+ break;
+ if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
+ return -1;
+ slotptr++;
+ counter--;
+ }
+
+ if ((__u8 *)slotptr >= buflimit) {
+ if (curclust == 0)
+ return -1;
+ curclust = get_fatent_value(mydata, dir_curclust);
+ if (CHECK_CLUST(curclust, mydata->fatsize)) {
+ debug("curclust: 0x%x\n", curclust);
+ printf("Invalid FAT entry\n");
+ return -1;
+ }
+
+ dir_curclust = curclust;
+
+ if (get_cluster(mydata, curclust, get_contents_vfatname_block,
+ mydata->clust_size * mydata->sect_size) != 0) {
+ debug("Error: reading directory block\n");
+ return -1;
+ }
+
+ slotptr2 = (dir_slot *)get_contents_vfatname_block;
+ while (counter > 0) {
+ if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
+ & 0xff) != counter)
+ return -1;
+ slotptr2++;
+ counter--;
+ }
+
+ /* Save the real directory entry */
+ realdent = (dir_entry *)slotptr2;
+ while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
+ slotptr2--;
+ slot2str(slotptr2, l_name, &idx);
+ }
+ } else {
+ /* Save the real directory entry */
+ realdent = (dir_entry *)slotptr;
+ }
+
+ do {
+ slotptr--;
+ if (slot2str(slotptr, l_name, &idx))
+ break;
+ } while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
+
+ l_name[idx] = '\0';
+ if (*l_name == DELETED_FLAG)
+ *l_name = '\0';
+ else if (*l_name == aRING)
+ *l_name = DELETED_FLAG;
+ downcase(l_name);
+
+ /* Return the real directory entry */
+ *retdent = realdent;
+
+ if (slotptr2) {
+ memcpy(get_dentfromdir_block, get_contents_vfatname_block,
+ mydata->clust_size * mydata->sect_size);
+ cur_position = (__u8 *)realdent - get_contents_vfatname_block;
+ *retdent = (dir_entry *) &get_dentfromdir_block[cur_position];
+ }
+
+ return 0;
+}
+
+#endif
+
+/*
+ * Set the entry at index 'entry' in a FAT (16/32) table.
+ */
+static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
+{
+ __u32 bufnum, offset;
+
+ switch (mydata->fatsize) {
+ case 32:
+ bufnum = entry / FAT32BUFSIZE;
+ offset = entry - bufnum * FAT32BUFSIZE;
+ break;
+ case 16:
+ bufnum = entry / FAT16BUFSIZE;
+ offset = entry - bufnum * FAT16BUFSIZE;
+ break;
+ default:
+ /* Unsupported FAT size */
+ return -1;
+ }
+
+ /* Read a new block of FAT entries into the cache. */
+ if (bufnum != mydata->fatbufnum) {
+ int getsize = FATBUFBLOCKS;
+ __u8 *bufptr = mydata->fatbuf;
+ __u32 fatlength = mydata->fatlength;
+ __u32 startblock = bufnum * FATBUFBLOCKS;
+
+ fatlength *= mydata->sect_size;
+ startblock += mydata->fat_sect;
+
+ if (getsize > fatlength)
+ getsize = fatlength;
+
+ if (mydata->fatbufnum != -1) {
+ if (flush_fat_buffer(mydata) < 0)
+ return -1;
+ }
+
+ if (disk_read(startblock, getsize, bufptr) < 0) {
+ debug("Error reading FAT blocks\n");
+ return -1;
+ }
+ mydata->fatbufnum = bufnum;
+ }
+
+ /* Set the actual entry */
+ switch (mydata->fatsize) {
+ case 32:
+ ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
+ break;
+ case 16:
+ ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Determine the entry value at index 'entry' in a FAT (16/32) table
+ */
+static __u32 determine_fatent(fsdata *mydata, __u32 entry)
+{
+ __u32 next_fat, next_entry = entry + 1;
+
+ while (1) {
+ next_fat = get_fatent_value(mydata, next_entry);
+ if (next_fat == 0) {
+ set_fatent_value(mydata, entry, next_entry);
+ break;
+ }
+ next_entry++;
+ }
+ debug("FAT%d: entry: %08x, entry_value: %04x\n",
+ mydata->fatsize, entry, next_entry);
+
+ return next_entry;
+}
+
+/*
+ * Write at most 'size' bytes from 'buffer' into the specified cluster.
+ * Return 0 on success, -1 otherwise.
+ */
+static int
+set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
+ unsigned long size)
+{
+ int idx = 0;
+ __u32 startsect;
+
+ if (clustnum > 0)
+ startsect = mydata->data_begin +
+ clustnum * mydata->clust_size;
+ else
+ startsect = mydata->rootdir_sect;
+
+ debug("clustnum: %d, startsect: %d\n", clustnum, startsect);
+
+ if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) {
+ debug("Error writing data\n");
+ return -1;
+ }
+
+ if (size % mydata->sect_size) {
+ __u8 tmpbuf[mydata->sect_size];
+
+ idx = size / mydata->sect_size;
+ buffer += idx * mydata->sect_size;
+ memcpy(tmpbuf, buffer, size % mydata->sect_size);
+
+ if (disk_write(startsect + idx, 1, tmpbuf) < 0) {
+ debug("Error writing data\n");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Find the first empty cluster
+ */
+static int find_empty_cluster(fsdata *mydata)
+{
+ __u32 fat_val, entry = 3;
+
+ while (1) {
+ fat_val = get_fatent_value(mydata, entry);
+ if (fat_val == 0)
+ break;
+ entry++;
+ }
+
+ return entry;
+}
+
+/*
+ * Write directory entries in 'get_dentfromdir_block' to block device
+ */
+static void flush_dir_table(fsdata *mydata, dir_entry **dentptr)
+{
+ int dir_newclust = 0;
+
+ if (set_cluster(mydata, dir_curclust,
+ get_dentfromdir_block,
+ mydata->clust_size * mydata->sect_size) != 0) {
+ printf("error: wrinting directory entry\n");
+ return;
+ }
+ dir_newclust = find_empty_cluster(mydata);
+ set_fatent_value(mydata, dir_curclust, dir_newclust);
+ if (mydata->fatsize == 32)
+ set_fatent_value(mydata, dir_newclust, 0xffffff8);
+ else if (mydata->fatsize == 16)
+ set_fatent_value(mydata, dir_newclust, 0xfff8);
+
+ dir_curclust = dir_newclust;
+
+ if (flush_fat_buffer(mydata) < 0)
+ return;
+
+ memset(get_dentfromdir_block, 0x00,
+ mydata->clust_size * mydata->sect_size);
+
+ *dentptr = (dir_entry *) get_dentfromdir_block;
+}
+
+/*
+ * Set empty cluster from 'entry' to the end of a file
+ */
+static int clear_fatent(fsdata *mydata, __u32 entry)
+{
+ __u32 fat_val;
+
+ while (1) {
+ fat_val = get_fatent_value(mydata, entry);
+ if (fat_val != 0)
+ set_fatent_value(mydata, entry, 0);
+ else
+ break;
+
+ if (fat_val == 0xfffffff || fat_val == 0xffff)
+ break;
+
+ entry = fat_val;
+ }
+
+ /* Flush fat buffer */
+ if (flush_fat_buffer(mydata) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Write at most 'maxsize' bytes from 'buffer' into
+ * the file associated with 'dentptr'
+ * Return the number of bytes read or -1 on fatal errors.
+ */
+static int
+set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
+ unsigned long maxsize)
+{
+ unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
+ unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
+ __u32 curclust = START(dentptr);
+ __u32 endclust = 0, newclust = 0;
+ unsigned long actsize;
+
+ debug("Filesize: %ld bytes\n", filesize);
+
+ if (maxsize > 0 && filesize > maxsize)
+ filesize = maxsize;
+
+ debug("%ld bytes\n", filesize);
+
+ actsize = bytesperclust;
+ endclust = curclust;
+ do {
+ /* search for consecutive clusters */
+ while (actsize < filesize) {
+ newclust = determine_fatent(mydata, endclust);
+
+ if ((newclust - 1) != endclust)
+ goto getit;
+
+ if (CHECK_CLUST(newclust, mydata->fatsize)) {
+ debug("curclust: 0x%x\n", newclust);
+ debug("Invalid FAT entry\n");
+ return gotsize;
+ }
+ endclust = newclust;
+ actsize += bytesperclust;
+ }
+ /* actsize >= file size */
+ actsize -= bytesperclust;
+ /* set remaining clusters */
+ if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
+ debug("error: writing cluster\n");
+ return -1;
+ }
+
+ /* set remaining bytes */
+ gotsize += (int)actsize;
+ filesize -= actsize;
+ buffer += actsize;
+ actsize = filesize;
+
+ if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
+ debug("error: writing cluster\n");
+ return -1;
+ }
+ gotsize += actsize;
+
+ /* Mark end of file in FAT */
+ if (mydata->fatsize == 16)
+ newclust = 0xffff;
+ else if (mydata->fatsize == 32)
+ newclust = 0xfffffff;
+ set_fatent_value(mydata, endclust, newclust);
+
+ return gotsize;
+getit:
+ if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
+ debug("error: writing cluster\n");
+ return -1;
+ }
+ gotsize += (int)actsize;
+ filesize -= actsize;
+ buffer += actsize;
+
+ if (CHECK_CLUST(curclust, mydata->fatsize)) {
+ debug("curclust: 0x%x\n", curclust);
+ debug("Invalid FAT entry\n");
+ return gotsize;
+ }
+ actsize = bytesperclust;
+ curclust = endclust = newclust;
+ } while (1);
+}
+
+/*
+ * Fill dir_entry
+ */
+static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
+ const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
+{
+ if (mydata->fatsize == 32)
+ dentptr->starthi =
+ cpu_to_le16((start_cluster & 0xffff0000) >> 16);
+ dentptr->start = cpu_to_le16(start_cluster & 0xffff);
+ dentptr->size = cpu_to_le32(size);
+
+ dentptr->attr = attr;
+
+ set_name(dentptr, filename);
+}
+
+/*
+ * Check whether adding a file makes the file system to
+ * exceed the size of the block device
+ * Return -1 when overflow occurs, otherwise return 0
+ */
+static int check_overflow(fsdata *mydata, __u32 clustnum, unsigned long size)
+{
+ __u32 startsect, sect_num;
+
+ if (clustnum > 0) {
+ startsect = mydata->data_begin +
+ clustnum * mydata->clust_size;
+ } else {
+ startsect = mydata->rootdir_sect;
+ }
+
+ sect_num = size / mydata->sect_size;
+ if (size % mydata->sect_size)
+ sect_num++;
+
+ if (startsect + sect_num > cur_part_info.start + total_sector)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Check if adding several entries exceed one cluster boundary
+ */
+static int is_next_clust(fsdata *mydata, dir_entry *dentptr)
+{
+ int cur_position;
+
+ cur_position = (__u8 *)dentptr - get_dentfromdir_block;
+
+ if (cur_position >= mydata->clust_size * mydata->sect_size)
+ return 1;
+ else
+ return 0;
+}
+
+static dir_entry *empty_dentptr;
+/*
+ * Find a directory entry based on filename or start cluster number
+ * If the directory entry is not found,
+ * the new position for writing a directory entry will be returned
+ */
+static dir_entry *find_directory_entry(fsdata *mydata, int startsect,
+ char *filename, dir_entry *retdent, __u32 start)
+{
+ __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size;
+
+ debug("get_dentfromdir: %s\n", filename);
+
+ while (1) {
+ dir_entry *dentptr;
+
+ int i;
+
+ if (get_cluster(mydata, curclust, get_dentfromdir_block,
+ mydata->clust_size * mydata->sect_size) != 0) {
+ printf("Error: reading directory block\n");
+ return NULL;
+ }
+
+ dentptr = (dir_entry *)get_dentfromdir_block;
+
+ dir_curclust = curclust;
+
+ for (i = 0; i < DIRENTSPERCLUST; i++) {
+ char s_name[14], l_name[VFAT_MAXLEN_BYTES];
+
+ l_name[0] = '\0';
+ if (dentptr->name[0] == DELETED_FLAG) {
+ dentptr++;
+ if (is_next_clust(mydata, dentptr))
+ break;
+ continue;
+ }
+ if ((dentptr->attr & ATTR_VOLUME)) {
+#ifdef CONFIG_SUPPORT_VFAT
+ if ((dentptr->attr & ATTR_VFAT) &&
+ (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
+ get_long_file_name(mydata, curclust,
+ get_dentfromdir_block,
+ &dentptr, l_name);
+ debug("vfatname: |%s|\n", l_name);
+ } else
+#endif
+ {
+ /* Volume label or VFAT entry */
+ dentptr++;
+ if (is_next_clust(mydata, dentptr))
+ break;
+ continue;
+ }
+ }
+ if (dentptr->name[0] == 0) {
+ debug("Dentname == NULL - %d\n", i);
+ empty_dentptr = dentptr;
+ return NULL;
+ }
+
+ get_name(dentptr, s_name);
+
+ if (strcmp(filename, s_name)
+ && strcmp(filename, l_name)) {
+ debug("Mismatch: |%s|%s|\n",
+ s_name, l_name);
+ dentptr++;
+ if (is_next_clust(mydata, dentptr))
+ break;
+ continue;
+ }
+
+ memcpy(retdent, dentptr, sizeof(dir_entry));
+
+ debug("DentName: %s", s_name);
+ debug(", start: 0x%x", START(dentptr));
+ debug(", size: 0x%x %s\n",
+ FAT2CPU32(dentptr->size),
+ (dentptr->attr & ATTR_DIR) ?
+ "(DIR)" : "");
+
+ return dentptr;
+ }
+
+ curclust = get_fatent_value(mydata, dir_curclust);
+ if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) {
+ empty_dentptr = dentptr;
+ return NULL;
+ }
+ if (CHECK_CLUST(curclust, mydata->fatsize)) {
+ debug("curclust: 0x%x\n", curclust);
+ debug("Invalid FAT entry\n");
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static int do_fat_write(const char *filename, void *buffer,
+ unsigned long size)
+{
+ dir_entry *dentptr, *retdent;
+ __u32 startsect;
+ __u32 start_cluster;
+ boot_sector bs;
+ volume_info volinfo;
+ fsdata datablock;
+ fsdata *mydata = &datablock;
+ int cursect;
+ int ret = -1, name_len;
+ char l_filename[VFAT_MAXLEN_BYTES];
+ int write_size = size;
+
+ dir_curclust = 0;
+
+ if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
+ debug("error: reading boot sector\n");
+ return -1;
+ }
+
+ total_sector = bs.total_sect;
+ if (total_sector == 0)
+ total_sector = cur_part_info.size;
+
+ if (mydata->fatsize == 32)
+ mydata->fatlength = bs.fat32_length;
+ else
+ mydata->fatlength = bs.fat_length;
+
+ mydata->fat_sect = bs.reserved;
+
+ cursect = mydata->rootdir_sect
+ = mydata->fat_sect + mydata->fatlength * bs.fats;
+ num_of_fats = bs.fats;
+
+ mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
+ mydata->clust_size = bs.cluster_size;
+
+ if (mydata->fatsize == 32) {
+ mydata->data_begin = mydata->rootdir_sect -
+ (mydata->clust_size * 2);
+ } else {
+ int rootdir_size;
+
+ rootdir_size = ((bs.dir_entries[1] * (int)256 +
+ bs.dir_entries[0]) *
+ sizeof(dir_entry)) /
+ mydata->sect_size;
+ mydata->data_begin = mydata->rootdir_sect +
+ rootdir_size -
+ (mydata->clust_size * 2);
+ }
+
+ mydata->fatbufnum = -1;
+ mydata->fatbuf = malloc(FATBUFSIZE);
+ if (mydata->fatbuf == NULL) {
+ debug("Error: allocating memory\n");
+ return -1;
+ }
+
+ if (disk_read(cursect,
+ (mydata->fatsize == 32) ?
+ (mydata->clust_size) :
+ PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {
+ debug("Error: reading rootdir block\n");
+ goto exit;
+ }
+ dentptr = (dir_entry *) do_fat_read_at_block;
+
+ name_len = strlen(filename);
+ if (name_len >= VFAT_MAXLEN_BYTES)
+ name_len = VFAT_MAXLEN_BYTES - 1;
+
+ memcpy(l_filename, filename, name_len);
+ l_filename[name_len] = 0; /* terminate the string */
+ downcase(l_filename);
+
+ startsect = mydata->rootdir_sect;
+ retdent = find_directory_entry(mydata, startsect,
+ l_filename, dentptr, 0);
+ if (retdent) {
+ /* Update file size and start_cluster in a directory entry */
+ retdent->size = cpu_to_le32(size);
+ start_cluster = FAT2CPU16(retdent->start);
+ if (mydata->fatsize == 32)
+ start_cluster |=
+ (FAT2CPU16(retdent->starthi) << 16);
+
+ ret = check_overflow(mydata, start_cluster, size);
+ if (ret) {
+ printf("Error: %ld overflow\n", size);
+ goto exit;
+ }
+
+ ret = clear_fatent(mydata, start_cluster);
+ if (ret) {
+ printf("Error: clearing FAT entries\n");
+ goto exit;
+ }
+
+ ret = set_contents(mydata, retdent, buffer, size);
+ if (ret < 0) {
+ printf("Error: writing contents\n");
+ goto exit;
+ }
+ write_size = ret;
+ debug("attempt to write 0x%x bytes\n", write_size);
+
+ /* Flush fat buffer */
+ ret = flush_fat_buffer(mydata);
+ if (ret) {
+ printf("Error: flush fat buffer\n");
+ goto exit;
+ }
+
+ /* Write directory table to device */
+ ret = set_cluster(mydata, dir_curclust,
+ get_dentfromdir_block,
+ mydata->clust_size * mydata->sect_size);
+ if (ret) {
+ printf("Error: writing directory entry\n");
+ goto exit;
+ }
+ } else {
+ /* Set short name to set alias checksum field in dir_slot */
+ set_name(empty_dentptr, filename);
+ fill_dir_slot(mydata, &empty_dentptr, filename);
+
+ ret = start_cluster = find_empty_cluster(mydata);
+ if (ret < 0) {
+ printf("Error: finding empty cluster\n");
+ goto exit;
+ }
+
+ ret = check_overflow(mydata, start_cluster, size);
+ if (ret) {
+ printf("Error: %ld overflow\n", size);
+ goto exit;
+ }
+
+ /* Set attribute as archieve for regular file */
+ fill_dentry(mydata, empty_dentptr, filename,
+ start_cluster, size, 0x20);
+
+ ret = set_contents(mydata, empty_dentptr, buffer, size);
+ if (ret < 0) {
+ printf("Error: writing contents\n");
+ goto exit;
+ }
+ write_size = ret;
+ debug("attempt to write 0x%x bytes\n", write_size);
+
+ /* Flush fat buffer */
+ ret = flush_fat_buffer(mydata);
+ if (ret) {
+ printf("Error: flush fat buffer\n");
+ goto exit;
+ }
+
+ /* Write directory table to device */
+ ret = set_cluster(mydata, dir_curclust,
+ get_dentfromdir_block,
+ mydata->clust_size * mydata->sect_size);
+ if (ret) {
+ printf("Error: writing directory entry\n");
+ goto exit;
+ }
+ }
+
+exit:
+ free(mydata->fatbuf);
+ return ret < 0 ? ret : write_size;
+}
+
+int file_fat_write(const char *filename, void *buffer, unsigned long maxsize)
+{
+ printf("writing %s\n", filename);
+ return do_fat_write(filename, buffer, maxsize);
+}
diff --git a/u-boot/fs/fat/file.c b/u-boot/fs/fat/file.c
index 59c5d37..59c5d37 100644..100755
--- a/u-boot/fs/fat/file.c
+++ b/u-boot/fs/fat/file.c
diff --git a/u-boot/fs/fs.c b/u-boot/fs/fs.c
new file mode 100755
index 0000000..ce62faa
--- /dev/null
+++ b/u-boot/fs/fs.c
@@ -0,0 +1,334 @@
+/*
+ * 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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+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 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;
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ static int relocated;
+
+ if (!relocated) {
+ for (i = 0; i < ARRAY_SIZE(fstypes); i++)
+ fstypes[i].probe += gd->reloc_off;
+ relocated = 1;
+ }
+#endif
+
+ 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;
+}
+
+#define CMD_RET_USAGE cmd_usage(cmdtp)
+
+int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ int fstype, int cmdline_base)
+{
+ unsigned long addr;
+ const char *addr_str;
+ const char *filename;
+ unsigned long bytes;
+ unsigned long pos;
+ int len_read;
+ char buf[12];
+ unsigned long time;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+ if (argc > 7)
+ return CMD_RET_USAGE;
+
+ if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
+ return 1;
+
+ if (argc >= 4) {
+ addr = simple_strtoul(argv[3], NULL, cmdline_base);
+ } 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, cmdline_base);
+ else
+ bytes = 0;
+ if (argc >= 7)
+ pos = simple_strtoul(argv[6], NULL, cmdline_base);
+ else
+ pos = 0;
+
+ time = get_timer(0);
+ len_read = fs_read(filename, addr, pos, bytes);
+ time = get_timer(time);
+ if (len_read <= 0)
+ return 1;
+
+ printf("%d bytes read in %lu ms", len_read, time);
+ if (time > 0) {
+ puts(" (");
+ print_size(len_read / time * 1000, "/s");
+ puts(")");
+ }
+ puts("\n");
+
+ 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 (argc > 4)
+ 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;
+}
diff --git a/u-boot/include/common.h b/u-boot/include/common.h
index d8c912d..d5ec64d 100644
--- a/u-boot/include/common.h
+++ b/u-boot/include/common.h
@@ -750,4 +750,91 @@ int cpu_release(int nr, int argc, char * const argv[]);
#define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+/*
+ * ARCH_DMA_MINALIGN is defined in asm/cache.h for each architecture. It
+ * is used to align DMA buffers.
+ */
+#ifndef __ASSEMBLY__
+// #include <asm/cache.h>
+#define ARCH_DMA_MINALIGN 64 // for ARM
+#endif
+
+/*
+ * The ALLOC_CACHE_ALIGN_BUFFER macro is used to allocate a buffer on the
+ * stack that meets the minimum architecture alignment requirements for DMA.
+ * Such a buffer is useful for DMA operations where flushing and invalidating
+ * the cache before and after a read and/or write operation is required for
+ * correct operations.
+ *
+ * When called the macro creates an array on the stack that is sized such
+ * that:
+ *
+ * 1) The beginning of the array can be advanced enough to be aligned.
+ *
+ * 2) The size of the aligned portion of the array is a multiple of the minimum
+ * architecture alignment required for DMA.
+ *
+ * 3) The aligned portion contains enough space for the original number of
+ * elements requested.
+ *
+ * The macro then creates a pointer to the aligned portion of this array and
+ * assigns to the pointer the address of the first element in the aligned
+ * portion of the array.
+ *
+ * Calling the macro as:
+ *
+ * ALLOC_CACHE_ALIGN_BUFFER(uint32_t, buffer, 1024);
+ *
+ * Will result in something similar to saying:
+ *
+ * uint32_t buffer[1024];
+ *
+ * The following differences exist:
+ *
+ * 1) The resulting buffer is guaranteed to be aligned to the value of
+ * ARCH_DMA_MINALIGN.
+ *
+ * 2) The buffer variable created by the macro is a pointer to the specified
+ * type, and NOT an array of the specified type. This can be very important
+ * if you want the address of the buffer, which you probably do, to pass it
+ * to the DMA hardware. The value of &buffer is different in the two cases.
+ * In the macro case it will be the address of the pointer, not the address
+ * of the space reserved for the buffer. However, in the second case it
+ * would be the address of the buffer. So if you are replacing hard coded
+ * stack buffers with this macro you need to make sure you remove the & from
+ * the locations where you are taking the address of the buffer.
+ *
+ * Note that the size parameter is the number of array elements to allocate,
+ * not the number of bytes.
+ *
+ * This macro can not be used outside of function scope, or for the creation
+ * of a function scoped static buffer. It can not be used to create a cache
+ * line aligned global buffer.
+ */
+#define ALLOC_ALIGN_BUFFER(type, name, size, align) \
+char __##name[ROUND(size * sizeof(type), align) + (align - 1)]; \
+\
+type *name = (type *) ALIGN((uintptr_t)__##name, align)
+#define ALLOC_CACHE_ALIGN_BUFFER(type, name, size) \
+ALLOC_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
+
+/*
+ * DEFINE_CACHE_ALIGN_BUFFER() is similar to ALLOC_CACHE_ALIGN_BUFFER, but it's
+ * purpose is to allow allocating aligned buffers outside of function scope.
+ * Usage of this macro shall be avoided or used with extreme care!
+ */
+#define DEFINE_ALIGN_BUFFER(type, name, size, align) \
+static char __##name[roundup(size * sizeof(type), align)] \
+__attribute__((aligned(align))); \
+\
+static type *name = (type *)__##name
+#define DEFINE_CACHE_ALIGN_BUFFER(type, name, size) \
+DEFINE_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
+
+/* Pull in stuff for the build system */
+#ifdef DO_DEPS_ONLY
+# include <environment.h>
+#endif
+
+
#endif /* __COMMON_H_ */
diff --git a/u-boot/include/config_defaults.h b/u-boot/include/config_defaults.h
index abdf3be..c822bbd 100644
--- a/u-boot/include/config_defaults.h
+++ b/u-boot/include/config_defaults.h
@@ -17,5 +17,6 @@
#define CONFIG_GZIP 1
#define CONFIG_ZLIB 1
+#define CONFIG_PARTITIONS 1
#endif
diff --git a/u-boot/include/configs/omap3_beagle.h b/u-boot/include/configs/omap3_beagle.h
index 519da79..9866d49 100644
--- a/u-boot/include/configs/omap3_beagle.h
+++ b/u-boot/include/configs/omap3_beagle.h
@@ -322,7 +322,7 @@
#define CONFIG_ENV_OFFSET boot_flash_off
#define CONFIG_ENV_ADDR SMNAND_ENV_OFFSET
-#define CONFIG_START_WITH_DEFAULT_ENVIRONMENT 1
+//#define CONFIG_START_WITH_DEFAULT_ENVIRONMENT 1
#ifndef __ASSEMBLY__
extern unsigned int boot_flash_base;
diff --git a/u-boot/include/configs/omap3_gta04.h b/u-boot/include/configs/omap3_gta04.h
index c6269af..69eb055 100644
--- a/u-boot/include/configs/omap3_gta04.h
+++ b/u-boot/include/configs/omap3_gta04.h
@@ -31,15 +31,13 @@
#define CONFIG_CMD_UNZIP 1 /* for reducing size of splash image */
-// #undef CONFIG_CMD_JFFS2
-// #define CONFIG_CMD_JFFS2 1 /* to access the rootfs in NAND flash */
-// FIXME: needs to add configs for the partitions so that JFFS2 runs in the correct NAND partition
-
-#define CONFIG_CMD_UBIFS 1
-
-#define CONFIG_CMD_EXT2 1
-#define CONFIG_CMD_EXT4 1
+// #define CONFIG_CMD_UBIFS 1 // broken
+#define CONFIG_FS_FAT 1
+#define CONFIG_FS_EXT2 1
+#define CONFIG_FS_EXT4 1
+#define CONFIG_CMD_FS 1
+#define CONFIG_CMD_EXT4 1
#undef CONFIG_SYS_PROMPT
#define CONFIG_SYS_PROMPT "GTA04 # "
diff --git a/u-boot/include/fat.h b/u-boot/include/fat.h
index afb2116..706cd7a 100644..100755
--- a/u-boot/include/fat.h
+++ b/u-boot/include/fat.h
@@ -33,22 +33,15 @@
/* Maximum Long File Name length supported here is 128 UTF-16 code units */
#define VFAT_MAXLEN_BYTES 256 /* Maximum LFN buffer in bytes */
#define VFAT_MAXSEQ 9 /* Up to 9 of 13 2-byte UTF-16 entries */
-#define LINEAR_PREFETCH_SIZE (SECTOR_SIZE*2) /* Prefetch buffer size */
-
-#define SECTOR_SIZE FS_BLOCK_SIZE
-
-#define FS_BLOCK_SIZE 512
-
-#if FS_BLOCK_SIZE != SECTOR_SIZE
-#error FS_BLOCK_SIZE != SECTOR_SIZE - This code needs to be fixed!
-#endif
+#define PREFETCH_BLOCKS 2
#define MAX_CLUSTSIZE 65536
-#define DIRENTSPERBLOCK (FS_BLOCK_SIZE/sizeof(dir_entry))
-#define DIRENTSPERCLUST ((mydata->clust_size*SECTOR_SIZE)/sizeof(dir_entry))
+#define DIRENTSPERBLOCK (mydata->sect_size / sizeof(dir_entry))
+#define DIRENTSPERCLUST ((mydata->clust_size * mydata->sect_size) / \
+ sizeof(dir_entry))
#define FATBUFBLOCKS 6
-#define FATBUFSIZE (FS_BLOCK_SIZE*FATBUFBLOCKS)
+#define FATBUFSIZE (mydata->sect_size * FATBUFBLOCKS)
#define FAT12BUFSIZE ((FATBUFSIZE*2)/3)
#define FAT16BUFSIZE (FATBUFSIZE/2)
#define FAT32BUFSIZE (FATBUFSIZE/4)
@@ -106,6 +99,8 @@
#endif
#define TOLOWER(c) if((c) >= 'A' && (c) <= 'Z'){(c)+=('a' - 'A');}
+#define TOUPPER(c) if ((c) >= 'a' && (c) <= 'z') \
+ (c) -= ('a' - 'A');
#define START(dent) (FAT2CPU16((dent)->start) \
+ (mydata->fatsize != 32 ? 0 : \
(FAT2CPU16((dent)->starthi) << 16)))
@@ -181,13 +176,14 @@ typedef struct dir_slot {
* (see FAT32 accesses)
*/
typedef struct {
- __u8 fatbuf[FATBUFSIZE]; /* Current FAT buffer */
+ __u8 *fatbuf; /* Current FAT buffer */
int fatsize; /* Size of FAT in bits */
- __u16 fatlength; /* Length of FAT in sectors */
+ __u32 fatlength; /* Length of FAT in sectors */
__u16 fat_sect; /* Starting sector of the FAT */
- __u16 rootdir_sect; /* Start sector of root directory */
+ __u32 rootdir_sect; /* Start sector of root directory */
+ __u16 sect_size; /* Size of sectors in bytes */
__u16 clust_size; /* Size of clusters in sectors */
- short data_begin; /* The sector of the first cluster, can be negative */
+ int data_begin; /* The sector of the first cluster, can be negative */
int fatbufnum; /* Used by get_fatent, init to -1 */
} fsdata;
@@ -212,8 +208,12 @@ file_read_func file_fat_read;
int file_cd(const char *path);
int file_fat_detectfs(void);
int file_fat_ls(const char *dir);
+long file_fat_read_at(const char *filename, unsigned long pos, void *buffer,
+ unsigned long maxsize);
long file_fat_read(const char *filename, void *buffer, unsigned long maxsize);
const char *file_getfsname(int idx);
+int fat_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info);
int fat_register_device(block_dev_desc_t *dev_desc, int part_no);
+int file_fat_write(const char *filename, void *buffer, unsigned long maxsize);
#endif /* _FAT_H_ */
diff --git a/u-boot/include/fs.h b/u-boot/include/fs.h
new file mode 100755
index 0000000..4f30a38
--- /dev/null
+++ b/u-boot/include/fs.h
@@ -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_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ int fstype, int cmdline_base);
+int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ int fstype);
+
+#endif /* _FS_H */
diff --git a/u-boot/include/part.h b/u-boot/include/part.h
index 3cdae02..27ea283 100644..100755
--- a/u-boot/include/part.h
+++ b/u-boot/include/part.h
@@ -36,7 +36,7 @@ typedef struct block_dev_desc {
#ifdef CONFIG_LBA48
unsigned char lba48; /* device can use 48bit addr (ATA/ATAPI v7) */
#endif
- lbaint_t lba; /* number of blocks */
+ lbaint_t lba; /* number of blocks */
unsigned long blksz; /* block size */
char vendor [40+1]; /* IDE model, SCSI Vendor */
char product[20+1]; /* IDE Serial no, SCSI product */
@@ -49,6 +49,9 @@ typedef struct block_dev_desc {
unsigned long start,
lbaint_t blkcnt,
const void *buffer);
+ unsigned long (*block_erase)(int dev,
+ unsigned long start,
+ lbaint_t blkcnt);
void *priv; /* driver private struct pointer */
}block_dev_desc_t;
@@ -90,10 +93,15 @@ typedef struct disk_partition {
ulong blksz; /* block size in bytes */
uchar name[32]; /* partition name */
uchar type[32]; /* string type description */
+ int bootable; /* Active/Bootable flag is set */
+#ifdef CONFIG_PARTITION_UUIDS
+ char uuid[37]; /* filesystem UUID as string, if exists */
+#endif
} disk_partition_t;
/* Misc _get_dev functions */
-block_dev_desc_t* get_dev(char* ifname, int dev);
+#ifdef CONFIG_PARTITIONS
+block_dev_desc_t *get_dev(const char *ifname, int dev);
block_dev_desc_t* ide_get_dev(int dev);
block_dev_desc_t* sata_get_dev(int dev);
block_dev_desc_t* scsi_get_dev(int dev);
@@ -107,7 +115,37 @@ int get_partition_info (block_dev_desc_t * dev_desc, int part, disk_partition_t
void print_part (block_dev_desc_t *dev_desc);
void init_part (block_dev_desc_t *dev_desc);
void dev_print(block_dev_desc_t *dev_desc);
-
+int get_device(const char *ifname, const char *dev_str,
+ block_dev_desc_t **dev_desc);
+int get_device_and_partition(const char *ifname, const char *dev_part_str,
+ block_dev_desc_t **dev_desc,
+ disk_partition_t *info, int allow_whole_dev);
+#else
+static inline block_dev_desc_t *get_dev(const char *ifname, int dev)
+{ return NULL; }
+static inline block_dev_desc_t* ide_get_dev(int dev) { return NULL; }
+static inline block_dev_desc_t* sata_get_dev(int dev) { return NULL; }
+static inline block_dev_desc_t* scsi_get_dev(int dev) { return NULL; }
+static inline block_dev_desc_t* usb_stor_get_dev(int dev) { return NULL; }
+static inline block_dev_desc_t* mmc_get_dev(int dev) { return NULL; }
+static inline block_dev_desc_t* systemace_get_dev(int dev) { return NULL; }
+static inline block_dev_desc_t* mg_disk_get_dev(int dev) { return NULL; }
+
+static inline int get_partition_info (block_dev_desc_t * dev_desc, int part,
+ disk_partition_t *info) { return -1; }
+static inline void print_part (block_dev_desc_t *dev_desc) {}
+static inline void init_part (block_dev_desc_t *dev_desc) {}
+static inline void dev_print(block_dev_desc_t *dev_desc) {}
+static inline int get_device(const char *ifname, const char *dev_str,
+ block_dev_desc_t **dev_desc)
+{ return -1; }
+static inline int get_device_and_partition(const char *ifname,
+ const char *dev_part_str,
+ block_dev_desc_t **dev_desc,
+ disk_partition_t *info,
+ int allow_whole_dev)
+{ *dev_desc = NULL; return -1; }
+#endif
#ifdef CONFIG_MAC_PARTITION
/* disk/part_mac.c */