Main Page   Data Structures   File List   Data Fields   Globals  

/fat.c

Go to the documentation of this file.
00001 /*! \file fat.c \brief FAT16/32 file system driver. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'fat.c'
00005 // Title        : FAT16/32 file system driver
00006 // Author       : Pascal Stang
00007 // Date         : 11/07/2000
00008 // Revised      : 12/12/2000
00009 // Version      : 0.3
00010 // Target MCU   : ATmega103 (should work for Atmel AVR Series)
00011 // Editor Tabs  : 4
00012 //
00013 // This code is based in part on work done by Jesper Hansen for his
00014 //      YAMPP MP3 player project.
00015 //
00016 // NOTE: This code is currently below version 1.0, and therefore is considered
00017 // to be lacking in some functionality or documentation, or may not be fully
00018 // tested.  Nonetheless, you can expect most functions to work.
00019 //
00020 // This code is distributed under the GNU Public License
00021 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00022 //
00023 //*****************************************************************************
00024 
00025 
00026 #include <avr/io.h>
00027 #include <avr/pgmspace.h>
00028 #include <string.h>
00029 
00030 #include "ata.h"
00031 #include "rprintf.h"
00032 
00033 #include "fat.h"
00034 #include "fatconf.h"
00035 
00036 // globals
00037 unsigned char *SectorBuffer  =      (unsigned char *) SECTOR_BUFFER1_ADDR;
00038 unsigned char *LongNameBuffer =     (unsigned char *) LONGNAME_BUFFER_ADDR;
00039 unsigned char *DirNameBuffer =      (unsigned char *) DIRNAME_BUFFER_ADDR;
00040 
00041 struct partrecord PartInfo;
00042 unsigned char Fat32Enabled;
00043 unsigned long FirstDataSector;
00044 unsigned int  BytesPerSector;
00045 unsigned int  SectorsPerCluster;
00046 unsigned long FirstFATSector;
00047 unsigned long FirstDirSector;
00048 unsigned long FileSize;
00049 unsigned long FatInCache = 0;
00050 
00051 /*************************************************************************/
00052 /*************************************************************************/
00053 
00054 
00055 unsigned long fatClustToSect(unsigned long clust)
00056 {
00057     return ((clust-2) * SectorsPerCluster) + FirstDataSector;
00058 }
00059 
00060 unsigned int fatClusterSize(void)
00061 {
00062     // return the number of sectors in a disk cluster
00063     return SectorsPerCluster;
00064 }
00065 
00066 unsigned char fatInit( unsigned char device)
00067 {
00068     //struct partrecord *pr;
00069     struct bpb710 *bpb;
00070 
00071     // read partition table
00072     // TODO.... error checking
00073     ataReadSectors(DRIVE0, 0, 1, SectorBuffer);
00074     // map first partition record   
00075     // save partition information to global PartInfo
00076     PartInfo = *((struct partrecord *) ((struct partsector *) SectorBuffer)->psPart);
00077 //  PartInfo = *pr;
00078     
00079     // Read the Partition BootSector
00080     // **first sector of partition in PartInfo.prStartLBA
00081     ataReadSectors( DRIVE0, PartInfo.prStartLBA, 1, SectorBuffer );
00082     bpb = (struct bpb710 *) ((struct bootsector710 *) SectorBuffer)->bsBPB;
00083 
00084     // setup global disk constants
00085     FirstDataSector = PartInfo.prStartLBA;
00086     if(bpb->bpbFATsecs)
00087     {
00088         // bpbFATsecs is non-zero and is therefore valid
00089         FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbFATsecs;
00090     }
00091     else
00092     {
00093         // bpbFATsecs is zero, real value is in bpbBigFATsecs
00094         FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbBigFATsecs;
00095     }
00096     SectorsPerCluster   = bpb->bpbSecPerClust;
00097     BytesPerSector      = bpb->bpbBytesPerSec;
00098     FirstFATSector      = bpb->bpbResSectors + PartInfo.prStartLBA;
00099 
00100     switch (PartInfo.prPartType)
00101     {
00102         case PART_TYPE_DOSFAT16:
00103         case PART_TYPE_FAT16:
00104         case PART_TYPE_FAT16LBA:
00105             // first directory cluster is 2 by default (clusters range 2->big)
00106             FirstDirSector  = CLUST_FIRST;
00107             // push data sector pointer to end of root directory area
00108             //FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
00109             Fat32Enabled = FALSE;
00110             break;
00111         case PART_TYPE_FAT32LBA:
00112         case PART_TYPE_FAT32:
00113             // bpbRootClust field exists in FAT32 bpb710, but not in lesser bpb's
00114             FirstDirSector = bpb->bpbRootClust;
00115             // push data sector pointer to end of root directory area
00116             // need this? FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
00117             Fat32Enabled = TRUE;
00118             break;
00119         default:
00120             rprintfProgStrM("Found: No Partition!\r\n");
00121             //return 1;
00122             break;
00123     }
00124 
00125 
00126 #ifdef DEBUG_FAT
00127     switch (PartInfo.prPartType)
00128     {
00129         case PART_TYPE_DOSFAT16:
00130                 rprintfProgStrM("Found: DOSFAT 16\r\n");
00131                 break;
00132         case PART_TYPE_FAT16:
00133                 rprintfProgStrM("Found: FAT16\r\n");
00134                 break;
00135         case PART_TYPE_FAT16LBA:
00136                 rprintfProgStrM("Found: FAT16 LBA\r\n");
00137                 break;
00138         case PART_TYPE_FAT32LBA:
00139                 rprintfProgStrM("Found: FAT32 LBA\r\n");
00140                 break;
00141         case PART_TYPE_FAT32:
00142                 rprintfProgStrM("Found: FAT32\r\n");
00143                 //return 1; 
00144                 break;
00145         default:
00146                 rprintfProgStrM("Found: No Partition!\r\n");
00147                 //return 1;
00148                 break;
00149     }
00150 
00151     rprintfProgStrM("First sector    : ");  rprintfu32(PartInfo.prStartLBA);    rprintfCRLF();
00152     rprintfProgStrM("Size            : ");  rprintfu32(PartInfo.prSize);        rprintfCRLF();
00153     rprintfProgStrM("bytes/sector    : ");  rprintfu16(bpb->bpbBytesPerSec);    rprintfCRLF();
00154     rprintfProgStrM("sectors/cluster : ");  rprintfu08(bpb->bpbSecPerClust);    rprintfCRLF();
00155     rprintfProgStrM("reserved sectors: ");  rprintfu16(bpb->bpbResSectors);     rprintfCRLF();
00156     rprintfProgStrM("FatSectors      : ");  rprintfu16(bpb->bpbFATsecs);        rprintfCRLF();
00157     rprintfProgStrM("BigFatSectors   : ");  rprintfu32(bpb->bpbBigFATsecs);     rprintfCRLF();
00158     rprintfProgStrM("Number of Fats  : ");  rprintfu08(bpb->bpbFATs);           rprintfCRLF();
00159     rprintfProgStrM("First Fat Sector: ");  rprintfu32(FirstFATSector);         rprintfCRLF();
00160     rprintfProgStrM("First Data Sect : ");  rprintfu32(FirstDataSector);        rprintfCRLF();
00161     rprintfProgStrM("First Dir Clust : ");  rprintfu32(FirstDirSector);         rprintfCRLF();
00162 #endif
00163 
00164     return 0;   
00165 }
00166 
00167 //////////////////////////////////////////////////////////////
00168 
00169 
00170 unsigned int baseentry = 0;
00171 unsigned int entrycount = 0;
00172 
00173 
00174 unsigned long fatGetDirEntry(unsigned int entry, unsigned int count)
00175 {
00176     unsigned long sector;
00177     struct direntry *de = 0;    // avoid compiler warning by initializing
00178     struct winentry *we;
00179     unsigned int hasBuffer;
00180     unsigned int b;
00181     int i,index;
00182     char *p;
00183     
00184     if(count == 0)
00185     {
00186         entrycount = 0;
00187         DirNameBuffer = 0;
00188     }
00189     
00190     // read dir data
00191     sector = fatClustToSect(FirstDirSector);
00192 
00193     hasBuffer = 0;
00194 
00195     index = 16; // crank it up
00196     do 
00197     {
00198         if(index == 16) // time for next sector ?
00199         {
00200             ataReadSectors( DRIVE0, sector++, 1, SectorBuffer);
00201             de = (struct direntry *) SectorBuffer;
00202             index = 0;
00203         }   
00204     
00205         if(*de->deName != 0xE5)
00206         {
00207             // if not a deleted entry
00208             if(de->deAttributes == ATTR_LONG_FILENAME)
00209             {
00210                 // we have a long name entry
00211                 we = (struct winentry *) de;
00212                 b = 13 *( (we->weCnt-1) & 0x0f);                // index into string
00213                 p = &LongNameBuffer[b];
00214                 for (i=0;i<5;i++)   *p++ = we->wePart1[i*2];    // copy first part          
00215                 for (i=0;i<6;i++)   *p++ = we->wePart2[i*2];    // second part
00216                 for (i=0;i<2;i++)   *p++ = we->wePart3[i*2];    // and third part
00217                 if (we->weCnt & 0x40) *p = 0;                   // in case dirnamelength is multiple of 13
00218                 if ((we->weCnt & 0x0f) == 1) hasBuffer = 1;     // mark that we have a long entry
00219             }
00220             else
00221             {
00222                 // we have a short name entry
00223                 // check if this is the end of a multi-part long name entry
00224                 if(hasBuffer)
00225                 {
00226                     // a long entry name has been collected
00227                     // is it a directory ?
00228                     if(de->deAttributes == ATTR_DIRECTORY)
00229                     {
00230                         unsigned long save = FirstDirSector;
00231                         unsigned int save2 = baseentry;
00232                         unsigned long rval;
00233                         
00234                         strcpy(DirNameBuffer,LongNameBuffer);
00235                         strcat(DirNameBuffer,"/");
00236 
00237 //                      rprintfStr(LongNameBuffer); rprintfProgStrM("/"); //EOL();
00238 
00239                         // call recursively
00240                         FirstDirSector = ((unsigned long)de->deHighClust << 16) + de->deStartCluster;
00241                         rval = fatGetDirEntry(entry,1);
00242                         FirstDirSector = save;
00243                         baseentry = save2;
00244                         if (rval)
00245                             return rval;
00246                         else    
00247                         {
00248                             // reload original sector
00249                             ataReadSectors( DRIVE0, sector-1, 1, SectorBuffer);
00250                             entrycount--;           // decrement entry counter      
00251                             *DirNameBuffer = 0;
00252                     }
00253                     }
00254                     else // normal file entry
00255                         if(entrycount == entry)     
00256                             break;
00257                     hasBuffer = 0;  // clear buffer 
00258                     entrycount++;   // increment entry counter      
00259                 }
00260                 // else ignore short_name_only entries
00261             }
00262         }
00263         de++;
00264         index++;
00265     }   while (*de->deName || index == 16); // 0 in de->deName[0] if no more entries
00266 
00267     if (hasBuffer == 0)     // end of entries
00268         return 0;
00269     
00270     FileSize = de->deFileSize;
00271     return (unsigned long) ((unsigned long)de->deHighClust << 16) + de->deStartCluster;
00272 }
00273 
00274 
00275 // return the size of the last directory entry
00276 unsigned long fatGetFilesize(void)
00277 {
00278     return FileSize;
00279 }
00280 
00281 
00282 // return the long name of the last directory entry
00283 char* fatGetFilename(void)
00284 {   
00285     return LongNameBuffer;
00286 }
00287 
00288 
00289 // return the directory of the last directory entry
00290 char* fatGetDirname(void)
00291 {   
00292     return DirNameBuffer;
00293 }
00294 
00295 
00296 // load a clusterfull of data
00297 void fatLoadCluster(unsigned long cluster, unsigned char *buffer)
00298 {
00299     register unsigned char i;
00300     // read cluster
00301     //while ( ataReadSectors( DRIVE0, clust2sect(cluster), SectorsPerCluster, buffer) != 0);
00302     for(i=0; i<SectorsPerCluster; i++)
00303     {
00304 //      ataReadSectors( DRIVE0, clust2sect(cluster)+i, 1, buffer+(i<<9) );
00305         // temporary fix for wierd misaligned cluster problem
00306         // (only when using FAT16?)
00307         ataReadSectors( DRIVE0, fatClustToSect(cluster+8)+i, 1, buffer+(i<<9) );
00308     }
00309 }
00310 
00311 
00312 // find next cluster in the FAT chain
00313 unsigned long fatNextCluster(unsigned long cluster)
00314 {
00315     unsigned long nextCluster;
00316     unsigned long fatMask;
00317     unsigned long fatOffset;
00318     unsigned long sector;
00319     unsigned int offset;
00320     
00321     // get fat offset in bytes
00322     if(Fat32Enabled)
00323     {
00324         // four FAT bytes (32 bits) for every cluster
00325         fatOffset = cluster << 2;
00326         // set the FAT bit mask
00327         fatMask = FAT32_MASK;
00328     }
00329     else
00330     {
00331         // two FAT bytes (16 bits) for every cluster
00332         fatOffset = cluster << 1;
00333         // set the FAT bit mask
00334         fatMask = FAT16_MASK;
00335     }
00336     
00337     // calculate the FAT sector that we're interested in
00338     sector = FirstFATSector + (fatOffset / BytesPerSector);
00339     // calculate offset of the our entry within that FAT sector
00340     offset = fatOffset % BytesPerSector;
00341 
00342     // if we don't already have this FAT chunk loaded, go get it
00343     if (sector != FatInCache)
00344     {
00345         // read sector of FAT table
00346         while (ataReadSectors( DRIVE0, sector, 1, (unsigned char*)FAT_CACHE_ADDR) != 0);
00347         FatInCache = sector;
00348     }
00349 
00350     // read the nextCluster value
00351     nextCluster = (*((unsigned long*) &((char*)FAT_CACHE_ADDR)[offset])) & fatMask;
00352 
00353     // check to see if we're at the end of the chain
00354     if (nextCluster == (CLUST_EOFE & fatMask))
00355         nextCluster = 0;
00356 
00357 #ifdef DEBUG_FAT
00358     rprintfProgStrM(">");
00359     rprintfu32(nextCluster);
00360     rprintfCRLF();
00361 #endif
00362     
00363     return nextCluster;
00364 }

Generated on Fri Aug 1 10:42:41 2003 for Procyon AVRlib by doxygen1.2.18