Removed ML401 support
[mw/milkymist.git] / software / libbase / fatfs.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <endian.h>
23 #include <console.h>
24 #include <fatfs.h>
25
26 //#define DEBUG
27
28 #define BLOCK_SIZE 512
29
30 struct partition_descriptor {
31         unsigned char flags;
32         unsigned char start_head;
33         unsigned short start_cylinder;
34         unsigned char type;
35         unsigned char end_head;
36         unsigned short end_cylinder;
37         unsigned int start_sector;
38         unsigned int end_sector;
39 } __attribute__((packed));
40
41 struct firstsector {
42         unsigned char bootsector[446];
43         struct partition_descriptor partitions[4];
44         unsigned char signature[2];
45 } __attribute__((packed));
46
47
48 struct fat16_firstsector {
49         /* Common to FATxx */
50         char jmp[3];
51         char oem[8];
52         unsigned short bytes_per_sector;
53         unsigned char sectors_per_cluster;
54         unsigned short reserved_sectors;
55         unsigned char number_of_fat;
56         unsigned short max_root_entries;
57         unsigned short total_sectors_short;
58         unsigned char media_descriptor;
59         unsigned short sectors_per_fat;
60         unsigned short sectors_per_track;
61         unsigned short head_count;
62         unsigned int hidden_sectors;
63         unsigned int total_sectors;
64         
65         /* FAT16 specific */
66         unsigned char drive_nr;
67         unsigned char reserved;
68         unsigned char ext_boot_signature;
69         unsigned int id;
70         unsigned char volume_label[11];
71         unsigned char fstype[8];
72         unsigned char bootcode[448];
73         unsigned char signature[2];
74 } __attribute__((packed));
75
76 struct directory_entry {
77         unsigned char filename[8];
78         unsigned char extension[3];
79         unsigned char attributes;
80         unsigned char reserved;
81         unsigned char create_time_ms;
82         unsigned short create_time;
83         unsigned short create_date;
84         unsigned short last_access;
85         unsigned short ea_index;
86         unsigned short lastm_time;
87         unsigned short lastm_date;
88         unsigned short first_cluster;
89         unsigned int file_size;
90 } __attribute__((packed));
91
92 struct directory_entry_lfn {
93         unsigned char seq;
94         unsigned short name1[5]; /* UTF16 */
95         unsigned char attributes;
96         unsigned char reserved;
97         unsigned char checksum;
98         unsigned short name2[6];
99         unsigned short first_cluster;
100         unsigned short name3[2];
101 } __attribute__((packed));
102
103 #define PARTITION_TYPE_FAT16            0x06
104 #define PARTITION_TYPE_FAT32            0x0b
105
106 static int fatfs_partition_start_sector;        /* Sector# of the beginning of the FAT16 partition */
107
108 static int fatfs_sectors_per_cluster;
109 static int fatfs_fat_sector;                    /* Sector of the first FAT */
110 static int fatfs_fat_entries;                   /* Number of entries in the FAT */
111 static int fatfs_max_root_entries;
112 static int fatfs_root_table_sector;             /* Sector# of the beginning of the root table */
113
114 static int fatfs_fat_cached_sector;
115 static unsigned short int fatfs_fat_sector_cache[BLOCK_SIZE/2];
116
117 static int fatfs_dir_cached_sector;
118 static struct directory_entry fatfs_dir_sector_cache[BLOCK_SIZE/sizeof(struct directory_entry)];
119
120 static int fatfs_data_start_sector;
121
122 int fatfs_init()
123 {
124         struct firstsector s0;
125         struct fat16_firstsector s;
126         int i;
127
128         if(/* !cf_init() */ 1) {
129                 printf("E: Unable to initialize memory card driver\n");
130                 return 0;
131         }
132         
133         /* Read sector 0, with partition table */
134         if(/* !cf_readblock(0, (void *)&s0) */ 1) {
135                 printf("E: Unable to read block 0\n");
136                 return 0;
137         }
138
139         fatfs_partition_start_sector = -1;
140         for(i=0;i<4;i++)
141                 if((s0.partitions[i].type == PARTITION_TYPE_FAT16)
142                  ||(s0.partitions[i].type == PARTITION_TYPE_FAT32)) {
143 #ifdef DEBUG
144                         printf("I: Using partition #%d: start sector %08x, end sector %08x\n", i,
145                                 le32toh(s0.partitions[i].start_sector), le32toh(s0.partitions[i].end_sector));
146 #endif
147                         fatfs_partition_start_sector = le32toh(s0.partitions[i].start_sector);
148                         break;
149                 }
150         if(fatfs_partition_start_sector == -1) {
151                 printf("E: No FAT partition was found\n");
152                 return 0;
153         }
154         
155         /* Read first FAT16 sector */
156         if(/* !cf_readblock(fatfs_partition_start_sector, (void *)&s) */ 1) {
157                 printf("E: Unable to read first FAT sector\n");
158                 return 0;
159         }
160         
161 #ifdef DEBUG
162         {
163                 char oem[9];
164                 char volume_label[12];
165                 memcpy(oem, s.oem, 8);
166                 oem[8] = 0;
167                 memcpy(volume_label, s.volume_label, 11);
168                 volume_label[11] = 0;
169                 printf("I: OEM name: %s\n", oem);
170                 printf("I: Volume label: %s\n", volume_label);
171         }
172 #endif
173         
174         if(le16toh(s.bytes_per_sector) != BLOCK_SIZE) {
175                 printf("E: Unexpected number of bytes per sector\n");
176                 return 0;
177         }
178         fatfs_sectors_per_cluster = s.sectors_per_cluster;
179         
180         fatfs_fat_entries = (le16toh(s.sectors_per_fat)*BLOCK_SIZE)/2;
181         fatfs_fat_sector = fatfs_partition_start_sector + 1;
182         fatfs_fat_cached_sector = -1;
183         
184         fatfs_max_root_entries = le16toh(s.max_root_entries);
185         fatfs_root_table_sector = fatfs_fat_sector + s.number_of_fat*le16toh(s.sectors_per_fat);
186         fatfs_dir_cached_sector = -1;
187         
188         fatfs_data_start_sector = fatfs_root_table_sector + (fatfs_max_root_entries*sizeof(struct directory_entry))/BLOCK_SIZE;
189
190         if(fatfs_max_root_entries == 0) {
191                 printf("E: Your memory card uses FAT32, which is not supported.\n");
192                 printf("E: Please reformat your card using FAT16, e.g. use mkdosfs -F 16\n");
193                 printf("E: FAT32 support would be an appreciated contribution.\n");
194                 return 0;
195         }
196         
197 #ifdef DEBUG
198         printf("I: Cluster is %d sectors, FAT has %d entries, FAT 1 is at sector %d,\nI: root table is at sector %d (max %d), data is at sector %d\n",
199                 fatfs_sectors_per_cluster, fatfs_fat_entries, fatfs_fat_sector,
200                 fatfs_root_table_sector, fatfs_max_root_entries,
201                 fatfs_data_start_sector);
202 #endif
203         return 1;
204 }
205
206 static int fatfs_read_fat(int offset)
207 {
208         int wanted_sector;
209         
210         if((offset < 0) || (offset >= fatfs_fat_entries))
211                 return -1;
212                 
213         wanted_sector = fatfs_fat_sector + (offset*2)/BLOCK_SIZE;
214         if(wanted_sector != fatfs_fat_cached_sector) {
215                 if(/* !cf_readblock(wanted_sector, (void *)&fatfs_fat_sector_cache) */ 1) {
216                         printf("E: Memory card failed (FAT), sector %d\n", wanted_sector);
217                         return -1;
218                 }
219                 fatfs_fat_cached_sector = wanted_sector;
220         }
221         
222         return le16toh(fatfs_fat_sector_cache[offset % (BLOCK_SIZE/2)]);
223 }
224
225 static const struct directory_entry *fatfs_read_root_directory(int offset)
226 {
227         int wanted_sector;
228         
229         if((offset < 0) || (offset >= fatfs_max_root_entries))
230                 return NULL;
231
232         wanted_sector = fatfs_root_table_sector + (offset*sizeof(struct directory_entry))/BLOCK_SIZE;
233
234         if(wanted_sector != fatfs_dir_cached_sector) {
235                 if(/* !cf_readblock(wanted_sector, (void *)&fatfs_dir_sector_cache) */ 1) {
236                         printf("E: Memory card failed (Rootdir), sector %d\n", wanted_sector);
237                         return NULL;
238                 }
239                 fatfs_dir_cached_sector = wanted_sector;
240         }
241         return &fatfs_dir_sector_cache[offset % (BLOCK_SIZE/sizeof(struct directory_entry))];
242 }
243
244 static void lfn_to_ascii(const struct directory_entry_lfn *entry, char *name, int terminate)
245 {
246         int i;
247         unsigned short c;
248
249         for(i=0;i<5;i++) {
250                 c = le16toh(entry->name1[i]);
251                 if(c <= 255) {
252                         *name = c;
253                         name++;
254                         if(c == 0) return;
255                 }
256         }
257         for(i=0;i<6;i++) {
258                 c = le16toh(entry->name2[i]);
259                 if(c <= 255) {
260                         *name = c;
261                         name++;
262                         if(c == 0) return;
263                 }
264         }
265         for(i=0;i<2;i++) {
266                 c = le16toh(entry->name3[i]);
267                 if(c <= 255) {
268                         *name = c;
269                         name++;
270                         if(c == 0) return;
271                 }
272         }
273
274         if(terminate)
275                 *name = 0;
276 }
277
278 static int fatfs_is_regular(const struct directory_entry *entry)
279 {
280         return ((entry->attributes & 0x10) == 0)
281                 && ((entry->attributes & 0x08) == 0)
282                 && (entry->filename[0] != 0xe5);
283 }
284
285 int fatfs_list_files(fatfs_dir_callback cb, void *param)
286 {
287         const struct directory_entry *entry;
288         char fmtbuf[8+1+3+1];
289         char longname[131];
290         int has_longname;
291         int i, j, k;
292
293         has_longname = 0;
294         longname[sizeof(longname)-1] = 0; /* avoid crashing when reading a corrupt FS */
295         for(k=0;k<fatfs_max_root_entries;k++) {
296                 entry = fatfs_read_root_directory(k);
297 #ifdef DEBUG
298                 printf("I: Read entry with attribute %02x\n", entry->attributes);
299 #endif
300                 if(entry->attributes == 0x0f) {
301                         const struct directory_entry_lfn *entry_lfn;
302                         unsigned char frag;
303                         int terminate;
304
305                         entry_lfn = (const struct directory_entry_lfn *)entry;
306                         frag = entry_lfn->seq & 0x3f;
307                         terminate = entry_lfn->seq & 0x40;
308                         if(frag*13 < sizeof(longname)) {
309                                 lfn_to_ascii((const struct directory_entry_lfn *)entry, &longname[(frag-1)*13], terminate);
310                                 if(frag == 1) has_longname = 1;
311                         }
312                         continue;
313                 } else {
314                         if(!fatfs_is_regular(entry)) {
315                                 has_longname = 0;
316                                 continue;
317                         }
318                 }
319                 if(entry == NULL) return 0;
320                 if(entry->filename[0] == 0) {
321                         has_longname = 0;
322                         break;
323                 }
324                 j = 0;
325                 for(i=0;i<8;i++) {
326                         if(entry->filename[i] == ' ') break;
327                         fmtbuf[j++] = entry->filename[i];
328                 }
329                 fmtbuf[j++] = '.';
330                 for(i=0;i<3;i++) {
331                         if(entry->extension[i] == ' ') break;
332                         fmtbuf[j++] = entry->extension[i];
333                 }
334                 fmtbuf[j++] = 0;
335                 if(!cb(fmtbuf, has_longname ? longname : fmtbuf, param)) return 0;
336                 has_longname = 0;
337         }
338         return 1;
339 }
340
341 static const struct directory_entry *fatfs_find_file_by_name(const char *filename)
342 {
343         char searched_filename[8];
344         char searched_extension[3];
345         char *dot;
346         const char *c;
347         int i;
348         const struct directory_entry *entry;
349         
350         dot = strrchr(filename, '.');
351         if(dot == NULL)
352                 return NULL;
353         
354         memset(searched_filename, ' ', 8);
355         memset(searched_extension, ' ', 3);
356         i = 0;
357         for(c=filename;c<dot;c++)
358                 searched_filename[i++] = toupper(*c);
359                 
360         i = 0;
361         for(c=dot+1;*c!=0;c++)
362                 searched_extension[i++] = toupper(*c);
363                 
364         for(i=0;i<fatfs_max_root_entries;i++) {
365                 entry = fatfs_read_root_directory(i);
366                 if(entry == NULL) break;
367                 if(entry->filename[0] == 0) break;
368                 if(!fatfs_is_regular(entry)) continue;
369                 if(!memcmp(searched_filename, entry->filename, 8)
370                  &&!memcmp(searched_extension, entry->extension, 3))
371                         return entry;
372         }
373         return NULL;
374 }
375
376 static int fatfs_load_cluster(int clustern, char *buffer, int maxsectors)
377 {
378         int startsector;
379         int i;
380         int toread;
381         
382         clustern = clustern - 2;
383         startsector = fatfs_data_start_sector + clustern*fatfs_sectors_per_cluster;
384         if(maxsectors < fatfs_sectors_per_cluster)
385                 toread = maxsectors;
386         else
387                 toread = fatfs_sectors_per_cluster;
388         for(i=0;i<toread;i++)
389                 if(/* !cf_readblock(startsector+i, (unsigned char *)buffer+i*CF_BLOCK_SIZE) */ 1) {
390                         printf("E: Memory card failed (Cluster), sector %d\n", startsector+i);
391                         return 0;
392                 }
393         return 1;
394 }
395
396 int fatfs_load(const char *filename, char *buffer, int size, int *realsize)
397 {
398         const struct directory_entry *entry;
399         int cluster_size;
400         int cluster;
401         int n;
402         
403         cluster_size = fatfs_sectors_per_cluster*BLOCK_SIZE;
404         size /= BLOCK_SIZE;
405         
406         entry = fatfs_find_file_by_name(filename);
407         if(entry == NULL) {
408                 printf("E: File not found: %s\n", filename);
409                 return 0;
410         }
411         
412         if(realsize != NULL) *realsize = le32toh(entry->file_size);
413         
414         n = 0;
415         cluster = le16toh(entry->first_cluster);
416         while(size > 0) {
417                 if(!fatfs_load_cluster(cluster, buffer+n*cluster_size, size))
418                         return 0;
419                 size -= fatfs_sectors_per_cluster;
420                 n++;
421                 cluster = fatfs_read_fat(cluster);
422                 if(cluster >= 0xFFF8) break;
423                 if(cluster == -1) return 0;
424         }
425         //putsnonl("\n");
426         
427         return n*cluster_size;
428 }
429
430 void fatfs_done()
431 {
432         /* cf_done(); */
433 }