📄 fat.c
字号:
/*! \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 <string.h>
#include "ata.h"
#include "rprintf.h"
#include "debug.h"
#include "fat.h"
#include "fatconf.h"
// globals
// buffers
unsigned char *SectorBuffer = (unsigned char *) FAT_SECTOR_BUFFER_ADDR;
unsigned char *FileNameBuffer = (unsigned char *) FAT_FILENAME_BUFFER_ADDR;
unsigned char *PathNameBuffer = (unsigned char *) FAT_PATHNAME_BUFFER_ADDR;
// filesystem constants/metrics
struct partrecord PartInfo;
unsigned char Fat32Enabled;
unsigned long FirstDataSector;
unsigned short BytesPerSector;
unsigned short SectorsPerCluster;
unsigned long FirstFATSector;
unsigned long RootDirStartCluster;
// operating variables
unsigned long CurrentDirStartCluster; //< current directory starting cluster
struct FileInfoStruct FileInfo; //< file information for last file accessed
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)
RootDirStartCluster = 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
RootDirStartCluster = bpb->bpbRootClust;
// push data sector pointer to end of root directory area
// need this? FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
Fat32Enabled = TRUE;
break;
default:
rprintfStr("Found: No Partition!\r\n");
//return 1;
break;
}
// set current directory to root (\)
CurrentDirStartCluster = RootDirStartCluster;
PathNameBuffer[0] = '\\';
PathNameBuffer[1] = 0;
// do debug
#ifdef DEBUG_FAT
switch (PartInfo.prPartType)
{
case PART_TYPE_DOSFAT16:
rprintfStr("Found: DOSFAT 16\r\n");
break;
case PART_TYPE_FAT16:
rprintfStr("Found: FAT16\r\n");
break;
case PART_TYPE_FAT16LBA:
rprintfStr("Found: FAT16 LBA\r\n");
break;
case PART_TYPE_FAT32LBA:
rprintfStr("Found: FAT32 LBA\r\n");
break;
case PART_TYPE_FAT32:
rprintfStr("Found: FAT32\r\n");
//return 1;
break;
default:
rprintfStr("Found: No Partition!\r\n");
//return 1;
break;
}
rprintfStr("First sector : "); rprintfu32(PartInfo.prStartLBA); rprintfCRLF();
rprintfStr("Size : "); rprintfu32(PartInfo.prSize); rprintfCRLF();
rprintfStr("bytes/sector : "); rprintfu16(bpb->bpbBytesPerSec); rprintfCRLF();
rprintfStr("sectors/cluster : "); rprintfu08(bpb->bpbSecPerClust); rprintfCRLF();
rprintfStr("reserved sectors: "); rprintfu16(bpb->bpbResSectors); rprintfCRLF();
rprintfStr("FatSectors : "); rprintfu16(bpb->bpbFATsecs); rprintfCRLF();
rprintfStr("BigFatSectors : "); rprintfu32(bpb->bpbBigFATsecs); rprintfCRLF();
rprintfStr("Number of Fats : "); rprintfu08(bpb->bpbFATs); rprintfCRLF();
rprintfStr("First Fat Sector: "); rprintfu32(FirstFATSector); rprintfCRLF();
rprintfStr("First Data Sect : "); rprintfu32(FirstDataSector); rprintfCRLF();
rprintfStr("RootDirStartClus: "); rprintfu32(RootDirStartCluster); rprintfCRLF();
#endif
return 0;
}
void fatPrintPartition(struct partrecord *partition)
{
rprintfStr("----- Partition -----\r\n");
rprintfStr("Active : "); rprintfu08(partition->prIsActive); rprintfCRLF();
rprintfStr("StartHead : "); rprintfu08(partition->prStartHead); rprintfCRLF();
rprintfStr("StartCylSect : "); rprintfu16(partition->prStartCylSect); rprintfCRLF();
rprintfStr("Partition Type: ");
switch(partition->prPartType)
{
case PART_TYPE_DOSFAT16:
rprintfStr("Found: DOSFAT 16\r\n");
break;
case PART_TYPE_FAT16:
rprintfStr("Found: FAT16\r\n");
break;
case PART_TYPE_FAT16LBA:
rprintfStr("Found: FAT16 LBA\r\n");
break;
case PART_TYPE_FAT32LBA:
rprintfStr("Found: FAT32 LBA\r\n");
break;
case PART_TYPE_FAT32:
rprintfStr("Found: FAT32\r\n");
break;
case PART_TYPE_UNKNOWN:
rprintfStr("No Partition\r\n");
break;
default:
rprintf("Type: 0x%x\r\n", partition->prPartType);
break;
}
rprintfStr("EndHead : "); rprintfu08(partition->prEndHead); rprintfCRLF();
rprintfStr("EndCylSect : "); rprintfu16(partition->prEndCylSect); rprintfCRLF();
rprintfStr("StartLBA : "); rprintfu32(partition->prStartLBA); rprintfCRLF();
rprintfStr("Size : "); rprintfu32(partition->prSize); rprintfCRLF();
}
void fatPrintPartitionTable(struct partsector *buffer)
{
ataReadSectors(DRIVE0, 0, 1, SectorBuffer);
buffer = SectorBuffer;
fatPrintPartition( (struct partrecord*) &(buffer->psPart[0x00]) );
fatPrintPartition( (struct partrecord*) &(buffer->psPart[0x10]) );
fatPrintPartition( (struct partrecord*) &(buffer->psPart[0x20]) );
fatPrintPartition( (struct partrecord*) &(buffer->psPart[0x30]) );
if( (buffer->psBootSectSig0 == BOOTSIG0) &&
(buffer->psBootSectSig1 == BOOTSIG1) )
{
rprintfStr("Partition Sector Valid.");
}
}
//////////////////////////////////////////////////////////////
unsigned char fatGetDirEntry(unsigned short entry)
{
unsigned long sector;
struct direntry *de = 0; // avoid compiler warning by initializing
struct winentry *we;
unsigned char haveLongNameEntry;
unsigned char gotEntry;
unsigned short b;
int i,index;
char *fnbPtr;
unsigned short entrycount = 0;
// read dir data
sector = fatClustToSect(CurrentDirStartCluster);
haveLongNameEntry = 0;
gotEntry = 0;
index = 16; // crank it up
//while(entrycount < entry)
while(1)
{
if(index == 16) // time for next sector ?
{
ataReadSectors( DRIVE0, sector++, 1, SectorBuffer);
de = (struct direntry *) SectorBuffer;
index = 0;
}
// check the status of this directory entry slot
if(de->deName[0] == 0x00)
{
// slot is empty and this is the end of directory
gotEntry = 0;
break;
}
else if(de->deName[0] == 0xE5)
{
// this is an empty slot
// do nothing and move to the next one
}
else
{
// this is a valid and occupied entry
// is it a part of a long file/dir name?
if(de->deAttributes == ATTR_LONG_FILENAME)
{
// we have a long name entry
// cast this directory entry as a "windows" (LFN: LongFileName) entry
we = (struct winentry *) de;
b = WIN_ENTRY_CHARS*( (we->weCnt-1) & 0x0f); // index into string
fnbPtr = &FileNameBuffer[b];
for (i=0;i<5;i++) *fnbPtr++ = we->wePart1[i*2]; // copy first part
for (i=0;i<6;i++) *fnbPtr++ = we->wePart2[i*2]; // second part
for (i=0;i<2;i++) *fnbPtr++ = we->wePart3[i*2]; // and third part
if (we->weCnt & WIN_LAST) *fnbPtr = 0; // in case dirnamelength is multiple of 13, add termination
if ((we->weCnt & 0x0f) == 1) haveLongNameEntry = 1; // flag that we have a complete long name entry set
}
else
{
// we have a short name entry
// check if this is the short name entry corresponding
// to the end of a multi-part long name entry
if(haveLongNameEntry)
{
// a long entry name has been collected
if(entrycount == entry)
{
// desired entry has been found, break out
gotEntry = 1;
break;
}
// otherwise
haveLongNameEntry = 0; // clear long name flag
entrycount++; // increment entry counter
}
else
{
// entry is a short name (8.3 format) without a
// corresponding multi-part long name entry
fnbPtr = FileNameBuffer;
for (i=0;i<8;i++) *fnbPtr++ = de->deName[i]; // copy name
*fnbPtr++ = '.'; // insert '.'
for (i=0;i<3;i++) *fnbPtr++ = de->deExtension[i]; // copy extension
*fnbPtr = 0; // null-terminate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -