/*! \file fat.c \brief FAT16/32 file system driver. */ //***************************************************************************** // // File Name : 'fat.c' // Title : FAT16/32 file system driver // Author : Pascal Stang // Date : 11/07/2000 // Revised : 12/12/2000 // Version : 0.3 // Target MCU : ATmega103 (should work for Atmel AVR Series) // Editor Tabs : 4 // // This code is based in part on work done by Jesper Hansen for his // YAMPP MP3 player project. // // NOTE: This code is currently below version 1.0, and therefore is considered // to be lacking in some functionality or documentation, or may not be fully // tested. Nonetheless, you can expect most functions to work. // // This code is distributed under the GNU Public License // which can be found at http://www.gnu.org/licenses/gpl.txt // //***************************************************************************** #include #include #include #include "ata.h" #include "rprintf.h" #include "fat.h" #include "fatconf.h" // globals unsigned char *SectorBuffer = (unsigned char *) SECTOR_BUFFER1_ADDR; unsigned char *LongNameBuffer = (unsigned char *) LONGNAME_BUFFER_ADDR; unsigned char *DirNameBuffer = (unsigned char *) DIRNAME_BUFFER_ADDR; struct partrecord PartInfo; unsigned char Fat32Enabled; unsigned long FirstDataSector; unsigned int BytesPerSector; unsigned int SectorsPerCluster; unsigned long FirstFATSector; unsigned long FirstDirSector; unsigned long FileSize; unsigned long FatInCache = 0; /*************************************************************************/ /*************************************************************************/ unsigned long fatClustToSect(unsigned long clust) { return ((clust-2) * SectorsPerCluster) + FirstDataSector; } unsigned int fatClusterSize(void) { // return the number of sectors in a disk cluster return SectorsPerCluster; } unsigned char fatInit( unsigned char device) { //struct partrecord *pr; struct bpb710 *bpb; // read partition table // TODO.... error checking ataReadSectors(DRIVE0, 0, 1, SectorBuffer); // map first partition record // save partition information to global PartInfo PartInfo = *((struct partrecord *) ((struct partsector *) SectorBuffer)->psPart); // PartInfo = *pr; // Read the Partition BootSector // **first sector of partition in PartInfo.prStartLBA ataReadSectors( DRIVE0, PartInfo.prStartLBA, 1, SectorBuffer ); bpb = (struct bpb710 *) ((struct bootsector710 *) SectorBuffer)->bsBPB; // setup global disk constants FirstDataSector = PartInfo.prStartLBA; if(bpb->bpbFATsecs) { // bpbFATsecs is non-zero and is therefore valid FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbFATsecs; } else { // bpbFATsecs is zero, real value is in bpbBigFATsecs FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbBigFATsecs; } SectorsPerCluster = bpb->bpbSecPerClust; BytesPerSector = bpb->bpbBytesPerSec; FirstFATSector = bpb->bpbResSectors + PartInfo.prStartLBA; switch (PartInfo.prPartType) { case PART_TYPE_DOSFAT16: case PART_TYPE_FAT16: case PART_TYPE_FAT16LBA: // first directory cluster is 2 by default (clusters range 2->big) FirstDirSector = CLUST_FIRST; // push data sector pointer to end of root directory area //FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR; Fat32Enabled = FALSE; break; case PART_TYPE_FAT32LBA: case PART_TYPE_FAT32: // bpbRootClust field exists in FAT32 bpb710, but not in lesser bpb's FirstDirSector = bpb->bpbRootClust; // push data sector pointer to end of root directory area // need this? FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR; Fat32Enabled = TRUE; break; default: rprintfProgStrM("Found: No Partition!\r\n"); //return 1; break; } #ifdef DEBUG_FAT switch (PartInfo.prPartType) { case PART_TYPE_DOSFAT16: rprintfProgStrM("Found: DOSFAT 16\r\n"); break; case PART_TYPE_FAT16: rprintfProgStrM("Found: FAT16\r\n"); break; case PART_TYPE_FAT16LBA: rprintfProgStrM("Found: FAT16 LBA\r\n"); break; case PART_TYPE_FAT32LBA: rprintfProgStrM("Found: FAT32 LBA\r\n"); break; case PART_TYPE_FAT32: rprintfProgStrM("Found: FAT32\r\n"); //return 1; break; default: rprintfProgStrM("Found: No Partition!\r\n"); //return 1; break; } rprintfProgStrM("First sector : "); rprintfu32(PartInfo.prStartLBA); rprintfCRLF(); rprintfProgStrM("Size : "); rprintfu32(PartInfo.prSize); rprintfCRLF(); rprintfProgStrM("bytes/sector : "); rprintfu16(bpb->bpbBytesPerSec); rprintfCRLF(); rprintfProgStrM("sectors/cluster : "); rprintfu08(bpb->bpbSecPerClust); rprintfCRLF(); rprintfProgStrM("reserved sectors: "); rprintfu16(bpb->bpbResSectors); rprintfCRLF(); rprintfProgStrM("FatSectors : "); rprintfu16(bpb->bpbFATsecs); rprintfCRLF(); rprintfProgStrM("BigFatSectors : "); rprintfu32(bpb->bpbBigFATsecs); rprintfCRLF(); rprintfProgStrM("Number of Fats : "); rprintfu08(bpb->bpbFATs); rprintfCRLF(); rprintfProgStrM("First Fat Sector: "); rprintfu32(FirstFATSector); rprintfCRLF(); rprintfProgStrM("First Data Sect : "); rprintfu32(FirstDataSector); rprintfCRLF(); rprintfProgStrM("First Dir Clust : "); rprintfu32(FirstDirSector); rprintfCRLF(); #endif return 0; } ////////////////////////////////////////////////////////////// unsigned int baseentry = 0; unsigned int entrycount = 0; unsigned long fatGetDirEntry(unsigned int entry, unsigned int count) { unsigned long sector; struct direntry *de = 0; // avoid compiler warning by initializing struct winentry *we; unsigned int hasBuffer; unsigned int b; int i,index; char *p; if(count == 0) { entrycount = 0; DirNameBuffer = 0; } // read dir data sector = fatClustToSect(FirstDirSector); hasBuffer = 0; index = 16; // crank it up do { if(index == 16) // time for next sector ? { ataReadSectors( DRIVE0, sector++, 1, SectorBuffer); de = (struct direntry *) SectorBuffer; index = 0; } if(*de->deName != 0xE5) { // if not a deleted entry if(de->deAttributes == ATTR_LONG_FILENAME) { // we have a long name entry we = (struct winentry *) de; b = 13 *( (we->weCnt-1) & 0x0f); // index into string p = &LongNameBuffer[b]; for (i=0;i<5;i++) *p++ = we->wePart1[i*2]; // copy first part for (i=0;i<6;i++) *p++ = we->wePart2[i*2]; // second part for (i=0;i<2;i++) *p++ = we->wePart3[i*2]; // and third part if (we->weCnt & 0x40) *p = 0; // in case dirnamelength is multiple of 13 if ((we->weCnt & 0x0f) == 1) hasBuffer = 1; // mark that we have a long entry } else { // we have a short name entry // check if this is the end of a multi-part long name entry if(hasBuffer) { // a long entry name has been collected // is it a directory ? if(de->deAttributes == ATTR_DIRECTORY) { unsigned long save = FirstDirSector; unsigned int save2 = baseentry; unsigned long rval; strcpy(DirNameBuffer,LongNameBuffer); strcat(DirNameBuffer,"/"); // rprintfStr(LongNameBuffer); rprintfProgStrM("/"); //EOL(); // call recursively FirstDirSector = ((unsigned long)de->deHighClust << 16) + de->deStartCluster; rval = fatGetDirEntry(entry,1); FirstDirSector = save; baseentry = save2; if (rval) return rval; else { // reload original sector ataReadSectors( DRIVE0, sector-1, 1, SectorBuffer); entrycount--; // decrement entry counter *DirNameBuffer = 0; } } else // normal file entry if(entrycount == entry) break; hasBuffer = 0; // clear buffer entrycount++; // increment entry counter } // else ignore short_name_only entries } } de++; index++; } while (*de->deName || index == 16); // 0 in de->deName[0] if no more entries if (hasBuffer == 0) // end of entries return 0; FileSize = de->deFileSize; return (unsigned long) ((unsigned long)de->deHighClust << 16) + de->deStartCluster; } // return the size of the last directory entry unsigned long fatGetFilesize(void) { return FileSize; } // return the long name of the last directory entry char* fatGetFilename(void) { return LongNameBuffer; } // return the directory of the last directory entry char* fatGetDirname(void) { return DirNameBuffer; } // load a clusterfull of data void fatLoadCluster(unsigned long cluster, unsigned char *buffer) { register unsigned char i; // read cluster //while ( ataReadSectors( DRIVE0, clust2sect(cluster), SectorsPerCluster, buffer) != 0); for(i=0; i"); rprintfu32(nextCluster); rprintfCRLF(); #endif return nextCluster; }