VLSI Solution Oy VLSI Solution Oy Evaluation MP3 Player Source Code Documentation

Main Page | Class List | File List | Class Members | File Members | Related Pages

filesys.c File Reference

File system functions, Implemented: FAT16, FAT32. More...

#include "board.h"
#include "filesys.h"
#include "storage.h"
#include "console.h"
#include "mmc.h"
#include "display.h"

Include dependency graph for filesys.c:

Include dependency graph

Go to the source code of this file.

Classes

struct  fragmentEntry
 Fragment Table. More...

struct  directoryStack
 Directory traversing structure. More...


Defines

#define MAX_NUMBER_FRAGMENTS   10
 Maximum allowable number of fragments in file.

#define MAX_NUMBER_SUBDIRECTORIES   5
 Maximum number of nested subdirectories.


Functions

void PConvertSectorToCluster (unsigned long *sector)
 Convert sector number to cluster number.

void PConvertClusterToSector (unsigned long *cluster)
 Convert cluster number to sector number.

unsigned long GetFatEntry (unsigned long clusterNumber)
 Return the FAT entry for cluster clusterNumber.

void WriteClusterChain ()
 Write a cluster chain to FAT for a fragment.

unsigned char ScanForFreeSector ()
 Search for next free sector.

unsigned long GetNextSector (unsigned long currentSector)
 Calculate next sector from currentSector.

Public unsigned char BuildFragmentTable ()
 Build a fragment table starting from current sector.

unsigned char LoadNextSector ()
 Traverse to next sector in file or directory.

Public unsigned char FGetChar ()
 Read a character from current file.

Public unsigned char OpenFile (unsigned int fileNumber)
 Open a file for reading.

unsigned char FatInitGlobals ()
 Decipher structure of FAT volume and set globals accordingly.

Public unsigned char InitFileSystem ()
 Start the filing system and initialize all necessary subsystems.


Variables

data unsigned long fatStart
 Starting sector of FAT table.

data unsigned long rootStart
 Starting sector of root directory.

data unsigned long dataStart
 (In FAT the start is cluster 2, so dataStart actually points to 2 clusters before the start of data area)

data unsigned char fatSectorsPerCluster
 FAT Global sectors per cluster.

xdata struct fragmentEntry fragment [MAX_NUMBER_FRAGMENTS]
 Fragment Table.

xdata unsigned long fileSize
 Size of current file to play.

xdata struct directoryStack dirStack [MAX_NUMBER_SUBDIRECTORIES]
 Directory traversing structure.

xdata unsigned char dirLevel = 0
 Current directory level, 0=Root directory.

xdata unsigned long freeSector = 0
 Next free cluster number.

xdata char currentFileName [12]
 8 first characters of current file name


Detailed Description

File system functions, Implemented: FAT16, FAT32.

Definition in file filesys.c.


Define Documentation

#define MAX_NUMBER_FRAGMENTS   10
 

Maximum allowable number of fragments in file.

Definition at line 37 of file filesys.c.

Referenced by BuildFragmentTable().

#define MAX_NUMBER_SUBDIRECTORIES   5
 

Maximum number of nested subdirectories.

Definition at line 50 of file filesys.c.

Referenced by OpenFile().


Function Documentation

Public unsigned char BuildFragmentTable void   ) 
 

Build a fragment table starting from current sector.

Returns number of fragments in song. This function is used to get fast access to the filesystem when playing so cluster chain needs not be followed when the song is playing, that would be too slow with MMC cards without extra buffer memory for the file allocation tables.

Note: filesys.c module does not use the fragment table internally. it is written to be a service to the player routine, which uses storage.c module directly for disk access after using the filesys.c module for finding a file to play. I am listening to Darude's Sandstorm while coding this.

In terms of memory allocation, this function is devilish. At one stage temp.l is used just to make compiler use memory at temp.l instead of spilling to another unnecessary temp variable...

Definition at line 397 of file filesys.c.

References Address::b, Address::B::b0, Address::B::b1, Address::B::b3, dataStart, diskSect, DiskBlock::Fat16Table, DiskBlock::Fat32Table, fatSectorsPerCluster, fatStart, fragment, IS_FAT_32, Address::l, Temp::l, fragmentEntry::length, MAX_NUMBER_FRAGMENTS, Public, ReadDiskSector(), sectorAddress, fragmentEntry::start, and temp.

Referenced by PlayCurrentFile().

00397 { 00398 00399 unsigned char c=0; 00400 addressType this,next; 00401 addressType fatSector; 00402 unsigned char entryNumber; 00403 00404 00405 //as long as the sectorAddress is "sane"... 00406 while (!(sectorAddress.b.b3 & 0x80)){ 00407 00408 fragment[c].start = sectorAddress.l; 00409 fragment[c].length = fatSectorsPerCluster; 00410 00411 /* Find cluster entry for the current sector */ 00412 00413 /* in how manyth sector from start of data area are we? ->this */ 00414 this.l = sectorAddress.l - dataStart; 00415 /* convert from CurrentSectorN to currentClusterN */ 00416 this.l /= fatSectorsPerCluster; 00417 /* this.l is now the current cluster number */ 00418 00419 00420 /* now let's find the FAT entry for this.l cluster */ 00421 if (!IS_FAT_32){ //FAT16 00422 entryNumber = this.b.b0; /* 256 entries / page in FAT16 table */ 00423 fatSector.l = this.l >> 8; /* Div by n of entries/page in FAT16 tbl*/ 00424 }else{ //FAT32 00425 entryNumber = (this.b.b0 & 0x7f); /* 128 entries/page in FAT32 table */ 00426 fatSector.l = this.l >> 7; /* Div by n of entries/page in FAT32 tbl*/ 00427 } 00428 fatSector.l += fatStart; 00429 /* fatSector.l is now the DISK SECTOR NUMBER CONTAINING THE FAT table */ 00430 /* read this page into memory */ 00431 ReadDiskSector(fatSector.l); 00432 00433 if (!IS_FAT_32){ //FAT16 00434 next.l = diskSect.Fat16Table[entryNumber]; /* get next cluster n */ 00435 /* Check for FAT16 end-of-file condition */ 00436 if ((next.b.b1 == 0xff) && (next.b.b0 == 0xff)){ 00437 /* FAT16 End of file */ 00438 next.b.b3 = 0xff; /* return a large value (fat32 compatible) */ 00439 } 00440 }else{ //FAT32 00441 next.l = diskSect.Fat32Table[entryNumber]&0x0fffffff; 00442 } 00443 /* next.l is the FAT entry (next cluster number) */ 00444 00445 00446 ConsoleWrite("\rFragment start: cluster "); 00447 ConsolePutUInt(this.l); 00448 ConsoleWrite("sector "); 00449 ConsolePutUInt(fragment[c].start); 00450 00451 while (next.l==(this.l+1)){ 00452 //Not a fragment break -- continue to next entry 00453 00454 //in this temp.l is used only to allow compiler memory spilling to temp 00455 temp.l = fragment[c].length; 00456 temp.l += fatSectorsPerCluster; 00457 fragment[c].length = temp.l; 00458 00459 entryNumber++; 00460 00461 // --- Check for a page break 00462 if (entryNumber==0){ //entryNumber has rolled over!!!! (8bit char) 00463 //FAT16 table page border is reached 00464 fatSector.l++; //Advance to next page; 00465 entryNumber=0; 00466 ReadDiskSector(fatSector.l); 00467 } 00468 if (IS_FAT_32 && (entryNumber==128)){ 00469 //FAT32 table page border is reached 00470 fatSector.l++; 00471 entryNumber=0; 00472 ReadDiskSector(fatSector.l); 00473 } 00474 00475 // --- Advance to next cluster 00476 this.l = next.l; 00477 00478 if (!IS_FAT_32){ 00479 //FAT16 get next cluster n 00480 next.l = diskSect.Fat16Table[entryNumber]; 00481 if ((next.b.b1==0xff)&&(next.b.b0==0xff)){ 00482 //FAT16 end-of-file 00483 next.b.b3 = 0xff; //mark end-of-file (FAT32 compatible) 00484 } 00485 }else{ 00486 //FAT32 get next cluster n 00487 next.l = diskSect.Fat32Table[entryNumber]; 00488 } 00489 }//This repeats until there is a discontinuity 00490 00491 /* next.l now has the cluster entry for last cluster in fragment 00492 it has a high value if eof (see FAT spec) */ 00493 00494 00495 ConsoleWrite("Size: "); 00496 ConsolePutUInt(fragment[c].length); 00497 ConsoleWrite("sectors."); 00498 00499 //EOF test 00500 if ((next.b.b3&0x08) //Quick test 00501 && ((next.l>0x0ffffff0) | !IS_FAT_32)){ //Complete test 00502 //EOF 00503 ConsoleWrite(" <EOF>\r"); 00504 sectorAddress.b.b3 = 0xff; 00505 }else{ 00506 00507 //Determine next physical sector for next fragment 00508 sectorAddress.l = next.l; 00509 sectorAddress.l *= fatSectorsPerCluster; 00510 sectorAddress.l += dataStart; 00511 } 00512 00513 c++; //Advance to next fragment number 00514 00515 if (c==MAX_NUMBER_FRAGMENTS){ 00516 //End of RAM space allocated for fragment table 00517 //Force end-of-file 00518 sectorAddress.b.b3=0xff; 00519 } 00520 00521 }//break or continue to next cluster 00522 00523 return c; //Return number of fragments; 00524 }

Here is the call graph for this function:

unsigned char FatInitGlobals  ) 
 

Decipher structure of FAT volume and set globals accordingly.

Definition at line 794 of file filesys.c.

References DiskBlock::Fat::Extensions::_16, DiskBlock::Fat::Extensions::_32, DiskBlock::Fat::BPB_BytsPerSec, DiskBlock::Fat::BPB_FATSz16, DiskBlock::Fat::Extensions::Fat32Specific::BPB_FATSz32, DiskBlock::Fat::BPB_HiddSec, DiskBlock::Fat::BPB_NumFATs, DiskBlock::Fat::BPB_RootEntCnt, DiskBlock::Fat::BPB_RsvdSecCnt, DiskBlock::Fat::BPB_SecPerClus, DiskBlock::Fat::BPB_TotSec16, DiskBlock::Fat::BPB_TotSec32, DiskBlock::Fat::Extensions::Fat16Specific::BS_FilSysType, DiskBlock::Fat::Extensions::Fat32Specific::BS_FilSysType, DiskBlock::Fat::BS_OEMName, DiskBlock::Fat::Extensions::Fat16Specific::BS_VolLab, DiskBlock::Fat::Extensions::Fat32Specific::BS_VolLab, Temp::c, dataStart, diskSect, DiskBlock::Fat::ext, DiskBlock::fat, fatSectorsPerCluster, fatStart, IS_FAT_32, Address::l, rootStart, sectorAddress, and temp.

Referenced by InitFileSystem().

00794 { 00795 00796 ConsoleWrite("Formatter signature:"); 00797 for (temp.c=0; temp.c<8; temp.c++){ 00798 ConsolePutChar(diskSect.fat.BS_OEMName[temp.c]); 00799 } 00800 ConsoleWrite("\rBytes per sector: "); 00801 ConsolePutUInt(diskSect.fat.BPB_BytsPerSec); 00802 ConsoleWrite("\rSectors per Cluster: "); 00803 ConsolePutUInt(diskSect.fat.BPB_SecPerClus); 00804 ConsoleWrite("\rReserved sectors: "); 00805 ConsolePutUInt(diskSect.fat.BPB_RsvdSecCnt); 00806 ConsoleWrite("\rNumber of FATs: "); 00807 ConsolePutUInt(diskSect.fat.BPB_NumFATs); 00808 ConsoleWrite("\rRoot entries: "); 00809 ConsolePutUInt(diskSect.fat.BPB_RootEntCnt); 00810 ConsoleWrite("\rTotal Sectors 16: "); 00811 ConsolePutUInt(diskSect.fat.BPB_TotSec16); 00812 ConsoleWrite("\rFat Size 16: "); 00813 ConsolePutUInt(diskSect.fat.BPB_FATSz16); 00814 ConsoleWrite("\rHidden Sectors: "); 00815 ConsolePutUInt(diskSect.fat.BPB_HiddSec); 00816 ConsoleWrite("\rTotal Sectors 32: "); 00817 ConsolePutUInt(diskSect.fat.BPB_TotSec32); 00818 00819 00820 00821 /* Determine FAT Type (16/32) */ 00822 /* This should be done better, but it'll do for now. */ 00823 IS_FAT_32 = 1; 00824 if (diskSect.fat.BPB_RootEntCnt) 00825 IS_FAT_32 = 0; /* FAT32 does not have separate root entries. */ 00826 00827 ConsoleWrite("\rFile system is "); 00828 if (IS_FAT_32){ 00829 ConsoleWrite("FAT32"); 00830 } else { 00831 ConsoleWrite("FAT16"); 00832 } 00833 00834 ConsoleWrite("\rFile system signature is "); 00835 for (temp.c=0;temp. c<8; temp.c++) 00836 if (IS_FAT_32){ 00837 ConsolePutChar(diskSect.fat.ext._32.BS_FilSysType[temp.c]); 00838 } else { 00839 ConsolePutChar(diskSect.fat.ext._16.BS_FilSysType[temp.c]); 00840 } 00841 ConsoleWrite("\rVolume Label is "); 00842 for (temp.c=0; temp.c<11; temp.c++) 00843 if (IS_FAT_32){ 00844 ConsolePutChar(diskSect.fat.ext._32.BS_VolLab[temp.c]); 00845 } else { 00846 ConsolePutChar(diskSect.fat.ext._16.BS_VolLab[temp.c]); 00847 } 00848 /* OK, let's calculate */ 00849 /* First, let's get rid of the idea that we have byte addresses 00850 in the file system. Nope, let's only deal in physical disk 00851 sectors of 512 bytes. First we convert the FAT byter per sector 00852 value to "512B disk sectors per fat sector" value. */ 00853 00854 diskSect.fat.BPB_BytsPerSec /= 512; 00855 00856 /* Then we adjust the Sector per Cluster to mean physical disk 00857 sectors. in 99% of the cases it is already so because bytes 00858 per sector almost always is 512 in FAT. Maximum cluster size 00859 is 65536 bytes (128 disk sectors). */ 00860 00861 fatSectorsPerCluster = 00862 diskSect.fat.BPB_SecPerClus *= diskSect.fat.BPB_BytsPerSec; 00863 /* Note: BPB_BytsPerSec has already been divided by 512 */ 00864 00865 ConsoleWrite("\rSectors per Cluster: "); 00866 ConsolePutUInt(fatSectorsPerCluster); 00867 00868 fatStart = (unsigned long)sectorAddress.l 00869 + (unsigned long)diskSect.fat.BPB_RsvdSecCnt 00870 * (unsigned long)diskSect.fat.BPB_BytsPerSec; 00871 00872 ConsoleWrite("\rFAT Start sector: "); 00873 ConsolePutUInt(fatStart); 00874 00875 rootStart = diskSect.fat.BPB_FATSz16; 00876 if (rootStart==0){ 00877 if (!IS_FAT_32) 00878 return 0x0b; /* should be FAT32; can not find root directory */ 00879 rootStart = diskSect.fat.ext._32.BPB_FATSz32; 00880 } 00881 rootStart *= diskSect.fat.BPB_NumFATs; 00882 rootStart *= diskSect.fat.BPB_BytsPerSec; /* ADJUSTED BytsPerSec! */ 00883 rootStart += fatStart; 00884 00885 ConsoleWrite("\rRoot start sector: "); 00886 ConsolePutUInt(rootStart); 00887 00888 dataStart = diskSect.fat.BPB_RootEntCnt >> 4; 00889 dataStart += rootStart; 00890 dataStart -= (fatSectorsPerCluster*2); /*first cluster is cluster 2*/ 00891 00892 ConsoleWrite("\rData start sector: "); 00893 ConsolePutUInt(dataStart); 00894 ConsolePutChar(13); 00895 00896 return 0; 00897 }

Public unsigned char FGetChar  ) 
 

Read a character from current file.

This can be called after calling OpenFile. It is a slow method for reading character based file data. fileSize holds the number of characters still left in file to be read, check for fileSize=0 to detect end-of-file. If FGetChar is called after the end of file is reached, it does nothing and returns 0.

Definition at line 549 of file filesys.c.

References DiskBlock::Raw::buf, dataBufPtr, diskSect, fileSize, Address::l, LoadNextSector(), Public, DiskBlock::raw, ReadDiskSector(), and sectorAddress.

Referenced by GetAVIBlock().

00549 { 00550 00551 if (!fileSize) return 0; //return 0 for end-of-file 00552 00553 if (dataBufPtr==0){ 00554 /* A file has been opened but not read from yet, so read the first 00555 sector. */ 00556 ReadDiskSector(sectorAddress.l); 00557 dataBufPtr = diskSect.raw.buf; 00558 } 00559 00560 if (dataBufPtr>diskSect.raw.buf+511){ 00561 /* An end of sector has been reached, read the next sector */ 00562 if (LoadNextSector()){ 00563 /* Error, end-of-file according to FAT records */ 00564 return 0; /* must return something */ 00565 } 00566 dataBufPtr=diskSect.raw.buf; 00567 } 00568 00569 /* Everything should now be ok for reading a byte. */ 00570 00571 fileSize--; 00572 return (*dataBufPtr++); 00573 }

Here is the call graph for this function:

unsigned long GetFatEntry unsigned long  clusterNumber  ) 
 

Return the FAT entry for cluster clusterNumber.

Definition at line 81 of file filesys.c.

References diskSect, DiskBlock::Fat16Table, DiskBlock::Fat32Table, fatStart, IS_FAT_32, Address::l, ReadDiskSector(), and sectorAddress.

Referenced by ScanForFreeSector().

00081 { 00082 unsigned char entryNumber; /* entry number inside page */ 00083 00084 if (!IS_FAT_32){ //FAT16 00085 entryNumber = clusterNumber & 0xff; 00086 clusterNumber >>= 8; 00087 }else{ //FAT32 00088 entryNumber = clusterNumber & 0x7f; 00089 clusterNumber >>= 7; 00090 } 00091 clusterNumber += fatStart; 00092 if (sectorAddress.l != clusterNumber){ 00093 sectorAddress.l = clusterNumber; 00094 ReadDiskSector(sectorAddress.l); 00095 } 00096 if (IS_FAT_32){ 00097 clusterNumber=diskSect.Fat32Table[entryNumber]; 00098 return clusterNumber; 00099 } 00100 if ((clusterNumber=diskSect.Fat16Table[entryNumber])==0xffff) return 0xffffffff; 00101 return clusterNumber; 00102 }

Here is the call graph for this function:

unsigned long GetNextSector unsigned long  currentSector  ) 
 

Calculate next sector from currentSector.

Return sector address with MSB set if end of file.

This is the essence of FAT filesystem: traversing through the file allocation table to scan for cluster chains.

Definition at line 299 of file filesys.c.

References Address::b, Address::B::b0, Address::B::b1, Address::B::b3, dataStart, diskSect, DiskBlock::Fat16Table, DiskBlock::Fat32Table, fatSectorsPerCluster, fatStart, IS_FAT_32, Address::l, ReadDiskSector(), and sectorAddress.

Referenced by LoadNextSector(), and OpenFile().

00299 { 00300 addressType fatSector; 00301 unsigned char entryNumber; 00302 00303 /* how manyth sector from start of data area -> fatsector */ 00304 fatSector.l = currentSector - dataStart; 00305 00306 /* Check for cluster boundary */ 00307 /* if we're not in cluster boundary then return currentsector + 1 */ 00308 if ((fatSector.b.b0 + 1) % fatSectorsPerCluster){ 00309 return currentSector + 1; 00310 } 00311 00312 /* is the value negative? then return currentSector + 1 */ 00313 if (fatSector.b.b3 & 0x80) { 00314 return currentSector + 1; 00315 } 00316 00317 /* The trivial conditions are not met, we actually do need to 00318 look up the next sector info from FAT tables in the disk.*/ 00319 00320 /* convert fatSector from CurrentSectorN to currentClusterN */ 00321 fatSector.l /= fatSectorsPerCluster; 00322 00323 /* calculate which page (fatSector) and entry of FAT table correspond 00324 to current sector */ 00325 00326 if (!IS_FAT_32){ //FAT16 00327 entryNumber = fatSector.b.b0; /* 256 entries / page in FAT16 table */ 00328 fatSector.l >>= 8; /* Divide by 256 (n of entries/page in FAT32 table */ 00329 }else{ //FAT32 00330 entryNumber =(fatSector.b.b0 & 0x7f); /* 128 entries/page in FAT32 tbl */ 00331 fatSector.l >>= 7; /* Divide by 128 (n of entries/sector in FAT32 table */ 00332 } 00333 00334 /* Get sector address for the needed page */ 00335 fatSector.l += fatStart; 00336 00337 /* Load (if needed) table page from disk */ 00338 if (sectorAddress.l != fatSector.l){ 00339 sectorAddress.l = fatSector.l; /* (not needed because mmc.c does this) */ 00340 ReadDiskSector(fatSector.l); 00341 00342 ConsolePutChar('n'); 00343 00344 00345 } 00346 /* Now there should be correct FAT entry page in memory... */ 00347 00348 if (!IS_FAT_32){ //FAT16 00349 fatSector.l = diskSect.Fat16Table[entryNumber]; 00350 /* Check for FAT16 end-of-file condition */ 00351 if ((fatSector.b.b1 == 0xff) && (fatSector.b.b0 == 0xff)){ 00352 /* End of file */ 00353 fatSector.b.b3 = 0xff; /* return a large value (fat32 compatible) */ 00354 return fatSector.l; 00355 } 00356 }else{ //FAT32 00357 fatSector.l = diskSect.Fat32Table[entryNumber] & 0x0fffffff; 00358 /* Check for FAT32 end-of-file condition */ 00359 if ((fatSector.b.b3&0x08) //Quick test 00360 && (fatSector.l>0x0ffffff0)){ //Complete test 00361 /* End of file */ 00362 return 0xffffffff; /* return EOF*/ 00363 } 00364 } 00365 00366 00367 /* now fatSector.l contains the proper next cluster value */ 00368 00369 fatSector.l *= fatSectorsPerCluster; 00370 /* now fatSector.l contains the next sector value */ 00371 00372 fatSector.l += dataStart; 00373 /* now fatSector.l contains the proper absolute sector address */ 00374 00375 return fatSector.l; 00376 }

Here is the call graph for this function:

Public unsigned char InitFileSystem  ) 
 

Start the filing system and initialize all necessary subsystems.

Init storage and file system. FAT16 and FAT32 are supported

Definition at line 902 of file filesys.c.

References Address::b, Address::B::b0, Address::B::b1, Address::B::b2, Address::B::b3, DiskBlock::Raw::buf, dataStart, diskSect, FatInitGlobals(), fatStart, freeSector, InitStorage(), Address::l, Public, DiskBlock::raw, ReadDiskSector(), rootStart, and sectorAddress.

Referenced by main().

00902 { 00903 unsigned char c; 00904 00905 /* Initialize variables to sane values in case of error exit. */ 00906 fatStart = 0; 00907 rootStart = 0; 00908 dataStart = 0; 00909 freeSector = 0; 00910 00911 ConsoleWrite("Init: Filesystem; supports: MBR, FAT16, FAT32\r"); 00912 00913 ConsoleWrite("Trying to bring up storage...\r"); 00914 /* Initialize the storage system */ 00915 if ((c=InitStorage())){ 00916 ConsoleWrite("Storage init returns error "); 00917 ConsolePutUInt(c); 00918 ConsolePutChar(13); 00919 return c; /* Error in InitStorage */ 00920 } 00921 00922 ConsoleWrite("Storage ok.\rSector 0 read..."); 00923 00924 /* Load MBR */ 00925 sectorAddress.l = 0; /* the first sector on disk */ 00926 ReadDiskSector(0); 00927 00928 ConsoleWrite("ok.\rSector signature..."); 00929 00930 /* Ok, it should be a MBR sector. Let's verify */ 00931 if (diskSect.raw.buf[510] != 0x55) 00932 return 8; /* sector 0 is not MBR. */ 00933 if (diskSect.raw.buf[511] != 0xaa) 00934 return 8; /* sector 0 is not MBR. */ 00935 00936 ConsoleWrite("ok.\rPartition 1..."); 00937 00938 /* This checks that partition 1 is active. Alter code to allow 00939 * other partition configurations. */ 00940 if (diskSect.raw.buf[0x1be] == 0x80){ 00941 sectorAddress.b.b0 = diskSect.raw.buf[0x1c6]; 00942 sectorAddress.b.b1 = diskSect.raw.buf[0x1c7]; 00943 sectorAddress.b.b2 = diskSect.raw.buf[0x1c8]; 00944 sectorAddress.b.b3 = diskSect.raw.buf[0x1c9]; 00945 ConsoleWrite (" active"); 00946 }else{ 00947 //-------- DEBUG: Uncomment if you want to explore the sector 00948 //DumpDiskSector(); 00949 //while (!KEY_BUTTON); 00950 sectorAddress.b.b0 = diskSect.raw.buf[0x1c6]; 00951 sectorAddress.b.b1 = diskSect.raw.buf[0x1c7]; 00952 sectorAddress.b.b2 = diskSect.raw.buf[0x1c8]; 00953 sectorAddress.b.b3 = diskSect.raw.buf[0x1c9]; 00954 00955 00956 } 00957 00958 // return 9; /* No active partition*/ 00959 00960 00961 ConsoleWrite(" at sector "); 00962 ConsolePutHex8(sectorAddress.b.b3); 00963 ConsolePutHex8(sectorAddress.b.b2); 00964 ConsolePutHex8(sectorAddress.b.b1); 00965 ConsolePutHex8(sectorAddress.b.b0); 00966 ConsolePutChar('\r'); 00967 00968 00969 /* Now leave MBR and load sector 0 of partition */ 00970 //SeekDiskSectorToRead(); 00971 //ReadDiskSector(); /* to global buffer */ 00972 00973 ReadDiskSector(sectorAddress.l); 00974 00975 if (FatInitGlobals()){ 00976 return 0x0a; /* FAT init failed */ 00977 } 00978 00979 return 0; /* All ok return */ 00980 00981 }

Here is the call graph for this function:

unsigned char LoadNextSector  ) 
 

Traverse to next sector in file or directory.

End of File

Definition at line 529 of file filesys.c.

References Address::b, Address::B::b1, GetNextSector(), Address::l, ReadDiskSector(), and sectorAddress.

Referenced by FGetChar().

00529 { 00530 sectorAddress.l = GetNextSector(sectorAddress.l); 00531 if (sectorAddress.b.b1 & 0x80){ 00533 return 0x0d; /*EOF*/ 00534 } 00535 if (ReadDiskSector(sectorAddress.l)){ 00536 return 0x0d; /*EOF*/ 00537 } 00538 return 0; /* All OK return */ 00539 }

Here is the call graph for this function:

Public unsigned char OpenFile unsigned int  fileNumber  ) 
 

Open a file for reading.

Prepares the Filing System to read a data file from the storage. Files are referred to by their numbers, not file names. This makes the system generic, not necessarily needing a complex file system such as FAT. The way to assign numbers to files is implementation dependent. Returns 0 when ok, error code otherwise.

Parameters:
fileNumber number of file, starting from beginning of storage, to open.
What this function actually does, is: it starts reading the FAT records from start of the root directory, traversing through subdirectories as it encounters them. When the fileNumber'th valid record is encountered, it sets sectorAddress to point to its first data sector but doesn't load any sector. fileSize is loaded with the size in bytes indicated in the FAT record.

Additionally, if it's called with 0 as the fileNumber and it happens to see an empty directory record, it registers a new file with name RECnnnnn.WAV starting from cluster fragment[0].start with file size from fragment[0].length

Definition at line 598 of file filesys.c.

References DirRecordUnion::Entry::Attr, Temp::c, currentFileName, dataBufPtr, dataStart, DiskBlock::dir, dirLevel, dirStack, diskSect, displayText, directoryStack::entry, DirRecordUnion::entry, fatSectorsPerCluster, DirRecordUnion::Entry::FileSize, fileSize, fragment, DirRecordUnion::Entry::FstClusHi, DirRecordUnion::Entry::FstClusLo, GetNextSector(), InitMMC(), Address::l, fragmentEntry::length, MAX_NUMBER_SUBDIRECTORIES, DirRecordUnion::Entry::Name, Public, ReadDiskSector(), rootStart, directoryStack::sector, sectorAddress, fragmentEntry::start, temp, and WriteDiskSector().

Referenced by main(), and WriteClusterChain().

00598 { 00599 char tempc; 00600 00601 ConsoleWrite("\rFilesystem: Looking for file "); 00602 ConsolePutUInt(fileNumber); 00603 ConsoleWrite("... "); 00604 00605 /* Start at the start of root directory. */ 00606 dirLevel = 0; /* At root directory */ 00607 dirStack[dirLevel].sector=rootStart; 00608 dirStack[dirLevel].entry=0; 00609 00610 00611 if (fileNumber==0){ 00612 fileNumber = 32766; //use max-1 value for scanning for free entry 00613 } 00614 00615 while (fileNumber){ 00616 if (dirStack[dirLevel].entry==0){ 00617 /* At the start of new dir, load first disk sector */ 00618 while (ReadDiskSector(dirStack[dirLevel].sector)){ 00619 InitMMC; 00620 } 00621 } 00622 temp.c = dirStack[dirLevel].entry; 00623 00624 /* We are now looking at FAT directory structure. */ 00625 00626 /* Is current entry empty? */ 00627 if ((diskSect.dir[temp.c].entry.Name[0]==0) 00628 ||(diskSect.dir[temp.c].entry.Name[0]==0xe5)){ 00629 /* Yes. Are we supposed to make an entry now? */ 00630 if (fileNumber>30000){ 00631 //yes, this is actually a request to write file directory entry!; 00632 00633 fileNumber = 32767-fileNumber; 00634 00635 diskSect.dir[temp.c].entry.Name[0] ='R'; 00636 diskSect.dir[temp.c].entry.Name[1] ='E'; 00637 diskSect.dir[temp.c].entry.Name[2] ='C'; 00638 diskSect.dir[temp.c].entry.Name[7] =(fileNumber%10)+'0'; 00639 fileNumber /= 10; 00640 diskSect.dir[temp.c].entry.Name[6] =(fileNumber%10)+'0'; 00641 fileNumber /= 10; 00642 diskSect.dir[temp.c].entry.Name[5] =(fileNumber%10)+'0'; 00643 fileNumber /= 10; 00644 diskSect.dir[temp.c].entry.Name[4] =(fileNumber%10)+'0'; 00645 fileNumber /= 10; 00646 diskSect.dir[temp.c].entry.Name[3] =(fileNumber%10)+'0'; 00647 diskSect.dir[temp.c].entry.Name[8] ='W'; 00648 diskSect.dir[temp.c].entry.Name[9] ='A'; 00649 diskSect.dir[temp.c].entry.Name[10]='V'; 00650 diskSect.dir[temp.c].entry.Attr = 0; 00651 diskSect.dir[temp.c].entry.FstClusHi = (fragment[0].start >> 16); 00652 diskSect.dir[temp.c].entry.FstClusLo = (fragment[0].start & 0xffff); 00653 diskSect.dir[temp.c].entry.FileSize = (fragment[0].length); 00654 00655 ConsoleWrite(" Making Directory Entry "); 00656 WriteDiskSector(sectorAddress.l); 00657 00658 return 99; //created a FAT entry 00659 } //register file 00660 } 00661 00662 00663 /* Does current entry point to a regular file? */ 00664 /* Attributes: NO directory, NO volume id, NO system, NO hidden */ 00665 if (((diskSect.dir[temp.c].entry.Attr & 222) == 0) 00666 && (diskSect.dir[temp.c].entry.Name[0] != 0xe5) 00667 && (diskSect.dir[temp.c].entry.Name[0] != 0) ){ 00668 00669 /* It is a regular file. */ 00670 if (!(--fileNumber)){ 00671 00672 /* ------------ FILE FOUND ------------- */ 00673 00674 sectorAddress.l = 00675 ((unsigned long)diskSect.dir[temp.c].entry.FstClusHi<<16) 00676 + diskSect.dir[temp.c].entry.FstClusLo; 00677 sectorAddress.l *= fatSectorsPerCluster; 00678 sectorAddress.l += dataStart; 00679 00680 fileSize = diskSect.dir[temp.c].entry.FileSize; 00681 dataBufPtr = 0; /* Reset data buffer ptr for FGetChar */ 00682 00683 ConsoleWrite("found, FAT name is \""); 00684 for (tempc=0; tempc<11; tempc++){ 00685 ConsolePutChar(diskSect.dir[temp.c].entry.Name[tempc]); 00686 } 00687 00688 //Store file name nicely for displaying on screen :) 00689 for (tempc=0; tempc<8; tempc++){ 00690 currentFileName[tempc]=diskSect.dir[temp.c].entry.Name[tempc]; 00691 } 00692 currentFileName[8]='.'; 00693 currentFileName[9]=diskSect.dir[temp.c].entry.Name[8]; 00694 currentFileName[10]=diskSect.dir[temp.c].entry.Name[9]; 00695 currentFileName[11]=diskSect.dir[temp.c].entry.Name[10]; 00696 displayText[0]=' '; 00697 for (tempc=0; tempc<12; tempc++){ 00698 displayText[tempc+1]=currentFileName[tempc]; 00699 } 00700 00701 ConsoleWrite("\"\rFile size: "); 00702 ConsolePutUInt(fileSize); 00703 ConsoleWrite("bytes. "); 00704 00705 ConsoleWrite("Start cluster: "); 00706 ConsolePutHex8(diskSect.dir[temp.c].entry.FstClusHi); 00707 ConsolePutHex8(diskSect.dir[temp.c].entry.FstClusLo); 00708 ConsoleWrite("h, sector "); 00709 ConsolePutUInt(sectorAddress.l); 00710 ConsoleWrite("decimal.\r"); 00711 00712 return 0; /* File found, All OK return */ 00713 } 00714 } /* it was a regular file */ 00715 00716 00717 00718 /* Is it a subdirectory? */ 00719 if (((diskSect.dir[temp.c].entry.Attr & 16) != 0) 00720 && (diskSect.dir[temp.c].entry.Name[0] != '.') /* skip . and .. */ 00721 && (diskSect.dir[temp.c].entry.Name[0] != 0xe5) 00722 && (diskSect.dir[temp.c].entry.Name[0] != 0) ){ 00723 00724 /* It is a subdirectory. */ 00725 00726 if (dirLevel<MAX_NUMBER_SUBDIRECTORIES-1){ 00727 /* Yes, we have room in dirStack to traverse deeper. */ 00728 dirLevel++; /* Advance to next directory level */ 00729 sectorAddress.l = 00730 ((unsigned long)diskSect.dir[temp.c].entry.FstClusHi<<16) 00731 + diskSect.dir[temp.c].entry.FstClusLo; 00732 sectorAddress.l *= fatSectorsPerCluster; 00733 sectorAddress.l += dataStart; 00734 00735 /* Prepare for loading. */ 00736 dirStack[dirLevel].sector = sectorAddress.l; 00737 dirStack[dirLevel].entry = 255; /* Magic number */ 00738 00739 } /* we had room in dirStack */ 00740 } /* it was a subdirectory */ 00741 00742 00743 /* Have we reached the end of the directory? */ 00744 if (diskSect.dir[temp.c].entry.Name[0] == 0){ 00745 /* It's the end of directory. */ 00746 00747 /* Is it the end of root directory? */ 00748 if (dirLevel == 0){ 00749 /* End of root directory, end of all files in volume */ 00750 ConsoleWrite("File not found.\r"); 00751 sectorAddress.l = dataStart; 00752 /* when in error point to start of data */ 00753 return 0x0c; /* File Not Found return */ 00754 } 00755 00756 /* End of subdirectory, return from subdirectory */ 00757 dirLevel--; 00758 ReadDiskSector(dirStack[dirLevel].sector); 00759 /* restore temp entry pointer */ 00760 temp.c = dirStack[dirLevel].entry; 00761 00762 } /* it was end of directory */ 00763 00764 00765 /* Advance to next entry */ 00766 temp.c++; 00767 00768 /* If we just went to a subdir, set temp entry pointer to 0 */ 00769 if (dirStack[dirLevel].entry == 255){ 00770 /* Magic Number 255: we have gone to a subdirectory */ 00771 temp.c=0; 00772 } 00773 00774 if (temp.c==16){ /* End of sector */ 00775 /* Prepare to load next sector */ 00776 dirStack[dirLevel].sector = GetNextSector (dirStack[dirLevel].sector); 00777 temp.c=0; 00778 } 00779 00780 dirStack[dirLevel].entry = temp.c; 00781 } 00782 00783 /* Control should never reach this far, end of root directory should 00784 occur first. */ 00785 00786 sectorAddress.l = dataStart; /* when in error point to start of data */ 00787 return 0x0c; /* File Not Found return */ 00788 }

Here is the call graph for this function:

void PConvertClusterToSector unsigned long *  cluster  ) 
 

Convert cluster number to sector number.

Definition at line 74 of file filesys.c.

References dataStart, and fatSectorsPerCluster.

Referenced by ScanForFreeSector().

00074 { 00075 *cluster*=fatSectorsPerCluster; 00076 *cluster+=dataStart; 00077 }

void PConvertSectorToCluster unsigned long *  sector  ) 
 

Convert sector number to cluster number.

Definition at line 68 of file filesys.c.

References dataStart, and fatSectorsPerCluster.

Referenced by ScanForFreeSector(), and WriteClusterChain().

00068 { 00069 *sector-=dataStart; 00070 *sector/=fatSectorsPerCluster; 00071 }

unsigned char ScanForFreeSector  ) 
 

Search for next free sector.

If freeSector is zero, a new file should be allocated.

Definition at line 244 of file filesys.c.

References dataStart, fatSectorsPerCluster, freeSector, GetFatEntry(), PConvertClusterToSector(), and PConvertSectorToCluster().

Referenced by Record().

00244 { 00245 00246 //ConsoleWrite("\rLooking for free space starting from "); 00247 00248 if ((freeSector) && (freeSector-dataStart+1)%fatSectorsPerCluster){ 00249 //Still room in current cluster... 00250 freeSector++; 00251 00252 //ConsoleWrite("free at sector "); 00253 //ConsolePutUInt(freeSector); 00254 00255 return 1; 00256 } 00257 00258 if (freeSector){ 00259 //Advance to next sector 00260 freeSector++; 00261 //switch from using sectors to using clusters 00262 PConvertSectorToCluster(&freeSector); 00263 }else{ 00264 freeSector=3; //starting cluster entry (should be 2?) 00265 } 00266 00267 00268 //scan until free entry is found 00269 //freeSector actually counts clusters here. 00270 while(GetFatEntry(freeSector)){ 00271 freeSector++; 00272 } 00273 00274 ConsoleWrite("F"); 00275 ConsolePutUInt(freeSector); 00276 00277 00278 //while (!KEY_BUTTON); 00279 //ConsoleWrite("free at cluster "); 00280 //ConsolePutUInt(freeSector); 00281 00282 //switch back from using clusters to using sectors. 00283 PConvertClusterToSector(&freeSector); 00284 00285 //ConsoleWrite("sector "); 00286 //ConsolePutUInt(freeSector); 00287 00288 return 1; 00289 }

Here is the call graph for this function:

void WriteClusterChain  ) 
 

Write a cluster chain to FAT for a fragment.

This takes its input from the fragment[] table. It currently has the ability to register only single fragment from fragment[0]. fragment[1].start should contain the next cluster number after this fragment or 0x0fffffff if this is the last fragment.

This function currently also registers a FAT directory entry for the file to first free entry slot in the directory structure. If no free directory entries are available, it will behave unpredictably. This could happen in FAT32.

OpenFile(0) is a special call to register a directory entry for fragment[0].

Todo:
update second FAT too

update second FAT too

Definition at line 125 of file filesys.c.

References Temp::c, diskSect, DiskBlock::Fat16Table, DiskBlock::Fat32Table, fatSectorsPerCluster, fatStart, fragment, IS_FAT_32, Address::l, fragmentEntry::length, OpenFile(), PConvertSectorToCluster(), ReadDiskSector(), sectorAddress, fragmentEntry::start, temp, and WriteDiskSector().

Referenced by Record().

00125 { 00126 00127 xdata unsigned long currentCluster; //is now fragment[0].start 00128 xdata unsigned long fragSize; //is now fragment[0].length 00129 xdata unsigned long fatPageSector; 00130 xdata unsigned char entryNumber; 00131 00132 00133 // PREPARE 00134 00135 // Calculate starting cluster number... 00136 currentCluster = fragment[0].start; 00137 PConvertSectorToCluster(&currentCluster); 00138 00139 fragSize = fragment[0].length; //size in sectors 00140 00141 // Write cluster number and size in bytes to fragment[0] 00142 // for the function that registers directory entries 00143 fragment[0].start = currentCluster; 00144 fragment[0].length *= 512; 00145 00146 // Locate the relevant page in FAT clusterchain records 00147 fatPageSector = currentCluster; 00148 if (!IS_FAT_32){ //FAT16 00149 entryNumber = fatPageSector & 0xff; 00150 fatPageSector >>= 8; 00151 }else{ //FAT32 00152 entryNumber = fatPageSector & 0x7f; 00153 fatPageSector >>= 7; 00154 } 00155 fatPageSector += fatStart; 00156 00157 ConsoleWrite("Writing clusterchain from: "); ConsolePutUInt(currentCluster); 00158 ConsoleWrite("Fragment size (sectors): "); ConsolePutUInt(fragSize); 00159 ConsoleWrite("FatPageSector: "); ConsolePutUInt(fatPageSector); 00160 ConsoleWrite("EntryNumber: "); ConsolePutUInt(entryNumber); 00161 00162 00163 // WRITE CLUSTER CHAIN TO FIRST FAT 00164 00165 while (fragSize>fatSectorsPerCluster){ 00166 // while more than 1 cluster left... 00167 00168 // is the FAT clusterchain page changed? 00169 if (sectorAddress.l != fatPageSector){ 00170 // Yes, have we advanced by 1 sector? 00171 if (sectorAddress.l == (fatPageSector - 1)){ 00172 //Yes, we must save the edited sector 00173 WriteDiskSector (sectorAddress.l); 00175 } 00176 // at least we need to load the new clusterchain page 00177 sectorAddress.l = fatPageSector; 00178 ReadDiskSector(sectorAddress.l); 00179 }//Load/Save FAT sector 00180 00181 00182 // Register Middle Entry 00183 currentCluster++; //advancce to next cluster 00184 00185 //fragSize-=fatSectorsPerCluster; //we will register one cluster 00186 //to avoid memory spill in C compiler, the preceding line is written as: 00187 for (temp.c = fatSectorsPerCluster;temp.c;temp.c--){ 00188 fragSize--; 00189 } 00190 00191 if (IS_FAT_32){ 00192 diskSect.Fat32Table[entryNumber]=currentCluster; 00193 }else{ 00194 diskSect.Fat16Table[entryNumber]=(currentCluster&0xffff); 00195 } 00196 00197 // Calculate next entry position in FAT records 00198 fatPageSector = currentCluster; 00199 if (!IS_FAT_32){ //FAT16 00200 entryNumber = fatPageSector & 0xff; 00201 fatPageSector >>= 8; 00202 }else{ //FAT32 00203 entryNumber = fatPageSector & 0x7f; 00204 fatPageSector >>= 7; 00205 } 00206 fatPageSector += fatStart; 00207 00208 }//while 00209 00210 00211 // WRITE THE FINAL ENTRY TO FAT CLUSTERCHAIN 00212 00213 // is the FAT clusterchain page changed? 00214 if (sectorAddress.l != fatPageSector){ 00215 // Yes, have we advanced by 1 sector? 00216 if (sectorAddress.l == (fatPageSector - 1)){ 00217 //Yes, we must save the edited sector 00218 WriteDiskSector (sectorAddress.l); 00220 } 00221 // at least we need to load the new clusterchain page 00222 sectorAddress.l = fatPageSector; 00223 ReadDiskSector(sectorAddress.l); 00224 }//Load/Save FAT sector 00225 00226 00227 //Write the Last entry 00228 if (IS_FAT_32){ 00229 diskSect.Fat32Table[entryNumber]=fragment[1].start; 00230 }else{ 00231 diskSect.Fat16Table[entryNumber]=(fragment[1].start & 0xffff); 00232 } 00233 WriteDiskSector(sectorAddress.l); //Write last sector 00234 00235 OpenFile(0); //Register FAT entry 00236 00237 }

Here is the call graph for this function:


Variable Documentation

xdata char currentFileName[12]
 

8 first characters of current file name

Definition at line 65 of file filesys.c.

Referenced by main(), and OpenFile().

data unsigned long dataStart
 

(In FAT the start is cluster 2, so dataStart actually points to 2 clusters before the start of data area)

Definition at line 29 of file filesys.c.

Referenced by BuildFragmentTable(), FatInitGlobals(), GetNextSector(), InitFileSystem(), OpenFile(), PConvertClusterToSector(), PConvertSectorToCluster(), and ScanForFreeSector().

xdata unsigned char dirLevel = 0
 

Current directory level, 0=Root directory.

Definition at line 59 of file filesys.c.

Referenced by OpenFile().

xdata struct directoryStack dirStack[MAX_NUMBER_SUBDIRECTORIES]
 

Directory traversing structure.

Referenced by OpenFile().

data unsigned char fatSectorsPerCluster
 

FAT Global sectors per cluster.

Definition at line 32 of file filesys.c.

Referenced by BuildFragmentTable(), FatInitGlobals(), GetNextSector(), OpenFile(), PConvertClusterToSector(), PConvertSectorToCluster(), Record(), ScanForFreeSector(), and WriteClusterChain().

data unsigned long fatStart
 

Starting sector of FAT table.

Definition at line 21 of file filesys.c.

Referenced by BuildFragmentTable(), FatInitGlobals(), GetFatEntry(), GetNextSector(), InitFileSystem(), and WriteClusterChain().

xdata unsigned long fileSize
 

Size of current file to play.

Definition at line 47 of file filesys.c.

Referenced by FGetChar(), GetAVIBlock(), OpenFile(), and PlayAvi().

xdata struct fragmentEntry fragment[MAX_NUMBER_FRAGMENTS]
 

Fragment Table.

Maximum fragment size is (4G-1 sectors)

Referenced by BuildFragmentTable(), OpenFile(), PlayCurrentFile(), Record(), and WriteClusterChain().

xdata unsigned long freeSector = 0
 

Next free cluster number.

Definition at line 62 of file filesys.c.

Referenced by InitFileSystem(), Record(), and ScanForFreeSector().

data unsigned long rootStart
 

Starting sector of root directory.

Definition at line 24 of file filesys.c.

Referenced by FatInitGlobals(), InitFileSystem(), and OpenFile().


All software copyright 2000-2004 VLSI Solution OY. Redistribution of these software modules are limited to promotional use only and only with the VS1011 / VS1002 / VS1003 MP3-Evakit evaluation boards. Free or commercial use of these software modules in MP3 players is ok if the product includes MP3 decoder chip(s) from VLSI. You can request the complete (compilable) package from mp3@vlsi.fi