fs.c 5.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * 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>
S
Simon Glass 已提交
23
#include <asm/io.h>
24

25 26
DECLARE_GLOBAL_DATA_PTR;

27 28 29 30
static block_dev_desc_t *fs_dev_desc;
static disk_partition_t fs_partition;
static int fs_type = FS_TYPE_ANY;

31 32
static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
				      disk_partition_t *fs_partition)
33 34 35 36 37
{
	printf("** Unrecognized filesystem type **\n");
	return -1;
}

38 39 40 41 42
static inline int fs_ls_unsupported(const char *dirname)
{
	return -1;
}

S
Simon Glass 已提交
43
static inline int fs_read_unsupported(const char *filename, void *buf,
44 45 46 47 48
				      int offset, int len)
{
	return -1;
}

49 50 51 52 53
static inline void fs_close_unsupported(void)
{
}

struct fstype_info {
54
	int fstype;
55 56
	int (*probe)(block_dev_desc_t *fs_dev_desc,
		     disk_partition_t *fs_partition);
57
	int (*ls)(const char *dirname);
S
Simon Glass 已提交
58
	int (*read)(const char *filename, void *buf, int offset, int len);
59 60 61 62 63
	void (*close)(void);
};

static struct fstype_info fstypes[] = {
#ifdef CONFIG_FS_FAT
64 65
	{
		.fstype = FS_TYPE_FAT,
66 67
		.probe = fat_set_blk_dev,
		.close = fat_close,
68
		.ls = file_fat_ls,
69
		.read = fat_read_file,
70
	},
71 72
#endif
#ifdef CONFIG_FS_EXT4
73 74
	{
		.fstype = FS_TYPE_EXT,
75 76
		.probe = ext4fs_probe,
		.close = ext4fs_close,
77
		.ls = ext4fs_ls,
78
		.read = ext4_read_file,
79 80 81 82 83 84 85 86
	},
#endif
	{
		.fstype = FS_TYPE_ANY,
		.probe = fs_probe_unsupported,
		.close = fs_close_unsupported,
		.ls = fs_ls_unsupported,
		.read = fs_read_unsupported,
87 88 89
	},
};

90 91 92 93 94 95 96 97 98 99 100 101 102 103
static struct fstype_info *fs_get_info(int fstype)
{
	struct fstype_info *info;
	int i;

	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
		if (fstype == info->fstype)
			return info;
	}

	/* Return the 'unsupported' sentinel */
	return info;
}

104 105
int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
{
106
	struct fstype_info *info;
107
	int part, i;
108 109 110 111
#ifdef CONFIG_NEEDS_MANUAL_RELOC
	static int relocated;

	if (!relocated) {
112 113 114 115 116 117 118
		for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
				i++, info++) {
			info->probe += gd->reloc_off;
			info->close += gd->reloc_off;
			info->ls += gd->reloc_off;
			info->read += gd->reloc_off;
		}
119 120 121
		relocated = 1;
	}
#endif
122 123 124 125 126 127

	part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
					&fs_partition, 1);
	if (part < 0)
		return -1;

128 129 130
	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
		if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
				fstype != info->fstype)
131 132
			continue;

133
		if (!info->probe(fs_dev_desc, &fs_partition)) {
134
			fs_type = info->fstype;
135 136 137 138 139 140 141 142 143
			return 0;
		}
	}

	return -1;
}

static void fs_close(void)
{
144
	struct fstype_info *info = fs_get_info(fs_type);
145

146
	info->close();
147

148 149 150 151 152 153 154
	fs_type = FS_TYPE_ANY;
}

int fs_ls(const char *dirname)
{
	int ret;

155 156 157
	struct fstype_info *info = fs_get_info(fs_type);

	ret = info->ls(dirname);
158

159
	fs_type = FS_TYPE_ANY;
160 161 162 163 164 165 166
	fs_close();

	return ret;
}

int fs_read(const char *filename, ulong addr, int offset, int len)
{
167
	struct fstype_info *info = fs_get_info(fs_type);
S
Simon Glass 已提交
168
	void *buf;
169 170
	int ret;

S
Simon Glass 已提交
171 172 173 174 175 176 177
	/*
	 * We don't actually know how many bytes are being read, since len==0
	 * means read the whole file.
	 */
	buf = map_sysmem(addr, len);
	ret = info->read(filename, buf, offset, len);
	unmap_sysmem(buf);
178

179 180 181 182 183
	/* If we requested a specific number of bytes, check we got it */
	if (ret >= 0 && len && ret != len) {
		printf("** Unable to read file %s **\n", filename);
		ret = -1;
	}
184 185 186 187 188
	fs_close();

	return ret;
}

S
Stephen Warren 已提交
189
int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
190
		int fstype, int cmdline_base)
191 192 193 194 195 196 197
{
	unsigned long addr;
	const char *addr_str;
	const char *filename;
	unsigned long bytes;
	unsigned long pos;
	int len_read;
198
	unsigned long time;
199

200 201 202
	if (argc < 2)
		return CMD_RET_USAGE;
	if (argc > 7)
203 204
		return CMD_RET_USAGE;

205
	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
206 207 208
		return 1;

	if (argc >= 4) {
209
		addr = simple_strtoul(argv[3], NULL, cmdline_base);
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
	} 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)
227
		bytes = simple_strtoul(argv[5], NULL, cmdline_base);
228 229 230
	else
		bytes = 0;
	if (argc >= 7)
231
		pos = simple_strtoul(argv[6], NULL, cmdline_base);
232 233 234
	else
		pos = 0;

235
	time = get_timer(0);
236
	len_read = fs_read(filename, addr, pos, bytes);
237
	time = get_timer(time);
238 239 240
	if (len_read <= 0)
		return 1;

241 242 243 244 245 246 247
	printf("%d bytes read in %lu ms", len_read, time);
	if (time > 0) {
		puts(" (");
		print_size(len_read / time * 1000, "/s");
		puts(")");
	}
	puts("\n");
248

249
	setenv_hex("filesize", len_read);
250 251 252 253 254 255 256 257 258

	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;
259 260
	if (argc > 4)
		return CMD_RET_USAGE;
261 262 263 264

	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
		return 1;

265
	if (fs_ls(argc >= 4 ? argv[3] : "/"))
266 267 268 269
		return 1;

	return 0;
}