blob: 023e7ef16a3e86a12b48b416638bbcd972b84fc9 [file] [log] [blame]
Stephen Warreneefbc3f2012-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 Warren44161af2012-10-30 07:50:47 +000024DECLARE_GLOBAL_DATA_PTR;
25
Stephen Warreneefbc3f2012-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 Warren44161af2012-10-30 07:50:47 +0000146static struct {
Stephen Warreneefbc3f2012-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 Warren44161af2012-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 Warreneefbc3f2012-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 Warren128d3d92012-10-31 11:05:07 +0000250int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
Stephen Warren40816a02012-10-30 12:04:19 +0000251 int fstype, int cmdline_base)
Stephen Warreneefbc3f2012-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;
259 char buf[12];
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100260 unsigned long time;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000261
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000262 if (argc < 2)
263 return CMD_RET_USAGE;
264 if (argc > 7)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000265 return CMD_RET_USAGE;
266
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000267 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000268 return 1;
269
270 if (argc >= 4) {
Stephen Warren40816a02012-10-30 12:04:19 +0000271 addr = simple_strtoul(argv[3], NULL, cmdline_base);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000272 } else {
273 addr_str = getenv("loadaddr");
274 if (addr_str != NULL)
275 addr = simple_strtoul(addr_str, NULL, 16);
276 else
277 addr = CONFIG_SYS_LOAD_ADDR;
278 }
279 if (argc >= 5) {
280 filename = argv[4];
281 } else {
282 filename = getenv("bootfile");
283 if (!filename) {
284 puts("** No boot file defined **\n");
285 return 1;
286 }
287 }
288 if (argc >= 6)
Stephen Warren40816a02012-10-30 12:04:19 +0000289 bytes = simple_strtoul(argv[5], NULL, cmdline_base);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000290 else
291 bytes = 0;
292 if (argc >= 7)
Stephen Warren40816a02012-10-30 12:04:19 +0000293 pos = simple_strtoul(argv[6], NULL, cmdline_base);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000294 else
295 pos = 0;
296
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100297 time = get_timer(0);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000298 len_read = fs_read(filename, addr, pos, bytes);
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100299 time = get_timer(time);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000300 if (len_read <= 0)
301 return 1;
302
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100303 printf("%d bytes read in %lu ms", len_read, time);
304 if (time > 0) {
305 puts(" (");
306 print_size(len_read / time * 1000, "/s");
307 puts(")");
308 }
309 puts("\n");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000310
311 sprintf(buf, "0x%x", len_read);
312 setenv("filesize", buf);
313
314 return 0;
315}
316
317int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
318 int fstype)
319{
320 if (argc < 2)
321 return CMD_RET_USAGE;
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000322 if (argc > 4)
323 return CMD_RET_USAGE;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000324
325 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
326 return 1;
327
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000328 if (fs_ls(argc >= 4 ? argv[3] : "/"))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000329 return 1;
330
331 return 0;
332}