?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 6

Line No. Rev Author Line
1 6 kaklik /*! \file fat.c \brief FAT16/32 file system driver. */
2 //*****************************************************************************
3 //
4 // File Name : 'fat.c'
5 // Title : FAT16/32 file system driver
6 // Author : Pascal Stang
7 // Date : 11/07/2000
8 // Revised : 12/12/2000
9 // Version : 0.3
10 // Target MCU : ATmega103 (should work for Atmel AVR Series)
11 // Editor Tabs : 4
12 //
13 // This code is based in part on work done by Jesper Hansen for his
14 // YAMPP MP3 player project.
15 //
16 // NOTE: This code is currently below version 1.0, and therefore is considered
17 // to be lacking in some functionality or documentation, or may not be fully
18 // tested. Nonetheless, you can expect most functions to work.
19 //
20 // This code is distributed under the GNU Public License
21 // which can be found at http://www.gnu.org/licenses/gpl.txt
22 //
23 //*****************************************************************************
24  
25  
26 #include <avr/io.h>
27 #include <avr/pgmspace.h>
28 #include <string.h>
29  
30 #include "ata.h"
31 #include "rprintf.h"
32 #include "debug.h"
33  
34 #include "fat.h"
35 #include "fatconf.h"
36  
37 // globals
38 // buffers
39 unsigned char *SectorBuffer = (unsigned char *) FAT_SECTOR_BUFFER_ADDR;
40 unsigned char *FileNameBuffer = (unsigned char *) FAT_FILENAME_BUFFER_ADDR;
41 unsigned char *PathNameBuffer = (unsigned char *) FAT_PATHNAME_BUFFER_ADDR;
42  
43 // filesystem constants/metrics
44 struct partrecord PartInfo;
45 unsigned char Fat32Enabled;
46 unsigned long FirstDataSector;
47 unsigned short BytesPerSector;
48 unsigned short SectorsPerCluster;
49 unsigned long FirstFATSector;
50 unsigned long RootDirStartCluster;
51  
52 // operating variables
53 unsigned long CurrentDirStartCluster; //< current directory starting cluster
54 struct FileInfoStruct FileInfo; //< file information for last file accessed
55 unsigned long FatInCache = 0;
56  
57  
58 /*************************************************************************/
59 /*************************************************************************/
60  
61  
62 unsigned long fatClustToSect(unsigned long clust)
63 {
64 return ((clust-2) * SectorsPerCluster) + FirstDataSector;
65 }
66  
67 unsigned int fatClusterSize(void)
68 {
69 // return the number of sectors in a disk cluster
70 return SectorsPerCluster;
71 }
72  
73 unsigned char fatInit( unsigned char device)
74 {
75 //struct partrecord *pr;
76 struct bpb710 *bpb;
77  
78 // read partition table
79 // TODO.... error checking
80 ataReadSectors(DRIVE0, 0, 1, SectorBuffer);
81 // map first partition record
82 // save partition information to global PartInfo
83 PartInfo = *((struct partrecord *) ((struct partsector *) SectorBuffer)->psPart);
84 // PartInfo = *pr;
85  
86 // Read the Partition BootSector
87 // **first sector of partition in PartInfo.prStartLBA
88 ataReadSectors( DRIVE0, PartInfo.prStartLBA, 1, SectorBuffer );
89 bpb = (struct bpb710 *) ((struct bootsector710 *) SectorBuffer)->bsBPB;
90  
91 // setup global disk constants
92 FirstDataSector = PartInfo.prStartLBA;
93 if(bpb->bpbFATsecs)
94 {
95 // bpbFATsecs is non-zero and is therefore valid
96 FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbFATsecs;
97 }
98 else
99 {
100 // bpbFATsecs is zero, real value is in bpbBigFATsecs
101 FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbBigFATsecs;
102 }
103 SectorsPerCluster = bpb->bpbSecPerClust;
104 BytesPerSector = bpb->bpbBytesPerSec;
105 FirstFATSector = bpb->bpbResSectors + PartInfo.prStartLBA;
106  
107 switch (PartInfo.prPartType)
108 {
109 case PART_TYPE_DOSFAT16:
110 case PART_TYPE_FAT16:
111 case PART_TYPE_FAT16LBA:
112 // first directory cluster is 2 by default (clusters range 2->big)
113 RootDirStartCluster = CLUST_FIRST;
114 // push data sector pointer to end of root directory area
115 //FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
116 Fat32Enabled = FALSE;
117 break;
118 case PART_TYPE_FAT32LBA:
119 case PART_TYPE_FAT32:
120 // bpbRootClust field exists in FAT32 bpb710, but not in lesser bpb's
121 RootDirStartCluster = bpb->bpbRootClust;
122 // push data sector pointer to end of root directory area
123 // need this? FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
124 Fat32Enabled = TRUE;
125 break;
126 default:
127 rprintfProgStrM("Found: No Partition!\r\n");
128 //return 1;
129 break;
130 }
131  
132 // set current directory to root (\)
133 CurrentDirStartCluster = RootDirStartCluster;
134 PathNameBuffer[0] = '\\';
135 PathNameBuffer[1] = 0;
136  
137  
138 // do debug
139 #ifdef DEBUG_FAT
140 switch (PartInfo.prPartType)
141 {
142 case PART_TYPE_DOSFAT16:
143 rprintfProgStrM("Found: DOSFAT 16\r\n");
144 break;
145 case PART_TYPE_FAT16:
146 rprintfProgStrM("Found: FAT16\r\n");
147 break;
148 case PART_TYPE_FAT16LBA:
149 rprintfProgStrM("Found: FAT16 LBA\r\n");
150 break;
151 case PART_TYPE_FAT32LBA:
152 rprintfProgStrM("Found: FAT32 LBA\r\n");
153 break;
154 case PART_TYPE_FAT32:
155 rprintfProgStrM("Found: FAT32\r\n");
156 //return 1;
157 break;
158 default:
159 rprintfProgStrM("Found: No Partition!\r\n");
160 //return 1;
161 break;
162 }
163  
164 rprintfProgStrM("First sector : "); rprintfu32(PartInfo.prStartLBA); rprintfCRLF();
165 rprintfProgStrM("Size : "); rprintfu32(PartInfo.prSize); rprintfCRLF();
166 rprintfProgStrM("bytes/sector : "); rprintfu16(bpb->bpbBytesPerSec); rprintfCRLF();
167 rprintfProgStrM("sectors/cluster : "); rprintfu08(bpb->bpbSecPerClust); rprintfCRLF();
168 rprintfProgStrM("reserved sectors: "); rprintfu16(bpb->bpbResSectors); rprintfCRLF();
169 rprintfProgStrM("FatSectors : "); rprintfu16(bpb->bpbFATsecs); rprintfCRLF();
170 rprintfProgStrM("BigFatSectors : "); rprintfu32(bpb->bpbBigFATsecs); rprintfCRLF();
171 rprintfProgStrM("Number of Fats : "); rprintfu08(bpb->bpbFATs); rprintfCRLF();
172 rprintfProgStrM("First Fat Sector: "); rprintfu32(FirstFATSector); rprintfCRLF();
173 rprintfProgStrM("First Data Sect : "); rprintfu32(FirstDataSector); rprintfCRLF();
174 rprintfProgStrM("RootDirStartClus: "); rprintfu32(RootDirStartCluster); rprintfCRLF();
175 #endif
176  
177 return 0;
178 }
179  
180 //////////////////////////////////////////////////////////////
181  
182 unsigned char fatGetDirEntry(unsigned short entry)
183 {
184 unsigned long sector;
185 struct direntry *de = 0; // avoid compiler warning by initializing
186 struct winentry *we;
187 unsigned char haveLongNameEntry;
188 unsigned char gotEntry;
189 unsigned short b;
190 int i,index;
191 char *fnbPtr;
192 unsigned short entrycount = 0;
193  
194 // read dir data
195 sector = fatClustToSect(CurrentDirStartCluster);
196  
197 haveLongNameEntry = 0;
198 gotEntry = 0;
199  
200 index = 16; // crank it up
201  
202 //while(entrycount < entry)
203 while(1)
204 {
205 if(index == 16) // time for next sector ?
206 {
207 ataReadSectors( DRIVE0, sector++, 1, SectorBuffer);
208 de = (struct direntry *) SectorBuffer;
209 index = 0;
210 }
211  
212 // check the status of this directory entry slot
213 if(de->deName[0] == 0x00)
214 {
215 // slot is empty and this is the end of directory
216 gotEntry = 0;
217 break;
218 }
219 else if(de->deName[0] == 0xE5)
220 {
221 // this is an empty slot
222 // do nothing and move to the next one
223 }
224 else
225 {
226 // this is a valid and occupied entry
227 // is it a part of a long file/dir name?
228 if(de->deAttributes == ATTR_LONG_FILENAME)
229 {
230 // we have a long name entry
231 // cast this directory entry as a "windows" (LFN: LongFileName) entry
232 we = (struct winentry *) de;
233  
234 b = WIN_ENTRY_CHARS*( (we->weCnt-1) & 0x0f); // index into string
235 fnbPtr = &FileNameBuffer[b];
236 for (i=0;i<5;i++) *fnbPtr++ = we->wePart1[i*2]; // copy first part
237 for (i=0;i<6;i++) *fnbPtr++ = we->wePart2[i*2]; // second part
238 for (i=0;i<2;i++) *fnbPtr++ = we->wePart3[i*2]; // and third part
239 if (we->weCnt & WIN_LAST) *fnbPtr = 0; // in case dirnamelength is multiple of 13, add termination
240 if ((we->weCnt & 0x0f) == 1) haveLongNameEntry = 1; // flag that we have a complete long name entry set
241 }
242 else
243 {
244 // we have a short name entry
245  
246 // check if this is the short name entry corresponding
247 // to the end of a multi-part long name entry
248 if(haveLongNameEntry)
249 {
250 // a long entry name has been collected
251 if(entrycount == entry)
252 {
253 // desired entry has been found, break out
254 gotEntry = 1;
255 break;
256 }
257 // otherwise
258 haveLongNameEntry = 0; // clear long name flag
259 entrycount++; // increment entry counter
260 }
261 else
262 {
263 // entry is a short name (8.3 format) without a
264 // corresponding multi-part long name entry
265 fnbPtr = FileNameBuffer;
266 for (i=0;i<8;i++) *fnbPtr++ = de->deName[i]; // copy name
267 *fnbPtr++ = '.'; // insert '.'
268 for (i=0;i<3;i++) *fnbPtr++ = de->deExtension[i]; // copy extension
269 *fnbPtr = 0; // null-terminate
270  
271 if(entrycount == entry)
272 {
273 // desired entry has been found, break out
274 gotEntry = 1;
275 break;
276 }
277 // otherwise
278 entrycount++; // increment entry counter
279 }
280 }
281 }
282 // next directory entry
283 de++;
284 // next index
285 index++;
286 }
287  
288 // we have a file/dir to return
289 // store file/dir starting cluster (start of data)
290 FileInfo.StartCluster = (unsigned long) ((unsigned long)de->deHighClust << 16) + de->deStartCluster;
291 // store file/dir size
292 // (note: size field for subdirectory entries is always zero)
293 FileInfo.Size = de->deFileSize;
294 // store file/dir attributes
295 FileInfo.Attr = de->deAttributes;
296 // store file/dir creation time
297 FileInfo.CreateTime = de->deCTime[0] | de->deCTime[1]<<8;
298 // store file/dir creation date
299 FileInfo.CreateTime = de->deCDate[0] | de->deCDate[1]<<8;
300  
301 return gotEntry;
302 }
303  
304 // change directory into
305 unsigned char fatChangeDirectory(unsigned short entry)
306 {
307 // get the requested directory entry
308 if( fatGetDirEntry(entry) )
309 {
310 // make sure the entry is a directory
311 if(FileInfo.Attr & ATTR_DIRECTORY)
312 {
313 // change directories into this directory
314 // check to see if we are changing back to root directory
315 if(FileInfo.StartCluster)
316 {
317 // standard change directory
318 CurrentDirStartCluster = FileInfo.StartCluster;
319 }
320 else
321 {
322 // if startCluster pointer is zero,
323 // a change to the root directory is intended
324 // change directory to root
325 CurrentDirStartCluster = RootDirStartCluster;
326 }
327 // TODO: handle pathname properly for going up a directory
328 // set path string
329 strcat(PathNameBuffer, FileNameBuffer);
330 strcat(PathNameBuffer, "\\");
331 // return success
332 return TRUE;
333 }
334 else
335 {
336 // not a directory, cannot CD into a file!
337 return FALSE;
338 }
339 }
340 else
341 {
342 // not a valid entry, cannot CD!
343 return FALSE;
344 }
345 }
346  
347 void fatPrintDirEntry(void)
348 {
349 // print a formatted dir-style output for most recent file
350 // print date
351 rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateDate&DD_MONTH_MASK)>>DD_MONTH_SHIFT ); // month
352 rprintfChar('/');
353 rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateDate&DD_DAY_MASK)>>DD_DAY_SHIFT ); // day
354 rprintfChar('/');
355 rprintfNum(10, 4, FALSE, '0', (FileInfo.CreateDate&DD_YEAR_MASK)>>DD_YEAR_SHIFT ); // year
356 rprintfChar(' ');
357  
358 // print time
359 rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateTime&DT_HOURS_MASK)>>DT_HOURS_SHIFT ); // month
360 rprintfChar(':');
361 rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateTime&DT_MINUTES_MASK)>>DT_MINUTES_SHIFT ); // day
362 rprintfChar(':');
363 rprintfNum(10, 2, FALSE, '0', 2*(FileInfo.CreateTime&DT_2SECONDS_MASK)>>DT_2SECONDS_SHIFT ); // seconds
364 rprintfChar(' ');
365  
366 // print attributes
367 if(FileInfo.Attr & ATTR_VOLUME) rprintfChar('V'); else rprintfChar('-');
368 if(FileInfo.Attr & ATTR_DIRECTORY) rprintfChar('D'); else rprintfChar('-');
369 if(FileInfo.Attr & ATTR_READONLY) rprintfChar('R'); else rprintfChar('-');
370 if(FileInfo.Attr & ATTR_HIDDEN) rprintfChar('H'); else rprintfChar('-');
371 if(FileInfo.Attr & ATTR_SYSTEM) rprintfChar('S'); else rprintfChar('-');
372 if(FileInfo.Attr & ATTR_ARCHIVE) rprintfChar('A'); else rprintfChar('-');
373 rprintfChar(' ');
374  
375 // print filesize
376 rprintfNum(10, 8, FALSE, ' ', FileInfo.Size); // filesize
377 rprintfChar(' ');
378  
379 // print filename
380 rprintfStr(FileNameBuffer);
381 }
382  
383 void fatDumpDirSlot(unsigned short slot)
384 {
385 unsigned long sector;
386 // load correct sector
387 sector = fatClustToSect(CurrentDirStartCluster);
388 sector += slot/DIRENTRIES_PER_SECTOR;
389 // print the entry as a hex table
390 debugPrintHexTable(32, SectorBuffer+(slot<<5) );
391 }
392  
393 struct FileInfoStruct* fatGetFileInfo(void)
394 {
395 return &FileInfo;
396 }
397  
398 // return the size of the last directory entry
399 unsigned long fatGetFilesize(void)
400 {
401 return FileInfo.Size;
402 }
403  
404 // return the long name of the last directory entry
405 char* fatGetFilename(void)
406 {
407 return FileNameBuffer;
408 }
409  
410 // return the directory of the last directory entry
411 char* fatGetDirname(void)
412 {
413 return PathNameBuffer;
414 }
415  
416 // load a clusterfull of data
417 void fatLoadCluster(unsigned long cluster, unsigned char *buffer)
418 {
419 register unsigned char i;
420 // read cluster
421 //while ( ataReadSectors( DRIVE0, clust2sect(cluster), SectorsPerCluster, buffer) != 0);
422 for(i=0; i<SectorsPerCluster; i++)
423 {
424 ataReadSectors( DRIVE0, fatClustToSect(cluster)+i, 1, buffer+(i<<9) );
425 // temporary fix for wierd misaligned cluster problem
426 // (only when using FAT16?)
427 // ataReadSectors( DRIVE0, fatClustToSect(cluster+8)+i, 1, buffer+(i<<9) );
428 }
429 }
430  
431  
432 // find next cluster in the FAT chain
433 unsigned long fatNextCluster(unsigned long cluster)
434 {
435 unsigned long nextCluster;
436 unsigned long fatMask;
437 unsigned long fatOffset;
438 unsigned long sector;
439 unsigned int offset;
440  
441 // get fat offset in bytes
442 if(Fat32Enabled)
443 {
444 // four FAT bytes (32 bits) for every cluster
445 fatOffset = cluster << 2;
446 // set the FAT bit mask
447 fatMask = FAT32_MASK;
448 }
449 else
450 {
451 // two FAT bytes (16 bits) for every cluster
452 fatOffset = cluster << 1;
453 // set the FAT bit mask
454 fatMask = FAT16_MASK;
455 }
456  
457 // calculate the FAT sector that we're interested in
458 sector = FirstFATSector + (fatOffset / BytesPerSector);
459 // calculate offset of the our entry within that FAT sector
460 offset = fatOffset % BytesPerSector;
461  
462 // if we don't already have this FAT chunk loaded, go get it
463 if (sector != FatInCache)
464 {
465 // read sector of FAT table
466 while (ataReadSectors( DRIVE0, sector, 1, (unsigned char*)FAT_CACHE_ADDR) != 0);
467 FatInCache = sector;
468 }
469  
470 // read the nextCluster value
471 nextCluster = (*((unsigned long*) &((char*)FAT_CACHE_ADDR)[offset])) & fatMask;
472  
473 // check to see if we're at the end of the chain
474 if (nextCluster == (CLUST_EOFE & fatMask))
475 nextCluster = 0;
476  
477 #ifdef DEBUG_FAT
478 rprintfProgStrM(">");
479 rprintfu32(nextCluster);
480 rprintfCRLF();
481 #endif
482  
483 return nextCluster;
484 }
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3