1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-11-30 11:24:12 +01:00
Arduino/build/shared/lib/avrlib/fat.c

365 lines
10 KiB
C
Raw Normal View History

/*! \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 <avr/io.h>
#include <avr/pgmspace.h>
#include <string.h>
#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<SectorsPerCluster; i++)
{
// ataReadSectors( DRIVE0, clust2sect(cluster)+i, 1, buffer+(i<<9) );
// temporary fix for wierd misaligned cluster problem
// (only when using FAT16?)
ataReadSectors( DRIVE0, fatClustToSect(cluster+8)+i, 1, buffer+(i<<9) );
}
}
// find next cluster in the FAT chain
unsigned long fatNextCluster(unsigned long cluster)
{
unsigned long nextCluster;
unsigned long fatMask;
unsigned long fatOffset;
unsigned long sector;
unsigned int offset;
// get fat offset in bytes
if(Fat32Enabled)
{
// four FAT bytes (32 bits) for every cluster
fatOffset = cluster << 2;
// set the FAT bit mask
fatMask = FAT32_MASK;
}
else
{
// two FAT bytes (16 bits) for every cluster
fatOffset = cluster << 1;
// set the FAT bit mask
fatMask = FAT16_MASK;
}
// calculate the FAT sector that we're interested in
sector = FirstFATSector + (fatOffset / BytesPerSector);
// calculate offset of the our entry within that FAT sector
offset = fatOffset % BytesPerSector;
// if we don't already have this FAT chunk loaded, go get it
if (sector != FatInCache)
{
// read sector of FAT table
while (ataReadSectors( DRIVE0, sector, 1, (unsigned char*)FAT_CACHE_ADDR) != 0);
FatInCache = sector;
}
// read the nextCluster value
nextCluster = (*((unsigned long*) &((char*)FAT_CACHE_ADDR)[offset])) & fatMask;
// check to see if we're at the end of the chain
if (nextCluster == (CLUST_EOFE & fatMask))
nextCluster = 0;
#ifdef DEBUG_FAT
rprintfProgStrM(">");
rprintfu32(nextCluster);
rprintfCRLF();
#endif
return nextCluster;
}