blob: 2c9f2c5ac1b01ec882547c5995e034206c9a2729 [file] [log] [blame]
Stephen Warren045fa1e2012-10-22 06:43:51 +00001/*
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
Stephen Warrena1b231c2012-10-30 07:50:47 +000024DECLARE_GLOBAL_DATA_PTR;
25
Stephen Warren045fa1e2012-10-22 06:43:51 +000026static block_dev_desc_t *fs_dev_desc;
27static disk_partition_t fs_partition;
28static int fs_type = FS_TYPE_ANY;
29
30static inline int fs_ls_unsupported(const char *dirname)
31{
32 printf("** Unrecognized filesystem type **\n");
33 return -1;
34}
35
36static inline int fs_read_unsupported(const char *filename, ulong addr,
37 int offset, int len)
38{
39 printf("** Unrecognized filesystem type **\n");
40 return -1;
41}
42
43#ifdef CONFIG_FS_FAT
44static int fs_probe_fat(void)
45{
46 return fat_set_blk_dev(fs_dev_desc, &fs_partition);
47}
48
49static void fs_close_fat(void)
50{
51}
52
53#define fs_ls_fat file_fat_ls
54
55static int fs_read_fat(const char *filename, ulong addr, int offset, int len)
56{
57 int len_read;
58
59 len_read = file_fat_read_at(filename, offset,
60 (unsigned char *)addr, len);
61 if (len_read == -1) {
62 printf("** Unable to read file %s **\n", filename);
63 return -1;
64 }
65
66 return len_read;
67}
68#else
69static inline int fs_probe_fat(void)
70{
71 return -1;
72}
73
74static inline void fs_close_fat(void)
75{
76}
77
78#define fs_ls_fat fs_ls_unsupported
79#define fs_read_fat fs_read_unsupported
80#endif
81
82#ifdef CONFIG_FS_EXT4
83static int fs_probe_ext(void)
84{
85 ext4fs_set_blk_dev(fs_dev_desc, &fs_partition);
86
87 if (!ext4fs_mount(fs_partition.size)) {
88 ext4fs_close();
89 return -1;
90 }
91
92 return 0;
93}
94
95static void fs_close_ext(void)
96{
97 ext4fs_close();
98}
99
100#define fs_ls_ext ext4fs_ls
101
102static int fs_read_ext(const char *filename, ulong addr, int offset, int len)
103{
104 int file_len;
105 int len_read;
106
107 if (offset != 0) {
108 printf("** Cannot support non-zero offset **\n");
109 return -1;
110 }
111
112 file_len = ext4fs_open(filename);
113 if (file_len < 0) {
114 printf("** File not found %s **\n", filename);
115 ext4fs_close();
116 return -1;
117 }
118
119 if (len == 0)
120 len = file_len;
121
122 len_read = ext4fs_read((char *)addr, len);
123 ext4fs_close();
124
125 if (len_read != len) {
126 printf("** Unable to read file %s **\n", filename);
127 return -1;
128 }
129
130 return len_read;
131}
132#else
133static inline int fs_probe_ext(void)
134{
135 return -1;
136}
137
138static inline void fs_close_ext(void)
139{
140}
141
142#define fs_ls_ext fs_ls_unsupported
143#define fs_read_ext fs_read_unsupported
144#endif
145
Stephen Warrena1b231c2012-10-30 07:50:47 +0000146static struct {
Stephen Warren045fa1e2012-10-22 06:43:51 +0000147 int fstype;
148 int (*probe)(void);
149} fstypes[] = {
150 {
151 .fstype = FS_TYPE_FAT,
152 .probe = fs_probe_fat,
153 },
154 {
155 .fstype = FS_TYPE_EXT,
156 .probe = fs_probe_ext,
157 },
158};
159
160int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
161{
162 int part, i;
Stephen Warrena1b231c2012-10-30 07:50:47 +0000163#ifdef CONFIG_NEEDS_MANUAL_RELOC
164 static int relocated;
165
166 if (!relocated) {
167 for (i = 0; i < ARRAY_SIZE(fstypes); i++)
168 fstypes[i].probe += gd->reloc_off;
169 relocated = 1;
170 }
171#endif
Stephen Warren045fa1e2012-10-22 06:43:51 +0000172
173 part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
174 &fs_partition, 1);
175 if (part < 0)
176 return -1;
177
178 for (i = 0; i < ARRAY_SIZE(fstypes); i++) {
179 if ((fstype != FS_TYPE_ANY) && (fstype != fstypes[i].fstype))
180 continue;
181
182 if (!fstypes[i].probe()) {
183 fs_type = fstypes[i].fstype;
184 return 0;
185 }
186 }
187
188 printf("** Unrecognized filesystem type **\n");
189 return -1;
190}
191
192static void fs_close(void)
193{
194 switch (fs_type) {
195 case FS_TYPE_FAT:
196 fs_close_fat();
197 break;
198 case FS_TYPE_EXT:
199 fs_close_ext();
200 break;
201 default:
202 break;
203 }
204
205 fs_type = FS_TYPE_ANY;
206}
207
208int fs_ls(const char *dirname)
209{
210 int ret;
211
212 switch (fs_type) {
213 case FS_TYPE_FAT:
214 ret = fs_ls_fat(dirname);
215 break;
216 case FS_TYPE_EXT:
217 ret = fs_ls_ext(dirname);
218 break;
219 default:
220 ret = fs_ls_unsupported(dirname);
221 break;
222 }
223
224 fs_close();
225
226 return ret;
227}
228
229int fs_read(const char *filename, ulong addr, int offset, int len)
230{
231 int ret;
232
233 switch (fs_type) {
234 case FS_TYPE_FAT:
235 ret = fs_read_fat(filename, addr, offset, len);
236 break;
237 case FS_TYPE_EXT:
238 ret = fs_read_ext(filename, addr, offset, len);
239 break;
240 default:
241 ret = fs_read_unsupported(filename, addr, offset, len);
242 break;
243 }
244
245 fs_close();
246
247 return ret;
248}
249
Stephen Warrenf9b55e22012-10-31 11:05:07 +0000250int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
Stephen Warren3f83c872012-10-30 12:04:19 +0000251 int fstype, int cmdline_base)
Stephen Warren045fa1e2012-10-22 06:43:51 +0000252{
253 unsigned long addr;
254 const char *addr_str;
255 const char *filename;
256 unsigned long bytes;
257 unsigned long pos;
258 int len_read;
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100259 unsigned long time;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000260
Stephen Warrene9b0f992012-10-30 12:04:17 +0000261 if (argc < 2)
262 return CMD_RET_USAGE;
263 if (argc > 7)
Stephen Warren045fa1e2012-10-22 06:43:51 +0000264 return CMD_RET_USAGE;
265
Stephen Warrene9b0f992012-10-30 12:04:17 +0000266 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
Stephen Warren045fa1e2012-10-22 06:43:51 +0000267 return 1;
268
269 if (argc >= 4) {
Stephen Warren3f83c872012-10-30 12:04:19 +0000270 addr = simple_strtoul(argv[3], NULL, cmdline_base);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000271 } else {
272 addr_str = getenv("loadaddr");
273 if (addr_str != NULL)
274 addr = simple_strtoul(addr_str, NULL, 16);
275 else
276 addr = CONFIG_SYS_LOAD_ADDR;
277 }
278 if (argc >= 5) {
279 filename = argv[4];
280 } else {
281 filename = getenv("bootfile");
282 if (!filename) {
283 puts("** No boot file defined **\n");
284 return 1;
285 }
286 }
287 if (argc >= 6)
Stephen Warren3f83c872012-10-30 12:04:19 +0000288 bytes = simple_strtoul(argv[5], NULL, cmdline_base);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000289 else
290 bytes = 0;
291 if (argc >= 7)
Stephen Warren3f83c872012-10-30 12:04:19 +0000292 pos = simple_strtoul(argv[6], NULL, cmdline_base);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000293 else
294 pos = 0;
295
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100296 time = get_timer(0);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000297 len_read = fs_read(filename, addr, pos, bytes);
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100298 time = get_timer(time);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000299 if (len_read <= 0)
300 return 1;
301
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100302 printf("%d bytes read in %lu ms", len_read, time);
303 if (time > 0) {
304 puts(" (");
305 print_size(len_read / time * 1000, "/s");
306 puts(")");
307 }
308 puts("\n");
Stephen Warren045fa1e2012-10-22 06:43:51 +0000309
Simon Glass49c4f032013-02-24 17:33:23 +0000310 setenv_hex("filesize", len_read);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000311
312 return 0;
313}
314
315int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
316 int fstype)
317{
318 if (argc < 2)
319 return CMD_RET_USAGE;
Stephen Warrene9b0f992012-10-30 12:04:17 +0000320 if (argc > 4)
321 return CMD_RET_USAGE;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000322
323 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
324 return 1;
325
Stephen Warrene9b0f992012-10-30 12:04:17 +0000326 if (fs_ls(argc >= 4 ? argv[3] : "/"))
Stephen Warren045fa1e2012-10-22 06:43:51 +0000327 return 1;
328
329 return 0;
330}