]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - fs/fs.c
eee7e23392e4cb9f76c4e4247c3d6c55981bdded
[karo-tx-uboot.git] / fs / fs.c
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 <sandboxfs.h>
24 #include <asm/io.h>
25
26 DECLARE_GLOBAL_DATA_PTR;
27
28 static block_dev_desc_t *fs_dev_desc;
29 static disk_partition_t fs_partition;
30 static int fs_type = FS_TYPE_ANY;
31
32 static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
33                                       disk_partition_t *fs_partition)
34 {
35         printf("** Unrecognized filesystem type **\n");
36         return -1;
37 }
38
39 static inline int fs_ls_unsupported(const char *dirname)
40 {
41         return -1;
42 }
43
44 static inline int fs_read_unsupported(const char *filename, void *buf,
45                                       int offset, int len)
46 {
47         return -1;
48 }
49
50 static inline int fs_write_unsupported(const char *filename, void *buf,
51                                       int offset, int len)
52 {
53         return -1;
54 }
55
56 static inline void fs_close_unsupported(void)
57 {
58 }
59
60 struct fstype_info {
61         int fstype;
62         int (*probe)(block_dev_desc_t *fs_dev_desc,
63                      disk_partition_t *fs_partition);
64         int (*ls)(const char *dirname);
65         int (*read)(const char *filename, void *buf, int offset, int len);
66         int (*write)(const char *filename, void *buf, int offset, int len);
67         void (*close)(void);
68 };
69
70 static struct fstype_info fstypes[] = {
71 #ifdef CONFIG_FS_FAT
72         {
73                 .fstype = FS_TYPE_FAT,
74                 .probe = fat_set_blk_dev,
75                 .close = fat_close,
76                 .ls = file_fat_ls,
77                 .read = fat_read_file,
78         },
79 #endif
80 #ifdef CONFIG_FS_EXT4
81         {
82                 .fstype = FS_TYPE_EXT,
83                 .probe = ext4fs_probe,
84                 .close = ext4fs_close,
85                 .ls = ext4fs_ls,
86                 .read = ext4_read_file,
87         },
88 #endif
89 #ifdef CONFIG_SANDBOX
90         {
91                 .fstype = FS_TYPE_SANDBOX,
92                 .probe = sandbox_fs_set_blk_dev,
93                 .close = sandbox_fs_close,
94                 .ls = sandbox_fs_ls,
95                 .read = fs_read_sandbox,
96         },
97 #endif
98         {
99                 .fstype = FS_TYPE_ANY,
100                 .probe = fs_probe_unsupported,
101                 .close = fs_close_unsupported,
102                 .ls = fs_ls_unsupported,
103                 .read = fs_read_unsupported,
104                 .write = fs_write_unsupported,
105         },
106 };
107
108 static struct fstype_info *fs_get_info(int fstype)
109 {
110         struct fstype_info *info;
111         int i;
112
113         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
114                 if (fstype == info->fstype)
115                         return info;
116         }
117
118         /* Return the 'unsupported' sentinel */
119         return info;
120 }
121
122 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
123 {
124         struct fstype_info *info;
125         int part, i;
126 #ifdef CONFIG_NEEDS_MANUAL_RELOC
127         static int relocated;
128
129         if (!relocated) {
130                 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
131                                 i++, info++) {
132                         info->probe += gd->reloc_off;
133                         info->close += gd->reloc_off;
134                         info->ls += gd->reloc_off;
135                         info->read += gd->reloc_off;
136                         info->write += gd->reloc_off;
137                 }
138                 relocated = 1;
139         }
140 #endif
141
142         part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
143                                         &fs_partition, 1);
144         if (part < 0)
145                 return -1;
146
147         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
148                 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
149                                 fstype != info->fstype)
150                         continue;
151
152                 if (!info->probe(fs_dev_desc, &fs_partition)) {
153                         fs_type = info->fstype;
154                         return 0;
155                 }
156         }
157
158         return -1;
159 }
160
161 static void fs_close(void)
162 {
163         struct fstype_info *info = fs_get_info(fs_type);
164
165         info->close();
166
167         fs_type = FS_TYPE_ANY;
168 }
169
170 int fs_ls(const char *dirname)
171 {
172         int ret;
173
174         struct fstype_info *info = fs_get_info(fs_type);
175
176         ret = info->ls(dirname);
177
178         fs_type = FS_TYPE_ANY;
179         fs_close();
180
181         return ret;
182 }
183
184 int fs_read(const char *filename, ulong addr, int offset, int len)
185 {
186         struct fstype_info *info = fs_get_info(fs_type);
187         void *buf;
188         int ret;
189
190         /*
191          * We don't actually know how many bytes are being read, since len==0
192          * means read the whole file.
193          */
194         buf = map_sysmem(addr, len);
195         ret = info->read(filename, buf, offset, len);
196         unmap_sysmem(buf);
197
198         /* If we requested a specific number of bytes, check we got it */
199         if (ret >= 0 && len && ret != len) {
200                 printf("** Unable to read file %s **\n", filename);
201                 ret = -1;
202         }
203         fs_close();
204
205         return ret;
206 }
207
208 int fs_write(const char *filename, ulong addr, int offset, int len)
209 {
210         struct fstype_info *info = fs_get_info(fs_type);
211         void *buf;
212         int ret;
213
214         /*
215          * We don't actually know how many bytes are being read, since len==0
216          * means read the whole file.
217          */
218         buf = map_sysmem(addr, len);
219         ret = info->write(filename, buf, offset, len);
220         unmap_sysmem(buf);
221
222         /* If we requested a specific number of bytes, check we got it */
223         if (ret >= 0 && len && ret != len) {
224                 printf("** Unable to write file %s **\n", filename);
225                 ret = -1;
226         }
227         fs_close();
228
229         return ret;
230 }
231
232 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
233                 int fstype, int cmdline_base)
234 {
235         unsigned long addr;
236         const char *addr_str;
237         const char *filename;
238         unsigned long bytes;
239         unsigned long pos;
240         int len_read;
241         unsigned long time;
242
243         if (argc < 2)
244                 return CMD_RET_USAGE;
245         if (argc > 7)
246                 return CMD_RET_USAGE;
247
248         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
249                 return 1;
250
251         if (argc >= 4) {
252                 addr = simple_strtoul(argv[3], NULL, cmdline_base);
253         } else {
254                 addr_str = getenv("loadaddr");
255                 if (addr_str != NULL)
256                         addr = simple_strtoul(addr_str, NULL, 16);
257                 else
258                         addr = CONFIG_SYS_LOAD_ADDR;
259         }
260         if (argc >= 5) {
261                 filename = argv[4];
262         } else {
263                 filename = getenv("bootfile");
264                 if (!filename) {
265                         puts("** No boot file defined **\n");
266                         return 1;
267                 }
268         }
269         if (argc >= 6)
270                 bytes = simple_strtoul(argv[5], NULL, cmdline_base);
271         else
272                 bytes = 0;
273         if (argc >= 7)
274                 pos = simple_strtoul(argv[6], NULL, cmdline_base);
275         else
276                 pos = 0;
277
278         time = get_timer(0);
279         len_read = fs_read(filename, addr, pos, bytes);
280         time = get_timer(time);
281         if (len_read <= 0)
282                 return 1;
283
284         printf("%d bytes read in %lu ms", len_read, time);
285         if (time > 0) {
286                 puts(" (");
287                 print_size(len_read / time * 1000, "/s");
288                 puts(")");
289         }
290         puts("\n");
291
292         setenv_hex("filesize", len_read);
293
294         return 0;
295 }
296
297 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
298         int fstype)
299 {
300         if (argc < 2)
301                 return CMD_RET_USAGE;
302         if (argc > 4)
303                 return CMD_RET_USAGE;
304
305         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
306                 return 1;
307
308         if (fs_ls(argc >= 4 ? argv[3] : "/"))
309                 return 1;
310
311         return 0;
312 }
313
314 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
315                 int fstype, int cmdline_base)
316 {
317         unsigned long addr;
318         const char *filename;
319         unsigned long bytes;
320         unsigned long pos;
321         int len;
322         unsigned long time;
323
324         if (argc < 6 || argc > 7)
325                 return CMD_RET_USAGE;
326
327         if (fs_set_blk_dev(argv[1], argv[2], fstype))
328                 return 1;
329
330         filename = argv[3];
331         addr = simple_strtoul(argv[4], NULL, cmdline_base);
332         bytes = simple_strtoul(argv[5], NULL, cmdline_base);
333         if (argc >= 7)
334                 pos = simple_strtoul(argv[6], NULL, cmdline_base);
335         else
336                 pos = 0;
337
338         time = get_timer(0);
339         len = fs_write(filename, addr, pos, bytes);
340         time = get_timer(time);
341         if (len <= 0)
342                 return 1;
343
344         printf("%d bytes written in %lu ms", len, time);
345         if (time > 0) {
346                 puts(" (");
347                 print_size(len / time * 1000, "/s");
348                 puts(")");
349         }
350         puts("\n");
351
352         return 0;
353 }