]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/fs.c
fs: Move ls and read methods into ext4, fat
[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 <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 }