xref: /rk3399_rockchip-uboot/fs/fs.c (revision 62584db191013f13133be0f6702d0c935a7c85a6)
1 /*
2  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <config.h>
18 #include <common.h>
19 #include <part.h>
20 #include <ext4fs.h>
21 #include <fat.h>
22 #include <fs.h>
23 #include <asm/io.h>
24 
25 DECLARE_GLOBAL_DATA_PTR;
26 
27 static block_dev_desc_t *fs_dev_desc;
28 static disk_partition_t fs_partition;
29 static int fs_type = FS_TYPE_ANY;
30 
31 static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
32 				      disk_partition_t *fs_partition)
33 {
34 	printf("** Unrecognized filesystem type **\n");
35 	return -1;
36 }
37 
38 static inline int fs_ls_unsupported(const char *dirname)
39 {
40 	return -1;
41 }
42 
43 static inline int fs_read_unsupported(const char *filename, void *buf,
44 				      int offset, int len)
45 {
46 	return -1;
47 }
48 
49 static inline void fs_close_unsupported(void)
50 {
51 }
52 
53 struct fstype_info {
54 	int fstype;
55 	int (*probe)(block_dev_desc_t *fs_dev_desc,
56 		     disk_partition_t *fs_partition);
57 	int (*ls)(const char *dirname);
58 	int (*read)(const char *filename, void *buf, int offset, int len);
59 	void (*close)(void);
60 };
61 
62 static struct fstype_info fstypes[] = {
63 #ifdef CONFIG_FS_FAT
64 	{
65 		.fstype = FS_TYPE_FAT,
66 		.probe = fat_set_blk_dev,
67 		.close = fat_close,
68 		.ls = file_fat_ls,
69 		.read = fat_read_file,
70 	},
71 #endif
72 #ifdef CONFIG_FS_EXT4
73 	{
74 		.fstype = FS_TYPE_EXT,
75 		.probe = ext4fs_probe,
76 		.close = ext4fs_close,
77 		.ls = ext4fs_ls,
78 		.read = ext4_read_file,
79 	},
80 #endif
81 	{
82 		.fstype = FS_TYPE_ANY,
83 		.probe = fs_probe_unsupported,
84 		.close = fs_close_unsupported,
85 		.ls = fs_ls_unsupported,
86 		.read = fs_read_unsupported,
87 	},
88 };
89 
90 static struct fstype_info *fs_get_info(int fstype)
91 {
92 	struct fstype_info *info;
93 	int i;
94 
95 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
96 		if (fstype == info->fstype)
97 			return info;
98 	}
99 
100 	/* Return the 'unsupported' sentinel */
101 	return info;
102 }
103 
104 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
105 {
106 	struct fstype_info *info;
107 	int part, i;
108 #ifdef CONFIG_NEEDS_MANUAL_RELOC
109 	static int relocated;
110 
111 	if (!relocated) {
112 		for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
113 				i++, info++) {
114 			info->probe += gd->reloc_off;
115 			info->close += gd->reloc_off;
116 			info->ls += gd->reloc_off;
117 			info->read += gd->reloc_off;
118 		}
119 		relocated = 1;
120 	}
121 #endif
122 
123 	part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
124 					&fs_partition, 1);
125 	if (part < 0)
126 		return -1;
127 
128 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
129 		if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
130 				fstype != info->fstype)
131 			continue;
132 
133 		if (!info->probe(fs_dev_desc, &fs_partition)) {
134 			fs_type = info->fstype;
135 			return 0;
136 		}
137 	}
138 
139 	return -1;
140 }
141 
142 static void fs_close(void)
143 {
144 	struct fstype_info *info = fs_get_info(fs_type);
145 
146 	info->close();
147 
148 	fs_type = FS_TYPE_ANY;
149 }
150 
151 int fs_ls(const char *dirname)
152 {
153 	int ret;
154 
155 	struct fstype_info *info = fs_get_info(fs_type);
156 
157 	ret = info->ls(dirname);
158 
159 	fs_type = FS_TYPE_ANY;
160 	fs_close();
161 
162 	return ret;
163 }
164 
165 int fs_read(const char *filename, ulong addr, int offset, int len)
166 {
167 	struct fstype_info *info = fs_get_info(fs_type);
168 	void *buf;
169 	int ret;
170 
171 	/*
172 	 * We don't actually know how many bytes are being read, since len==0
173 	 * means read the whole file.
174 	 */
175 	buf = map_sysmem(addr, len);
176 	ret = info->read(filename, buf, offset, len);
177 	unmap_sysmem(buf);
178 
179 	/* If we requested a specific number of bytes, check we got it */
180 	if (ret >= 0 && len && ret != len) {
181 		printf("** Unable to read file %s **\n", filename);
182 		ret = -1;
183 	}
184 	fs_close();
185 
186 	return ret;
187 }
188 
189 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
190 		int fstype, int cmdline_base)
191 {
192 	unsigned long addr;
193 	const char *addr_str;
194 	const char *filename;
195 	unsigned long bytes;
196 	unsigned long pos;
197 	int len_read;
198 	unsigned long time;
199 
200 	if (argc < 2)
201 		return CMD_RET_USAGE;
202 	if (argc > 7)
203 		return CMD_RET_USAGE;
204 
205 	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
206 		return 1;
207 
208 	if (argc >= 4) {
209 		addr = simple_strtoul(argv[3], NULL, cmdline_base);
210 	} else {
211 		addr_str = getenv("loadaddr");
212 		if (addr_str != NULL)
213 			addr = simple_strtoul(addr_str, NULL, 16);
214 		else
215 			addr = CONFIG_SYS_LOAD_ADDR;
216 	}
217 	if (argc >= 5) {
218 		filename = argv[4];
219 	} else {
220 		filename = getenv("bootfile");
221 		if (!filename) {
222 			puts("** No boot file defined **\n");
223 			return 1;
224 		}
225 	}
226 	if (argc >= 6)
227 		bytes = simple_strtoul(argv[5], NULL, cmdline_base);
228 	else
229 		bytes = 0;
230 	if (argc >= 7)
231 		pos = simple_strtoul(argv[6], NULL, cmdline_base);
232 	else
233 		pos = 0;
234 
235 	time = get_timer(0);
236 	len_read = fs_read(filename, addr, pos, bytes);
237 	time = get_timer(time);
238 	if (len_read <= 0)
239 		return 1;
240 
241 	printf("%d bytes read in %lu ms", len_read, time);
242 	if (time > 0) {
243 		puts(" (");
244 		print_size(len_read / time * 1000, "/s");
245 		puts(")");
246 	}
247 	puts("\n");
248 
249 	setenv_hex("filesize", len_read);
250 
251 	return 0;
252 }
253 
254 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
255 	int fstype)
256 {
257 	if (argc < 2)
258 		return CMD_RET_USAGE;
259 	if (argc > 4)
260 		return CMD_RET_USAGE;
261 
262 	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
263 		return 1;
264 
265 	if (fs_ls(argc >= 4 ? argv[3] : "/"))
266 		return 1;
267 
268 	return 0;
269 }
270