ADVERTISEMENT

EFSL_SAM7_example.rar

[C] AT91SAM7S256 – różnice i zalety bibliotek EFSL vs FATfs do obsługi systemu plików

Nie ma problemów. Robiłem to na własną płytkę. Do obsługi karty wykorzystuję sprzętowe SPI (nie SSC).


Download file - link to post
  • EFSL_SAM7_example.rar
    • makefile
    • SRC
      • startup.s
      • low_level_init.c
      • EFSL
        • dir.c
        • time.c
        • ui.c
        • ls.c
        • ioman_v2.c
        • at91_spi.c
        • extract.c
        • fat.c
        • mkfs.c
        • file.c
        • partition.c
        • ioman.c
        • regressiontest.c
        • efs.c
        • plibc.c
        • fs.c
        • disc.c
        • efsl_dbg_printf_arm.c
        • sd.c
        • debug.c
      • main.c
    • LNK
      • sam7s256_ram.ld
      • sam7s256_rom.ld
    • .cproject
    • INC
      • typedefs.h
      • AT91SAM7S256.h
      • EFSL
        • fat.h
        • linuxfile.h
        • ioman.h
        • types.h
        • ls.h
        • extract.h
        • dir.h
        • ioman_v2.h
        • debug.h
        • efs.h
        • error.h
        • partition.h
        • disc.h
        • config.h
        • fs.h
        • arm_spi.h
        • helper.h
        • mkfs.h
        • AT91SAM7S_regs.h
        • file.h
        • efsl_dbg_printf_arm.h
        • time.h
        • sd.h
        • ui.h
        • plibc.h
        • interface.h
    • .dep
      • efs.o.d
      • stproc.o.d
      • mkfs.o.d
      • efsl_dbg_printf_arm.o.d
      • ui.o.d
      • partition.o.d
      • dir.o.d
      • trigtabs.o.d
      • LCD.o.d
      • CODEC.o.d
      • huffman.o.d
      • hermite.o.d
      • fs.o.d
      • file.o.d
      • dct32.o.d
      • fat.o.d
      • S1D15G14_LCD.o.d
      • at91_spi.o.d
      • imdct.o.d
      • mp3dec.o.d
      • low_level_init.o.d
      • buttons.o.d
      • subband.o.d
      • ioman.o.d
      • debug.o.d
      • extract.o.d
      • dqchan.o.d
      • main.o.d
      • AIC.o.d
      • PWM.o.d
      • scalfact.o.d
      • time.o.d
      • dequant.o.d
      • bitstream.o.d
      • hufftabs.o.d
      • ls.o.d
      • buffers.o.d
      • sd.o.d
      • plibc.o.d
      • mp3tabs.o.d
      • disc.o.d
    • .project


EFSL_SAM7_example.rar > dir.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : dir.c *
* Description : The functions of dir.c are part of fs.c, they deal with all *
* the directory specific stuff. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
* *
* mthomas: applied patch for sf.net bug-tracker: *
* - for(c=fs- & gt; FirstSectorRootDir;c & lt; (fs- & gt; FirstSectorRootDir+fs- & gt; volumeId.RootEntryCount/32);c++){ *
* + for(c=fs- & gt; FirstSectorRootDir;c & lt; (fs- & gt; FirstSectorRootDir+fs- & gt; volumeId.RootEntryCount/16);c++){ *
* *
* mthomas: testing - modified byte-array access to use extract.h-functions *
* to avoid aligment warnings with arm-elf-gcc *
\*****************************************************************************/

/*****************************************************************************/
#include " dir.h "
/*****************************************************************************/

/* ****************************************************************************
* void dir_getFileStructure(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
* Description: This function stores the filerecord located at loc in filerec.
* It fetches the required sector for this.
* Return value: void
*/
void dir_getFileStructure(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
{
euint8 *buf;

buf=part_getSect(fs- & gt; part,loc- & gt; Sector,IOM_MODE_READONLY);
*filerec=*(((FileRecord*)buf)+loc- & gt; Offset);
part_relSect(fs- & gt; part,buf);
}

/*****************************************************************************/

/* ****************************************************************************
* void dir_createDirectoryEntry(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
* Description: This function writes the filerecord stored in filerec to disc at
* location loc.
* Return value: void
*/
void dir_createDirectoryEntry(FileSystem *fs,FileRecord *filerec,FileLocation *loc)
{
euint8 *buf;

buf = part_getSect(fs- & gt; part,loc- & gt; Sector,IOM_MODE_READWRITE);
memCpy(filerec,buf+(loc- & gt; Offset*sizeof(*filerec)),sizeof(*filerec));
part_relSect(fs- & gt; part,buf);
}
/*****************************************************************************/

/* ****************************************************************************
* void dir_createDefaultEntry(FileSystem *fs,FileRecord *filerec,eint8* fatfilename)
* Description: This function fills in a filerecord with safe default values, and
* a given fatfilename. If your system has a means of knowing time, here is an
* excellent place to apply it to the filerecord.
* Return value: void
*/
void dir_createDefaultEntry(FileSystem *fs,FileRecord *filerec,eint8* fatfilename)
{
memCpy(fatfilename,filerec- & gt; FileName,11);
filerec- & gt; Attribute=0x00;
filerec- & gt; NTReserved=0x00;
filerec- & gt; MilliSecTimeStamp=0x00;
filerec- & gt; CreatedTime=time_getTime();
filerec- & gt; CreatedDate=time_getDate();
filerec- & gt; AccessDate=filerec- & gt; CreatedDate;
filerec- & gt; FirstClusterHigh=0x0000;
filerec- & gt; WriteTime=filerec- & gt; CreatedTime;
filerec- & gt; WriteDate=filerec- & gt; CreatedDate;
filerec- & gt; FirstClusterLow=0x0000;
filerec- & gt; FileSize=0x00000000;
}
/*****************************************************************************/

/* ****************************************************************************
* void dir_setFirstCluster(File *file,euint32 cluster_addr)
* Description: This function requires modification to release it from
* depending on the file object.
* Return value:
*/
void dir_setFirstCluster(FileSystem *fs,FileLocation *loc,euint32 cluster_addr)
{
euint8 *buf;

buf = part_getSect(fs- & gt; part,loc- & gt; Sector,IOM_MODE_READWRITE);
(((FileRecord*)buf)+loc- & gt; Offset)- & gt; FirstClusterHigh=cluster_addr & gt; & gt; 16;
(((FileRecord*)buf)+loc- & gt; Offset)- & gt; FirstClusterLow=cluster_addr & 0xFFFF;
part_relSect(fs- & gt; part,buf);
}
/*****************************************************************************/

/* ****************************************************************************
* void dir_setFileSize(FileSystem *fs, FileLocation *loc,euint32 numbytes)
* Description: This function changes the filesize recorded at loc- & gt; Sector
* to 'numbytes'.
* Return value: void
*/
void dir_setFileSize(FileSystem *fs, FileLocation *loc,euint32 numbytes)
{
euint8 *buf;

buf = part_getSect(fs- & gt; part,loc- & gt; Sector,IOM_MODE_READWRITE);
(((FileRecord*)buf)+loc- & gt; Offset)- & gt; FileSize=numbytes;
part_relSect(fs- & gt; part,buf);
}
/*****************************************************************************/

/* ****************************************************************************
* esint8 dir_updateDirectoryEntry(FileSystem *fs,FileRecord *entry,FileLocation *loc))
* This function changes the entire entity stores at loc to the data recorded
* in entry. This is for custom updates to the directoryentry.
* Return value: 0 on success, -1 on failure
*/
esint8 dir_updateDirectoryEntry(FileSystem *fs,FileRecord *entry,FileLocation *loc)
{
euint8 *buf;

buf = part_getSect(fs- & gt; part,loc- & gt; Sector,IOM_MODE_READWRITE);
memCpy(entry,buf+(loc- & gt; Offset*sizeof(*entry)),sizeof(*entry));
part_relSect(fs- & gt; part,buf);
return(0);
}

/* ****************************************************************************
* euint32 dir_findFileinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc)
* This function searches for a given fatfilename in the buffer provided.
* It will iterate through the 16 direntry's in the buffer and searches
* for the fatfilename. If found, it will store the offset and attribute
* entry of the directoryrecord in the loc structure.
* If loc is 0, then it's members are not touched.
* Return value: This function returns 0 when it cannot find the file,
* if it can find the file it will return the first cluster number.
*/
euint32 dir_findFileinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc)
{
FileRecord fileEntry;
euint8 c;

for(c=0; c & lt; 16; c++)
{
fileEntry = *(((FileRecord*)buf) + c);
/* Check if the entry is for short filenames */
if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) )
{
if( strMatch((eint8*)fileEntry.FileName,fatname,11) == 0 )
{
/* The entry has been found, return the location in the dir */
if(loc)loc- & gt; Offset = c;
if(loc)loc- & gt; attrib = fileEntry.Attribute;
if((((euint32 )fileEntry.FirstClusterHigh) & lt; & lt; 16)+ fileEntry.FirstClusterLow==0){
return(1); /* Lie about cluster, 0 means not found! */
}else{
return
(
(((euint32 )fileEntry.FirstClusterHigh) & lt; & lt; 16)
+ fileEntry.FirstClusterLow
);
}
}
}
}
return(0);
}

/* ****************************************************************************
* euint32 dir_findFreeEntryinBuf(euint8* buf, FileLocation *loc)
* This function searches for a free entry in a given sector 'buf'.
* It will put the offset into the loc- & gt; Offset field, given that loc is not 0.
* Return value: 1 when it found a free spot, 0 if it hasn't.
*/
euint32 dir_findFreeEntryinBuf(euint8* buf, FileLocation *loc)
{
FileRecord fileEntry;
euint8 c;

for(c=0;c & lt; 16;c++){
fileEntry = *(((FileRecord*)buf) + c);
if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) ){
if(fileEntry.FileName[0] == 0x00 ||
fileEntry.FileName[0] == 0xE5 ){
if(loc)loc- & gt; Offset=c;
return(1);
}
}
}
return(0);
}

/* ****************************************************************************
* euint32 dir_findinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc)
* Description: This function searches for a given fatfilename in a buffer.
* Return value: Returns 0 on not found, and the firstcluster when the name is found.
*/
euint32 dir_findinBuf(euint8 *buf, eint8 *fatname, FileLocation *loc, euint8 mode)
{
switch(mode){
case DIRFIND_FILE:
return(dir_findFileinBuf(buf,fatname,loc));
break;
case DIRFIND_FREE:
return(dir_findFreeEntryinBuf(buf,loc));
break;
default:
return(0);
break;
}
return(0);
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 dir_findinCluster(FileSystem *fs,euint32 cluster,eint8 *fatname, FileLocation *loc, euint8 mode)
* This function will search for an existing (fatname) or free directory entry
* in a full cluster.
* Return value: 0 on failure, firstcluster on finding file, and 1 on finding free spot.
*/
euint32 dir_findinCluster(FileSystem *fs,euint32 cluster,eint8 *fatname, FileLocation *loc, euint8 mode)
{
euint8 c,*buf=0;
euint32 fclus;

for(c=0;c & lt; fs- & gt; volumeId.SectorsPerCluster;c++){
buf = part_getSect(fs- & gt; part,fs_clusterToSector(fs,cluster)+c,IOM_MODE_READONLY);
if((fclus=dir_findinBuf(buf,fatname,loc,mode))){
if(loc)loc- & gt; Sector=fs_clusterToSector(fs,cluster)+c;
part_relSect(fs- & gt; part,buf);
return(fclus);
}
part_relSect(fs- & gt; part,buf); /* Thanks Mike ;) */
}
return(0);
}

/* ****************************************************************************
* euint32 dir_findinDir(FileSystem *fs, eint8* fatname,euint32 firstcluster, FileLocation *loc, euint8 mode)
* This function will search for an existing (fatname) or free directory entry
* in a directory, following the clusterchains.
* Return value: 0 on failure, firstcluster on finding file, and 1 on finding free spot.
*/
euint32 dir_findinDir(FileSystem *fs, eint8* fatname,euint32 firstcluster, FileLocation *loc, euint8 mode)
{
euint32 c=0,cluster;
ClusterChain Cache;

Cache.DiscCluster = Cache.FirstCluster = firstcluster;
Cache.LogicCluster = Cache.LastCluster = Cache.Linear = 0;

if(firstcluster & lt; = 1){
return(dir_findinRootArea(fs,fatname,loc,mode));
}

while(!fat_LogicToDiscCluster(fs, & Cache,c++)){
if((cluster=dir_findinCluster(fs,Cache.DiscCluster,fatname,loc,mode))){
return(cluster);
}
}
return(0);
}

/* ****************************************************************************
* euint32 dir_findinDir(FileSystem *fs, eint8* fatname,euint32 firstcluster, FileLocation *loc, euint8 mode)
* This function will search for an existing (fatname) or free directory entry
* in the rootdirectory-area of a FAT12/FAT16 filesystem.
* Return value: 0 on failure, firstcluster on finding file, and 1 on finding free spot.
*/
euint32 dir_findinRootArea(FileSystem *fs,eint8* fatname, FileLocation *loc, euint8 mode)
{
euint32 c,fclus;
euint8 *buf=0;

if((fs- & gt; type != FAT12) & & (fs- & gt; type != FAT16))return(0);

//#warning " inofficial find in root patch included "
/* for(c=fs- & gt; FirstSectorRootDir;c & lt; (fs- & gt; FirstSectorRootDir+fs- & gt; volumeId.RootEntryCount/32);c++){*/
for(c=fs- & gt; FirstSectorRootDir;c & lt; (fs- & gt; FirstSectorRootDir+fs- & gt; volumeId.RootEntryCount/16);c++) {
buf = part_getSect(fs- & gt; part,c,IOM_MODE_READONLY);
if((fclus=dir_findinBuf(buf,fatname,loc,mode))){
if(loc)loc- & gt; Sector=c;
part_relSect(fs- & gt; part,buf);
return(fclus);
}
part_relSect(fs- & gt; part,buf);
}
part_relSect(fs- & gt; part,buf);
return(0);
}

/* ****************************************************************************
* esint8 dir_getFatFileName(eint8* filename, eint8* fatfilename)
* This function will take a full directory path, and strip off all leading
* dirs and characters, leaving you with the MS-DOS notation of the actual filename.
* Return value: 1 on success, 0 on not being able to produca a filename
*/
esint8 dir_getFatFileName(eint8* filename, eint8* fatfilename)
{
eint8 ffnamec[11],*next,nn=0;

memClr(ffnamec,11); memClr(fatfilename,11);
next = filename;

if(*filename=='/')next++;

while((next=file_normalToFatName(next,ffnamec))){
memCpy(ffnamec,fatfilename,11);
nn++;
}
if(nn)return(1);
return(0);
}

/* ****************************************************************************
* esint8 dir_addCluster(FileSystem *fs,euint32 firstCluster)
* This function extends a directory by 1 cluster + optional the number of
* clusters you want pre-allocated. It will also delete the contents of that
* cluster. (or clusters)
* Return value: 0 on success, -1 on fail
*/
esint8 dir_addCluster(FileSystem *fs,euint32 firstCluster)
{
euint32 lastc,logicalc;
ClusterChain cache;

fs_initClusterChain(fs, & cache,firstCluster);
if(fat_allocClusterChain(fs, & cache,1)){
return(-1);
}
lastc = fs_getLastCluster(fs, & cache);
if(CLUSTER_PREALLOC_DIRECTORY){
if(fat_allocClusterChain(fs, & cache,CLUSTER_PREALLOC_DIRECTORY)){
return(-1);
}
logicalc = fat_DiscToLogicCluster(fs,firstCluster,lastc);
while(!fat_LogicToDiscCluster(fs, & cache,++logicalc)){
fs_clearCluster(fs,cache.DiscCluster);
}
}else{
fs_clearCluster(fs,lastc);
}
return(0);
}


EFSL_SAM7_example.rar > file.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : file.c *
* Description : This file contains functions dealing with files such as: *
* fopen, fread and fwrite. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
* Revisions by Mike Anton: *
* 26. May 2006 - Fixed a bug in file_initFile() that left the ClusterCount *
* value uninitialized. *
\*****************************************************************************/

/*****************************************************************************/
#include " file.h "
/*****************************************************************************/

/* ****************************************************************************
* euint32 file_fread(File *file,euint32 offset, euint32 size,euint8 *buf)
* Description: This function reads 'size' bytes from 'file' starting at
* 'offset' and puts the result in '*buf'.
* Return value: amount of bytes actually read (can differ from the given
* size when the file was smaller
*/
euint32 file_fread(File *file,euint32 offset, euint32 size,euint8 *buf)
{
euint32 bytes_read=0,size_left=size,coffset=offset;
euint32 cclus,csec,cbyte;
euint32 rclus,rsec;
euint32 btr;
euint8 *tbuf;

if(!file_getAttr(file,FILE_STATUS_OPEN))return(0);

if(offset & gt; =file- & gt; FileSize)
size_left=0; /* Offset check */

if( (offset+size & gt; file- & gt; FileSize) & & size_left!=0)
size_left=file- & gt; FileSize-offset;

while(size_left & gt; 0){

cclus = coffset/(512*file- & gt; fs- & gt; volumeId.SectorsPerCluster);
csec = (coffset/(512))%file- & gt; fs- & gt; volumeId.SectorsPerCluster;
cbyte = coffset%512;

if(cbyte!=0 || size_left & lt; 512){
btr = 512-(coffset%512) & gt; =size_left?size_left:512-(coffset%512);
}else{
btr = 512;
}

if((fat_LogicToDiscCluster(file- & gt; fs, & (file- & gt; Cache),cclus))!=0){
return(0);
}
rclus=file- & gt; Cache.DiscCluster;
rsec=fs_clusterToSector(file- & gt; fs,rclus);


if(btr==512){
/*part_readBuf(file- & gt; fs- & gt; part,rsec+csec,buf+bytes_read);*/
part_directSectorRead(file- & gt; fs- & gt; part,rsec+csec,buf+bytes_read);
}else{
/*part_readBuf(file- & gt; fs- & gt; part,rsec+csec,tbuf);*/
tbuf = part_getSect(file- & gt; fs- & gt; part,rsec+csec,IOM_MODE_READONLY);
memCpy(tbuf+(coffset%512),buf+bytes_read,btr);
part_relSect(file- & gt; fs- & gt; part,tbuf);
}

coffset+=btr;
bytes_read+=btr;
size_left-=btr;
}

return(bytes_read);
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 file_read (File *file,euint32 size,euint8 *buf)
* Description: This function reads from a file, taking the FilePtr into account
* and advancing it according to the freadcall.
* Return value: Value obtained from fread
*/
euint32 file_read(File *file,euint32 size,euint8 *buf)
{
euint32 r;

r=file_fread(file,file- & gt; FilePtr,size,buf);
file- & gt; FilePtr+=r;
return(r);
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 file_write(File *file, euint32 size,euint8 *buf)
* Description: This function writes to a file, taking FilePtr into account
* and advancing it according to the fwritecall.
* Return value: Value obtained from fread
*/
euint32 file_write(File *file, euint32 size,euint8 *buf)
{
euint32 r;

r=file_fwrite(file,file- & gt; FilePtr,size,buf);
file- & gt; FilePtr+=r;
return(r);
}
/*****************************************************************************/

/* ****************************************************************************
* esint16 file_setpos(File *file,euint32 pos)
* Description: This function does a sanity check on the requested position
* and changes the fileptr accordingly.
* Return value: 0 on success and -1 on failure.
*/
esint16 file_setpos(File *file,euint32 pos)
{
if(pos & lt; =file- & gt; FileSize){
file- & gt; FilePtr=pos;
return(0);
}
return(-1);
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 file_fwrite(File* file,euint32 offset,euint32 size,euint8* buf)
* Description: This function writes to a file, at offset 'offset' and size 'size'.
* It also updates the FileSize in the object, and discstructure.
* Return value: Bytes actually written.
*/
euint32 file_fwrite(File* file,euint32 offset,euint32 size,euint8* buf)
{
euint32 need_cluster;
euint32 cclus,csec,cbyte;
euint32 size_left=size,bytes_written=0;
euint32 rclus,rsec;
euint32 coffset=offset;
euint16 btr;
euint8 *tbuf;

if(!file_getAttr(file,FILE_STATUS_OPEN) || !file_getAttr(file,FILE_STATUS_WRITE))return(0);

if(offset & gt; file- & gt; FileSize){
offset=file- & gt; FileSize;
}

need_cluster = file_requiredCluster(file,offset,size);

if(need_cluster){
if(fat_allocClusterChain(file- & gt; fs, & (file- & gt; Cache),need_cluster+CLUSTER_PREALLOC_FILE)!=0){
return(0);
}
}

while(size_left & gt; 0){

cclus = coffset/(512*file- & gt; fs- & gt; volumeId.SectorsPerCluster);
csec = (coffset/(512))%file- & gt; fs- & gt; volumeId.SectorsPerCluster;
cbyte = coffset%512;

if(cbyte!=0 || size_left & lt; 512){
btr = 512-(coffset%512) & gt; =size_left?size_left:512-(coffset%512);
}else{
btr = 512;
}

if((fat_LogicToDiscCluster(file- & gt; fs, & (file- & gt; Cache),cclus))!=0){
file- & gt; FileSize+=bytes_written;
dir_setFileSize(file- & gt; fs, & (file- & gt; Location),file- & gt; FileSize);
return(bytes_written);
}
rclus=file- & gt; Cache.DiscCluster;
rsec=fs_clusterToSector(file- & gt; fs,rclus);

if(btr==512){
/*part_writeBuf(file- & gt; fs- & gt; part,rsec+csec,buf+bytes_written);*/
part_directSectorWrite(file- & gt; fs- & gt; part,rsec+csec,buf+bytes_written);
}else{
/*part_readBuf(file- & gt; fs- & gt; part,rsec+csec,tbuf);*/
tbuf = part_getSect(file- & gt; fs- & gt; part,rsec+csec,IOM_MODE_READWRITE);
memCpy(buf+bytes_written,tbuf+(coffset%512),btr);
/*part_writeBuf(file- & gt; fs- & gt; part,rsec+csec,tbuf);*/
part_relSect(file- & gt; fs- & gt; part,tbuf);
}

coffset+=btr;
bytes_written+=btr;
size_left-=btr;
}

if(bytes_written & gt; file- & gt; FileSize-offset){
file- & gt; FileSize+=bytes_written-(file- & gt; FileSize-offset);
}

return(bytes_written);
}

/* ***************************************************************************\
* signed eint8 file_fopen(FileSystem *fs,File* file,eint8* filename)
* Description: This functions opens a file.
* This function is about to be redesigned. No Docs.
* Return value:
*/
esint8 file_fopen(File* file,FileSystem *fs,eint8* filename,eint8 mode)
{
FileLocation loc;
FileRecord wtmp;
eint8 fatfilename[11];
euint32 sec;

dir_getFatFileName(filename,fatfilename);

switch(mode)
{
case MODE_READ:
if(fs_findFile(fs,filename, & loc,0)==1)
{
dir_getFileStructure(fs, & (file- & gt; DirEntry), & loc);
file_initFile(file,fs, & loc);
file_setAttr(file,FILE_STATUS_OPEN,1);
file_setAttr(file,FILE_STATUS_WRITE,0);
return(0);
}
return(-1);
break;
case MODE_WRITE:
if(fs_findFile(fs,filename, & loc, & sec)) /* File may NOT exist, but parent HAS to exist */
{
return(-2);
}
if(sec==0){ /* Parent dir does not exist */
return(-4);
}
if(fs_findFreeFile(fs,filename, & loc,0))
{
dir_createDefaultEntry(fs, & wtmp,fatfilename);
dir_createDirectoryEntry(fs, & wtmp, & loc);
memCpy( & wtmp, & (file- & gt; DirEntry),sizeof(wtmp));
file_initFile(file,fs, & loc);
sec=fs_getNextFreeCluster(file- & gt; fs,fs_giveFreeClusterHint(file- & gt; fs));
dir_setFirstCluster(file- & gt; fs, & (file- & gt; Location),sec);
fs_setFirstClusterInDirEntry( & (file- & gt; DirEntry),sec);
fs_initClusterChain(fs, & (file- & gt; Cache),sec);
fat_setNextClusterAddress(fs,sec,fat_giveEocMarker(fs));
file_setAttr(file,FILE_STATUS_OPEN,1);
file_setAttr(file,FILE_STATUS_WRITE,1);
return(0);
}
else
{
return(-3);
}
break;
case MODE_APPEND:
if(fs_findFile(fs,filename, & loc,0)==1) /* File exists */
{
dir_getFileStructure(fs, & (file- & gt; DirEntry), & loc);
file_initFile(file,fs, & loc);
if(file- & gt; Cache.FirstCluster==0){
sec=fs_getNextFreeCluster(file- & gt; fs,fs_giveFreeClusterHint(file- & gt; fs));
dir_setFirstCluster(file- & gt; fs, & (file- & gt; Location),sec);
fs_setFirstClusterInDirEntry( & (file- & gt; DirEntry),sec);
fat_setNextClusterAddress(fs,sec,fat_giveEocMarker(fs));
file_initFile(file,fs, & loc);
}
file_setpos(file,file- & gt; FileSize);
file_setAttr(file,FILE_STATUS_OPEN,1);
file_setAttr(file,FILE_STATUS_WRITE,1);
}
else /* File does not excist */
{
if(fs_findFreeFile(fs,filename, & loc,0))
{
dir_createDefaultEntry(fs, & wtmp,fatfilename);
dir_createDirectoryEntry(fs, & wtmp, & loc);
memCpy( & wtmp, & (file- & gt; DirEntry),sizeof(wtmp));
file_initFile(file,fs, & loc);
sec=fs_getNextFreeCluster(file- & gt; fs,fs_giveFreeClusterHint(file- & gt; fs));
dir_setFirstCluster(file- & gt; fs, & (file- & gt; Location),sec);
fs_setFirstClusterInDirEntry( & (file- & gt; DirEntry),sec);
fs_initClusterChain(fs, & (file- & gt; Cache),sec);
fat_setNextClusterAddress(fs,sec,fat_giveEocMarker(fs));
file_setAttr(file,FILE_STATUS_OPEN,1);
file_setAttr(file,FILE_STATUS_WRITE,1);
}
else
{
return(-3);
}
}
return(0);
break;
default:
return(-4);
break;
}
return(-5);
}
/*****************************************************************************/

/* ****************************************************************************
* esint8 file_fclose(File *file)
* Description: This function closes a file, by clearing the object.
* Return value: 0 on success.
*/
esint8 file_fclose(File *file)
{
if(fs_hasTimeSupport()){
file- & gt; DirEntry.AccessDate = time_getDate();
if(file_getAttr(file,FILE_STATUS_WRITE)){
file- & gt; DirEntry.FileSize = file- & gt; FileSize;
file- & gt; DirEntry.WriteDate = file- & gt; DirEntry.AccessDate;
file- & gt; DirEntry.WriteTime = time_getTime();
}
dir_updateDirectoryEntry(file- & gt; fs, & (file- & gt; DirEntry), & (file- & gt; Location));
}else{
if(file_getAttr(file,FILE_STATUS_WRITE)){
dir_setFileSize(file- & gt; fs, & (file- & gt; Location),file- & gt; FileSize);
}
}

memClr(file,sizeof(*file));
file_setAttr(file,FILE_STATUS_OPEN,0);
file_setAttr(file,FILE_STATUS_WRITE,0);
return(0);
}


/* ****************************************************************************
* void file_initFile(File *file, FileSystem *fs, FileLocation *loc)
* Description: This function initialises a new file object, by filling in
* the fs pointer, filesize (note, that DirEntry must already be filled in)
* and known cache parameters.
* Return value: void
*/
void file_initFile(File *file, FileSystem *fs, FileLocation *loc)
{
file- & gt; fs=fs;
file- & gt; FileSize=file- & gt; DirEntry.FileSize;
file- & gt; FilePtr=0;
file- & gt; Location.Sector=loc- & gt; Sector;
file- & gt; Location.Offset=loc- & gt; Offset;
file- & gt; Cache.Linear=0;
file- & gt; Cache.FirstCluster=(((euint32)file- & gt; DirEntry.FirstClusterHigh) & lt; & lt; 16)+
file- & gt; DirEntry.FirstClusterLow;
file- & gt; Cache.LastCluster=0;
file- & gt; Cache.LogicCluster=0;
file- & gt; Cache.DiscCluster=file- & gt; Cache.FirstCluster;

//#warning " non-official ClusterCount=0 patch by Mike Anton active "
file- & gt; Cache.ClusterCount=0; /* 0 means NOT known (added by Mike Anton) */
}
/*****************************************************************************/

/* ****************************************************************************
* euint8* file_normalToFatName(eint8* filename,eint8* fatfilename)
* Description: This function converts a human readable filename (limited to
* 8.3 eint8 character) to a valid FAT (not VFAT) filename. Invalid characters are
* changed to capital X and only the first 11 characters are used.
* Furthermore all letters are capitalised.
* Return value: pointer after the filename
*/
eint8* file_normalToFatName(eint8* filename,eint8* fatfilename)
{
euint8 c,dot=0,vc=0;

for(c=0;c & lt; 11;c++)fatfilename[c]=' ';

c=0;

if(*filename == '.'){
fatfilename[0]='.';
vc++;
if(*(filename+1) == '.'){
fatfilename[1]='.';
filename+=2;
}else{
filename++;
}
}else{
while(*filename != '\0' & & *filename != ' ' & & *filename != '/'){
if(*filename=='.' & & !dot){
dot=1;
c=8;
}else{
if(dot){
if(c & lt; =10){
fatfilename[c]=file_validateChar(*filename);
c++;
}
}else{
if(c & lt; =7){
fatfilename[c]=file_validateChar(*filename);
c++; vc++;
}
}
}
filename++;
}
}

if(vc & gt; 0){
if(*filename=='\0'){
return(filename);
}else{
return(filename+1);
}
}else{
return(0);
}
}
/*****************************************************************************/

/* ****************************************************************************
*
* Description: This function takes the character c, and if it is not a *
* valid FAT Filename character returns X. If it is a lowercase letter the *
* uppercase equivalent is returned. The remaining characters are returned *
* as they are.
* Return value: The validated char
*/
euint8 file_validateChar(euint8 c)
{
if( (c & lt; 0x20) || (c & gt; 0x20 & & c & lt; 0x30 & & c!='-') || (c & gt; 0x39 & & c & lt; 0x41) || (c & gt; 0x5A & & c & lt; 0x61 & & c!='_') || (c & gt; 0x7A & & c!='~') )
return(0x58);
if( c & gt; =0x61 & & c & lt; =0x7A )
return(c-32);

return(c);
}
/*****************************************************************************/

/* ****************************************************************************
* void ioman_setAttr(IOManager *ioman,euint16 bufplace,euint8 attribute,euint8 val)
* Description: This sets the attribute of 'bufplace' to the given value (binary).
*
* Return value: void
*/
void file_setAttr(File* file,euint8 attribute,euint8 val)
{
if(val){
file- & gt; FileStatus|=1 & lt; & lt; attribute;
}else{
file- & gt; FileStatus & =~(1 & lt; & lt; attribute);
}
}
/*****************************************************************************/

/* ****************************************************************************
* euint8 ioman_getAttr(IOManager *ioman,euint16 bufplace,euint8 attribute)
* Description: This function retrieves an attribute from the bufstat array.
* It returns nonzero when it attribute is true and 0 when it is false.
* Please note, I said " nonzero " , not 1.
* Return value: Attribute.
*/
euint8 file_getAttr(File* file,euint8 attribute)
{
return(file- & gt; FileStatus & (1 & lt; & lt; attribute));
}
/*****************************************************************************/

euint32 file_requiredCluster(File *file,euint32 offset, euint32 size)
{
euint32 clusters_required,clustersize;
euint32 hc;

if((offset+size) & gt; file- & gt; FileSize){
if(file- & gt; Cache.ClusterCount==0){ /* Number of cluster unknown */
hc = fat_countClustersInChain(file- & gt; fs,file- & gt; Cache.FirstCluster);
file- & gt; Cache.ClusterCount = hc;
}else{
hc = file- & gt; Cache.ClusterCount; /* This better be right */
}
clustersize = file- & gt; fs- & gt; volumeId.BytesPerSector * file- & gt; fs- & gt; volumeId.SectorsPerCluster;
if((size-file- & gt; FileSize+offset) & gt;
((hc-((file- & gt; FileSize+clustersize-1)/clustersize))*clustersize)){
clusters_required = (((offset+size)-(hc*clustersize))+clustersize-1)/clustersize;
}else{
clusters_required = 0;
}
}else{
clusters_required = 0;
}
return(clusters_required);
}


EFSL_SAM7_example.rar > time.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : time.c *
* Description : This file contains functions for time support *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/

/*****************************************************************************/
#include " time.h "
#include " fs.h "
/*****************************************************************************/

euint16 fs_makeDate(void)
{
#ifndef DATE_TIME_SUPPORT
return(0);
#else
euint8 m,d;
euint16 y;

y = time_getYear()-1980;
m = time_getMonth();
d = time_getDay();

return(
(y & gt; 127?127 & lt; & lt; 9:(y & 0x3F) & lt; & lt; 9) |
((m==0||m & gt; 12)?1:(m & 0xF) & lt; & lt; 5) |
((d==0||d & gt; 31)?1:(d & 0x1F))
);
#endif
}
/*****************************************************************************/

euint16 fs_makeTime(void)
{
#ifndef DATE_TIME_SUPPORT
return(0);
#else
euint8 s,m,h;

s = time_getSecond();
m = time_getMinute();
h = time_getHour();

return(
(h & gt; 23?0:(h & 0x1F) & lt; & lt; 11) |
(m & gt; 59?0:(m & 0x3F) & lt; & lt; 5) |
(s & gt; 59?0:(s-s%2)/2)
);
#endif
}
/*****************************************************************************/

euint8 fs_hasTimeSupport(void)
{
#ifdef DATE_TIME_SUPPORT
return(1);
#else
return(0);
#endif
}
/*****************************************************************************/


EFSL_SAM7_example.rar > ui.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : ui.c *
* Description : This file contains functions which will be presented to the *
* user of this library. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/

/*****************************************************************************/
#include " ui.h "
/*****************************************************************************/

/*****************************************************************************
* short listfiles(char *dir)
*
* Deschription: This function returns the number of files / directories
* inside the given directory.
*
* Return value: number of files/directories in the given directory or -1
* if directory does not exist.
\*****************************************************************************/

short listFiles(FileSystem *fs, char *dirname)
{
unsigned long startCluster;
unsigned char fileEntryCount;
unsigned short counter=0;
unsigned long offset=0;
FileRecord fileEntry;
FileLocation loc;
unsigned char buf[512];
File dir;
unsigned short i;

/* Find out if we are searching in the root dir or in */
if(dirname[0]=='/' & & dirname[1]=='\0')
{
if( (fs- & gt; type == FAT12) || (fs- & gt; type == FAT16) )
{
for(i=0;i & lt; =(fs- & gt; volumeId.RootEntryCount/16);i++)
{
loc.Sector=fs- & gt; FirstSectorRootDir + i;
part_readBuf(fs- & gt; part,loc.Sector,buf);
/* I STOPPED HERE*/
/* FIXME */
}
}
}
else /* Normal directory */
{
/* Check if path given is a directory */
if(fs_findFile(fs,dirname, & loc,0)!=2)
{
FUNC_OUT((TXT( " " )));
return(-1);
}

/* Find out what the startcluster of the directory is */
part_readBuf(fs- & gt; part,loc.Sector, buf);
fileEntry = *(((FileRecord*)buf) + loc.Offset);
startCluster = (((unsigned long)fileEntry.FirstClusterHigh) & lt; & lt; 16)
+ fileEntry.FirstClusterLow;

/* Init of dir */
dir.fs=fs;
dir.Cache.LogicCluster=-1;
dir.Cache.FirstCluster=startCluster;
dir.DirEntry.Attribute=ATTR_DIRECTORY;

while((file_fread( & dir,offset,512,buf)))
{
DBG((TXT( " Read 512 bytes from dir with offset %li.\n " ),offset));
for(fileEntryCount=0;fileEntryCount & lt; 16;fileEntryCount++)
{
fileEntry = *(((FileRecord*)buf) + fileEntryCount);
if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) )
{
if
(
(fileEntry.FileName[0] & gt; ='A' & & fileEntry.FileName[0] & lt; ='Z')
||
(fileEntry.FileName[0] & gt; ='0' & & fileEntry.FileName[0] & lt; ='9')
)
{
DBG((TXT( " Filename: %s\n " ),fileEntry.FileName));
counter++;
}
}
}
offset+=512;
}
}

FUNC_OUT((TXT( " " )));
return(counter);

return(-1);
}
/*****************************************************************************/

/* ****************************************************************************
* esint16 rmfile(FileSystem *fs,euint8* filename)
* Description: This function takes a filename as argument and deletes it,
* by freeing it's clusterchain, and deleting it's entry from the directory.
* Return value: 0 on success, -1 on errors, like file not found.
*/
esint16 rmfile(FileSystem *fs,euint8* filename)
{
FileLocation loc;
ClusterChain cache;
euint8* buf;
euint32 firstCluster=0;

if((fs_findFile(fs,(eint8*)filename, & loc,0))==1){
buf=part_getSect(fs- & gt; part,loc.Sector,IOM_MODE_READWRITE);
firstCluster = ex_getb16(buf,loc.Offset*32+20);
firstCluster & lt; & lt; = 16;
firstCluster += ex_getb16(buf,loc.Offset*32+26);
/* Bugfix:
* By clearing the entire structure, you mark end of directory.
* If this is not the case, files that are further away cannot
* be opened anymore by implementations that follow the spec. */
/*memClr(buf+(loc.Offset*32),32);*/
*(buf+(loc.Offset*32)+0) = 0xE5; /* Mark file deleted */
part_relSect(fs- & gt; part,buf);
cache.DiscCluster = cache.LastCluster = cache.Linear = cache.LogicCluster = 0;
cache.FirstCluster = firstCluster;
fat_unlinkClusterChain(fs, & cache);
return(0);
}
return(-1);
}

/*****************************************************************************/
esint8 mkdir(FileSystem *fs,eint8* dirname)
{
FileLocation loc;
FileRecord direntry;
euint32 nc,parentdir;
euint8* buf;
eint8 ffname[11];

if( fs_findFile(fs,dirname, & loc, & parentdir) ){
return(-1);
}
if(parentdir==0)return(-2);

if(!fs_findFreeFile(fs,dirname, & loc,0))return(-3);

/* You may never search for a free cluster, and the call
* functions that may cause changes to the FAT table, that
* is why getNextFreeCluster has to be called AFTER calling
* fs_findFreeFile, which may have to expand a directory in
* order to store the new filerecord !!
*/

nc = fs_getNextFreeCluster(fs,fs_giveFreeClusterHint(fs));
if(nc==0)return(0);

fs_clearCluster(fs,nc);

buf = part_getSect(fs- & gt; part,loc.Sector,IOM_MODE_READWRITE);

dir_getFatFileName(dirname,ffname);
memClr( & direntry,sizeof(direntry));
memCpy(ffname, & direntry,11);
direntry.FileSize = 0;
direntry.FirstClusterHigh=nc & gt; & gt; 16;
direntry.FirstClusterLow=nc & 0xFFFF;
direntry.Attribute = ATTR_DIRECTORY;
memCpy( & direntry,buf+(32*loc.Offset),32);

part_relSect(fs- & gt; part,buf);

buf = part_getSect(fs- & gt; part,fs_clusterToSector(fs,nc),IOM_MODE_READWRITE);

memClr( & direntry,sizeof(direntry));
memCpy( " . " , & direntry,11);
direntry.Attribute = ATTR_DIRECTORY;
direntry.FileSize = 0;
direntry.FirstClusterHigh=nc & gt; & gt; 16;
direntry.FirstClusterLow=nc & 0xFFFF;
memCpy( & direntry,buf,32);

if(fs- & gt; type == FAT32 & & parentdir == fs- & gt; volumeId.RootCluster){
parentdir = 0;
}
if(fs- & gt; type != FAT32 & & parentdir & lt; =1){
parentdir = 0;
}

memClr( & direntry,sizeof(direntry));
memCpy( " .. " , & direntry,11);
direntry.Attribute = ATTR_DIRECTORY;
direntry.FileSize = 0;
direntry.FirstClusterHigh=parentdir & gt; & gt; 16;
direntry.FirstClusterLow=parentdir & 0xFFFF;
memCpy( & direntry,buf+32,32);

part_relSect(fs- & gt; part,buf);

fat_setNextClusterAddress(fs,nc,fat_giveEocMarker(fs));

return(0);
}


EFSL_SAM7_example.rar > plibc.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : plibc.c *
* Description : This file contains replacements of common c library functions *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/

/*****************************************************************************/
#include " plibc.h "
/*****************************************************************************/

/* ****************************************************************************
* unsigned short strMatch(char* bufa, char*bufb, unsigned long n)
* Description: Compares bufa and bufb for a length of n bytes.
* Return value: Returns the number of character NOT matching.
*/
euint16 strMatch(eint8* bufa, eint8*bufb,euint32 n)
{
euint32 c;
euint16 res=0;
for(c=0;c & lt; n;c++)if(bufa[c]!=bufb[c])res++;
return(res);
}
/*****************************************************************************/


/* ****************************************************************************
* void memCpy(void* psrc, void* pdest, unsigned long size)
* Description: Copies the contents of psrc into pdest on a byte per byte basis.
* The total number of bytes copies is size.
*/
void memCpy(void* psrc, void* pdest, euint32 size)
{
while(size & gt; 0){
*((eint8*)pdest+size-1)=*((eint8*)psrc+size-1);
size--;
}
}
/*****************************************************************************/

void memClr(void *pdest,euint32 size)
{
while(size & gt; 0){
*(((eint8*)pdest)+size-1)=0x00;
size--;
}
}

void memSet(void *pdest,euint32 size,euint8 data)
{
while(size & gt; 0){
*(((eint8*)pdest)+size-1)=data;
size--;
}
}


EFSL_SAM7_example.rar > fs.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : fs.c *
* Description : These are general filesystem functions, supported by the *
* functions of dir.c and fat.c file.c uses these functions *
* heavily, but is not used by fs.c (not true anymore) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/

/*****************************************************************************/
#include " fs.h "
#include " fat.h "
#include " dir.h "
/*****************************************************************************/

/* ****************************************************************************
* eint16 fs_initFs(FileSystem *fs,Partition *part)
* Description: This functions glues the initialisation of the filesystem together.
* It loads the volumeID, computes the FS type and searches for the rootsector.
* Return value: Returns 0 on succes and -1 on error (if magic code is wrong)
*/
eint16 fs_initFs(FileSystem *fs,Partition *part)
{
if(!fs_isValidFat(part)){
return(-1);
}
fs- & gt; part=part;
fs_loadVolumeId(fs,part);
if(!fs_verifySanity(fs))return(-2);
fs_countDataSectors(fs);
fs_determineFatType(fs);
fs_findFirstSectorRootDir(fs);
fs_initCurrentDir(fs);
return(0);
}
/*****************************************************************************/

/* ****************************************************************************
* eint16 fs_isValidFat(Partition *part)
* Description: This functions loads the volumeID and checks if the magic
* value is present.
* Return value: returns 0 when magic code is missing, 1 if it is there.
*/
eint16 fs_isValidFat(Partition *part)
{
euint8 *buf;

buf=part_getSect(part,0,IOM_MODE_READONLY|IOM_MODE_EXP_REQ); /* Load Volume label */
if( ex_getb16(buf,0x1FE) != 0xAA55 ){
return (0);
}
part_relSect(part,buf);
return(1);
}
/*****************************************************************************/

/* ****************************************************************************
* void fs_loadVolumeId(FileSystem *fs, Partition *part)
* Description: This function loads all relevant fields from the volumeid.
*/
void fs_loadVolumeId(FileSystem *fs, Partition *part)
{
euint8 *buf;

buf=part_getSect(part,0,IOM_MODE_READONLY|IOM_MODE_EXP_REQ);

fs- & gt; volumeId.BytesPerSector=ex_getb16(buf,0x0B);
fs- & gt; volumeId.SectorsPerCluster=*((eint8*)(buf+0x0D));
fs- & gt; volumeId.ReservedSectorCount=ex_getb16(buf,0x0E);
fs- & gt; volumeId.NumberOfFats=*((eint8*)(buf+0x10));
fs- & gt; volumeId.RootEntryCount=ex_getb16(buf,0x11);
fs- & gt; volumeId.SectorCount16=ex_getb16(buf,0x13);
fs- & gt; volumeId.FatSectorCount16=ex_getb16(buf,0x16);
fs- & gt; volumeId.SectorCount32=ex_getb32(buf,0x20);
fs- & gt; volumeId.FatSectorCount32=ex_getb32(buf,0x24);
fs- & gt; volumeId.RootCluster=ex_getb32(buf,0x2C);

part_relSect(part,buf);

}
/*****************************************************************************/

/* ****************************************************************************
* esint16 fs_verifySanity(FileSystem *fs)
* Description: Does some sanity calculations.
* Return value: 1 on success, 0 when discrepancies were found.
*/
esint16 fs_verifySanity(FileSystem *fs)
{
esint16 sane=1; /* Sane until proven otherwise */
/* First check, BPS, we only support 512 */
if(fs- & gt; volumeId.BytesPerSector!=512)sane=0;
/* Check is SPC is valid (multiple of 2, and clustersize & gt; =32KB */
if(!((fs- & gt; volumeId.SectorsPerCluster == 1 ) |
(fs- & gt; volumeId.SectorsPerCluster == 2 ) |
(fs- & gt; volumeId.SectorsPerCluster == 4 ) |
(fs- & gt; volumeId.SectorsPerCluster == 8 ) |
(fs- & gt; volumeId.SectorsPerCluster == 16) |
(fs- & gt; volumeId.SectorsPerCluster == 32) |
(fs- & gt; volumeId.SectorsPerCluster == 64) ))sane=0;
/* Any number of FAT's should be supported... (untested) */
/* There should be at least 1 reserved sector */
if(fs- & gt; volumeId.ReservedSectorCount==0)sane=0;
if(fs- & gt; volumeId.FatSectorCount16 != 0){
if(fs- & gt; volumeId.FatSectorCount16 & gt; fs- & gt; part- & gt; disc- & gt; partitions[fs- & gt; part- & gt; activePartition].numSectors)sane=0;
}else{
if(fs- & gt; volumeId.FatSectorCount32 & gt; fs- & gt; part- & gt; disc- & gt; partitions[fs- & gt; part- & gt; activePartition].numSectors)sane=0;
}
return(sane);
}
/*****************************************************************************/

/* ****************************************************************************
* void fs_countDataSectors(FileSystem *fs)
* Description: This functions calculates the sectorcounts, fatsectorcounts and
* dataclustercounts. It fills in the general fields.
*/
void fs_countDataSectors(FileSystem *fs)
{
euint32 rootDirSectors,dataSectorCount;

rootDirSectors=((fs- & gt; volumeId.RootEntryCount*32) +
(fs- & gt; volumeId.BytesPerSector - 1)) /
fs- & gt; volumeId.BytesPerSector;

if(fs- & gt; volumeId.FatSectorCount16 != 0)
{
fs- & gt; FatSectorCount=fs- & gt; volumeId.FatSectorCount16;
fs- & gt; volumeId.FatSectorCount32=0;
}
else
{
fs- & gt; FatSectorCount=fs- & gt; volumeId.FatSectorCount32;
fs- & gt; volumeId.FatSectorCount16=0;
}

if(fs- & gt; volumeId.SectorCount16!=0)
{
fs- & gt; SectorCount=fs- & gt; volumeId.SectorCount16;
fs- & gt; volumeId.SectorCount32=0;
}
else
{
fs- & gt; SectorCount=fs- & gt; volumeId.SectorCount32;
fs- & gt; volumeId.SectorCount16=0;
}

dataSectorCount=fs- & gt; SectorCount - (
fs- & gt; volumeId.ReservedSectorCount +
(fs- & gt; volumeId.NumberOfFats * fs- & gt; FatSectorCount) +
rootDirSectors);

fs- & gt; DataClusterCount=dataSectorCount/fs- & gt; volumeId.SectorsPerCluster;
}
/*****************************************************************************/

/* ****************************************************************************
* void fs_determineFatType(FileSystem *fs)
* Description: This function looks af the Dataclustercount and determines the
* FAT type. It fills in fs- & gt; type.
*/
void fs_determineFatType(FileSystem *fs)
{
if(fs- & gt; DataClusterCount & lt; 4085)
{
fs- & gt; type=FAT12;
fs- & gt; volumeId.RootCluster=0;
}
else if(fs- & gt; DataClusterCount & lt; 65525)
{
fs- & gt; type=FAT16;
fs- & gt; volumeId.RootCluster=0;
}
else
{
fs- & gt; type=FAT32;
}
}
/*****************************************************************************/

/* ****************************************************************************
* void fs_findFirstSectorRootDir(FileSystem *fs)
* Description: This functions fills in the fs- & gt; FirstSectorRootDir field, even
* for FAT32, although that is not necessary (because you have FirstClusterRootDir).
*/
void fs_findFirstSectorRootDir(FileSystem *fs)
{
if(fs- & gt; type==FAT32)
fs- & gt; FirstSectorRootDir = fs- & gt; volumeId.ReservedSectorCount +
(fs- & gt; volumeId.NumberOfFats*fs- & gt; volumeId.FatSectorCount32) +
(fs- & gt; volumeId.RootCluster-2)*fs- & gt; volumeId.SectorsPerCluster;
else
fs- & gt; FirstSectorRootDir = fs- & gt; volumeId.ReservedSectorCount +
(fs- & gt; volumeId.NumberOfFats*fs- & gt; volumeId.FatSectorCount16);
}
/*****************************************************************************/

void fs_initCurrentDir(FileSystem *fs)
{
fs- & gt; FirstClusterCurrentDir = fs_getFirstClusterRootDir(fs);
}
/*****************************************************************************/

/* ****************************************************************************
* long fs_clusterToSector(FileSystem *fs,euint32 cluster)
* Description: This function converts a clusternumber in the effective sector
* number where this cluster starts. Boundary check is not implemented
* Return value: A long is returned representing the sectornumber.
*/
euint32 fs_clusterToSector(FileSystem *fs,euint32 cluster)
{
eint32 base;

if(fs- & gt; type==FAT32)
{
base=
fs- & gt; volumeId.ReservedSectorCount+
fs- & gt; FatSectorCount*fs- & gt; volumeId.NumberOfFats;
}
else
{
base=
fs- & gt; volumeId.ReservedSectorCount+
fs- & gt; FatSectorCount*fs- & gt; volumeId.NumberOfFats+
fs- & gt; volumeId.RootEntryCount/16;
}
return( base + (cluster-2)*fs- & gt; volumeId.SectorsPerCluster );
}
/*****************************************************************************/

/* Function is unused, but may be usefull */
euint32 fs_sectorToCluster(FileSystem *fs,euint32 sector)
{
eint32 base;

if(fs- & gt; type==FAT32)
{
base=
fs- & gt; volumeId.ReservedSectorCount+
fs- & gt; FatSectorCount*fs- & gt; volumeId.NumberOfFats;
}
else
{
base=
fs- & gt; volumeId.ReservedSectorCount+
fs- & gt; FatSectorCount*fs- & gt; volumeId.NumberOfFats+
fs- & gt; volumeId.RootEntryCount/16;
}
return(((sector-base)-((sector-base)%fs- & gt; volumeId.SectorsPerCluster))/fs- & gt; volumeId.SectorsPerCluster+2 );
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 fs_getNextFreeCluster(FileSystem *fs,euint32 startingcluster)
* Description: This functions searches for a free cluster, starting it's search at
* cluster startingcluster. This allow to speed up searches and try to avoid
* fragmentation. Implementing rollover search is still to be done.
* Return value: If a free cluster is found it's number is returned. If none is
* found 0 is returned.
*/
euint32 fs_getNextFreeCluster(FileSystem *fs,euint32 startingcluster)
{
euint32 r;

while(startingcluster & lt; fs- & gt; DataClusterCount){
r=fat_getNextClusterAddress(fs,startingcluster,0);
if(r==0){
return(startingcluster);
}
startingcluster++;
}
return(0);
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 fs_giveFreeClusterHint(FileSystem *fs)
*
* Description: This function should return a clusternumber that is free or
* lies close before free clusters. The result MUST be checked to see if
* it is free! Implementationhint: search the largest clusternumber in the
* files in the rootdirectory.
*
* Return value: Returns it's best guess.
*/
euint32 fs_giveFreeClusterHint(FileSystem *fs)
{
return(2); /* Now THIS is a hint ;) */
}
/*****************************************************************************/

/* ****************************************************************************
* esint8 fs_findFile(FileSystem *fs,eint8* filename,FileLocation *loc,euint32 *lastDir)
*
* Description: This function looks if the given filename is on the given fs
* and, if found, fills in its location in loc.
* The function will first check if the pathname starts with a slash. If so it will
* set the starting directory to the rootdirectory. Else, it will take the firstcluster-
* currentdir (That you can change with chdir()) as startingpoint.
* The lastdir pointer will be the first cluster of the last directory fs_findfile
* enters. It starts out at the root/current dir and then traverses the path along with
* fs_findFile.
* It is set to 0 in case of errors (like dir/dir/dir/file/dir/dir...)
* Return value: Returns 0 when nothing was found, 1 when the thing found
* was a file and 2 if the thing found was a directory.
*/

esint8 fs_findFile(FileSystem *fs,eint8* filename,FileLocation *loc,euint32 *lastDir)
{
euint32 fccd,tmpclus;
eint8 ffname[11],*next,it=0,filefound=0;

if(*filename=='/'){
fccd = fs_getFirstClusterRootDir(fs);
filename++;
if(lastDir)*lastDir=fccd;
if(!*filename){
return(2);
}
}else{
fccd = fs- & gt; FirstClusterCurrentDir;
if(lastDir)*lastDir=fccd;
}


while((next=file_normalToFatName(filename,ffname))!=0){
if((tmpclus=dir_findinDir(fs,ffname,fccd,loc,DIRFIND_FILE))==0){
/* We didn't find what we wanted */
/* We should check, to see if there is more after it, so that
* we can invalidate lastDir
*/
if((file_normalToFatName(next,ffname))!=0){
if(lastDir)*lastDir=0;
}
return(0);
}
it++;
if(loc- & gt; attrib & ATTR_DIRECTORY){
fccd = tmpclus;
filename = next;
if(lastDir)*lastDir=fccd;
if(filefound)*lastDir=0;
}else{
filefound=1;
if((file_normalToFatName(next,ffname))!=0){
if(lastDir)*lastDir=0;
return(0);
}else{
filename=next;
}
}
}

if(it==0)return(0);
if(loc- & gt; attrib & ATTR_DIRECTORY || !filefound)return(2);
return(1);
}
/*****************************************************************************/

esint16 fs_findFreeFile(FileSystem *fs,eint8* filename,FileLocation *loc,euint8 mode)
{
euint32 targetdir=0;
eint8 ffname[11];

if(fs_findFile(fs,filename,loc, & targetdir))return(0);
if(!dir_getFatFileName(filename,ffname))return(0);
if(dir_findinDir(fs,ffname,targetdir,loc,DIRFIND_FREE)){
return(1);
}else{
if(dir_addCluster(fs,targetdir)){
return(0);
}else{
if(dir_findinDir(fs,ffname,targetdir,loc,DIRFIND_FREE)){
return(1);
}
}
}

return(0);
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 fs_getLastCluster(FileSystem *fs,ClusterChain *Cache)
* Description: This function searches the last cluster of a chain.
* Return value: The LastCluster (also stored in cache);
*/
euint32 fs_getLastCluster(FileSystem *fs,ClusterChain *Cache)
{
if(Cache- & gt; DiscCluster==0){
Cache- & gt; DiscCluster=Cache- & gt; FirstCluster;
Cache- & gt; LogicCluster=0;
}

if(Cache- & gt; LastCluster==0)
{
while(fat_getNextClusterChain(fs, Cache)==0)
{
Cache- & gt; LogicCluster+=Cache- & gt; Linear;
Cache- & gt; DiscCluster+=Cache- & gt; Linear;
Cache- & gt; Linear=0;
}
}
return(Cache- & gt; LastCluster);
}
/*****************************************************************************/

euint32 fs_getFirstClusterRootDir(FileSystem *fs)
{
switch(fs- & gt; type){
case FAT32:
return(fs- & gt; volumeId.RootCluster);
break;
default:
return(1);
break;
}
}
/*****************************************************************************/

void fs_initClusterChain(FileSystem *fs,ClusterChain *cache,euint32 cluster_addr)
{
cache- & gt; FirstCluster=cluster_addr;
cache- & gt; DiscCluster=cluster_addr;
cache- & gt; LogicCluster=0;
cache- & gt; LastCluster=0; /* Warning flag here */
cache- & gt; Linear=0;
cache- & gt; ClusterCount=0; /* 0 means NOT known */
}
/*****************************************************************************/

void fs_setFirstClusterInDirEntry(FileRecord *rec,euint32 cluster_addr)
{
rec- & gt; FirstClusterHigh=cluster_addr & gt; & gt; 16;
rec- & gt; FirstClusterLow=cluster_addr & 0xFFFF;
}
/*****************************************************************************/

esint8 fs_flushFs(FileSystem *fs)
{
return(part_flushPart(fs- & gt; part,0,fs- & gt; SectorCount));
}
/*****************************************************************************/

esint8 fs_umount(FileSystem *fs)
{
return(fs_flushFs(fs));
}
/*****************************************************************************/

esint8 fs_clearCluster(FileSystem *fs,euint32 cluster)
{
euint16 c;
euint8* buf;

for(c=0;c & lt; (fs- & gt; volumeId.SectorsPerCluster);c++){
buf = part_getSect(fs- & gt; part,fs_clusterToSector(fs,cluster)+c,IOM_MODE_READWRITE);
memClr(buf,512);
part_relSect(fs- & gt; part,buf);
}
return(0);
}

esint8 fs_getFsInfo(FileSystem *fs,euint8 force_update)
{
euint8 *buf;

if(!fs- & gt; type==FAT32)return(0);
buf = part_getSect(fs- & gt; part,FS_INFO_SECTOR,IOM_MODE_READONLY);
if(ex_getb32(buf,0)!=FSINFO_MAGIC_BEGIN || ex_getb32(buf,508)!=FSINFO_MAGIC_END){
part_relSect(fs- & gt; part,buf);
return(-1);
}
fs- & gt; FreeClusterCount = ex_getb32(buf,488);
fs- & gt; NextFreeCluster = ex_getb32(buf,492);
part_relSect(fs- & gt; part,buf);
if(force_update){
fs- & gt; FreeClusterCount=fat_countFreeClusters(fs);
}
return(0);
}

esint8 fs_setFsInfo(FileSystem *fs)
{
euint8* buf;

if(!fs- & gt; type==FAT32)return(0);
buf = part_getSect(fs- & gt; part,FS_INFO_SECTOR,IOM_MODE_READWRITE);
if(ex_getb32(buf,0)!=FSINFO_MAGIC_BEGIN || ex_getb32(buf,508)!=FSINFO_MAGIC_END){
part_relSect(fs- & gt; part,buf);
return(-1);
}
ex_setb32(buf,488,fs- & gt; FreeClusterCount);
ex_setb32(buf,492,fs- & gt; NextFreeCluster);
part_relSect(fs- & gt; part,buf);
return(0);
}


EFSL_SAM7_example.rar > ls.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : ls.c *
* Description : This file contains functions to list the files in a directory *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/

/*****************************************************************************/
#include " ls.h "
/*****************************************************************************/

esint8 ls_openDir(DirList *dlist,FileSystem *fs,eint8* dirname)
{
FileLocation loc;
euint32 fc;

dlist- & gt; fs=fs;

if(fs_findFile(dlist- & gt; fs,dirname, & loc, & fc)!=2)
{
return(-1);
}

fs_initClusterChain(dlist- & gt; fs, & (dlist- & gt; Cache),fc);
memClr( & (dlist- & gt; currentEntry),sizeof(dlist- & gt; currentEntry));
dlist- & gt; rEntry=0;
dlist- & gt; cEntry=0xFFFF;

return(0);
}
/*****************************************************************************/

esint8 ls_getDirEntry(DirList *dlist)
{
if(dlist- & gt; Cache.FirstCluster == 1){
return(ls_getRootAreaEntry(dlist));
}else if(dlist- & gt; Cache.FirstCluster){
return(ls_getRealDirEntry(dlist));
}
return(-1);
}
/*****************************************************************************/

esint8 ls_getNext(DirList *dlist)
{
do{
if(ls_getDirEntry(dlist))return(-1);
dlist- & gt; rEntry++;
}while(!ls_isValidFileEntry( & (dlist- & gt; currentEntry)));
dlist- & gt; cEntry++;
return(0);
}
/*****************************************************************************/

esint8 ls_getRealDirEntry(DirList *dlist)
{
euint8* buf;

if(dlist- & gt; Cache.FirstCluster & lt; =1)return(-1);

if(fat_LogicToDiscCluster(dlist- & gt; fs,
& (dlist- & gt; Cache),
(dlist- & gt; rEntry)/(16 * dlist- & gt; fs- & gt; volumeId.SectorsPerCluster))){
return(-1);
}

buf = part_getSect(dlist- & gt; fs- & gt; part,
fs_clusterToSector(dlist- & gt; fs,dlist- & gt; Cache.DiscCluster) + (dlist- & gt; rEntry/16)%dlist- & gt; fs- & gt; volumeId.SectorsPerCluster,
IOM_MODE_READONLY);

/*memCpy(buf+(dlist- & gt; rEntry%16)*32, & (dlist- & gt; currentEntry),32);*/
ls_fileEntryToDirListEntry(dlist,buf,32*(dlist- & gt; rEntry%16));

part_relSect(dlist- & gt; fs- & gt; part,buf);

return(0);
}
/*****************************************************************************/

esint8 ls_getRootAreaEntry(DirList *dlist)
{
euint8 *buf=0;

if((dlist- & gt; fs- & gt; type != FAT12) & & (dlist- & gt; fs- & gt; type != FAT16))return(-1);
if(dlist- & gt; rEntry & gt; =dlist- & gt; fs- & gt; volumeId.RootEntryCount)return(-1);

buf = part_getSect(dlist- & gt; fs- & gt; part,
dlist- & gt; fs- & gt; FirstSectorRootDir+dlist- & gt; rEntry/16,
IOM_MODE_READONLY);
/*memCpy(buf+32*(dlist- & gt; rEntry%16), & (dlist- & gt; currentEntry),32);*/
ls_fileEntryToDirListEntry(dlist,buf,32*(dlist- & gt; rEntry%16));
part_relSect(dlist- & gt; fs- & gt; part,buf);
return(0);
}
/*****************************************************************************/

esint8 ls_isValidFileEntry(ListDirEntry *entry)
{
if(entry- & gt; FileName[0] == 0 || entry- & gt; FileName[0] == 0xE5 || entry- & gt; FileName[0] == '.')return(0);
if((entry- & gt; Attribute & 0x0F)==0x0F)return(0);
return(1);
}
/*****************************************************************************/

void ls_fileEntryToDirListEntry(DirList *dlist, euint8* buf, euint16 offset)
{
if(offset & gt; 480 || offset%32)return;

buf+=offset;
memCpy(buf+OFFSET_DE_FILENAME,dlist- & gt; currentEntry.FileName,LIST_MAXLENFILENAME);
dlist- & gt; currentEntry.Attribute = *(buf+OFFSET_DE_ATTRIBUTE);
dlist- & gt; currentEntry.FileSize = ex_getb32(buf,OFFSET_DE_FILESIZE);
}
/*****************************************************************************/


EFSL_SAM7_example.rar > ioman_v2.c

/*****************************************************************************\
* libfat - General purpose FAT library *
* ---------------------------------- *
* *
* Filename : ioman.c *
* Description : The IO Manager receives all requests for sectors in a central *
* allowing it to make smart decision regarding caching. *
* The IOMAN_NUMBUFFER parameter determines how many sectors *
* ioman can cache. ioman also supports overallocating and *
* backtracking sectors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/

/*****************************************************************************/
#include " ioman_v2.h "
/*****************************************************************************/

esint8 ioman_init(IOManager *ioman, hwInterface *iface, euint8* bufferarea)
{
ioman- & gt; iface=iface;

ioman- & gt; bufptr = ioman_getBuffer(ioman,bufferarea);
ioman- & gt; numbuf = IOMAN_NUMBUFFER;
ioman- & gt; numit = IOMAN_NUMITERATIONS;

ioman_reset(ioman);
return(0);
}

void ioman_reset(IOManager *ioman)
{
euint16 nb,ni;

memClr(ioman- & gt; sector,sizeof(euint32)*ioman- & gt; numbuf);
memClr(ioman- & gt; status,sizeof(euint8) *ioman- & gt; numbuf);
memClr(ioman- & gt; usage ,sizeof(euint8) *ioman- & gt; numbuf);
memClr(ioman- & gt; itptr ,sizeof(euint8) *ioman- & gt; numbuf);

for(nb=0;nb & lt; ioman- & gt; numbuf;nb++){
for(ni=0;ni & lt; ioman- & gt; numit;ni++){
ioman- & gt; stack[nb][ni].sector=0;
ioman- & gt; stack[nb][ni].status=0;
ioman- & gt; stack[nb][ni].usage =0;
}
}
}

euint8* ioman_getBuffer(IOManager *ioman,euint8* bufferarea)
{
static euint8 buf[512 * IOMAN_NUMBUFFER];
return(buf);
}

void ioman_setAttr(IOManager *ioman,euint16 bufplace,euint8 attribute,euint8 val)
{
if(bufplace & gt; =ioman- & gt; numbuf)return; /* Out of bounds */

if(val){
ioman- & gt; status[bufplace]|=1 & lt; & lt; attribute;
}else{
ioman- & gt; status[bufplace] & =~(1 & lt; & lt; attribute);
}
}

euint8 ioman_getAttr(IOManager *ioman,euint16 bufplace,euint8 attribute)
{
if(bufplace & gt; =ioman- & gt; numbuf)
return(0xFF); /* Out of bounds */

return(ioman- & gt; status[bufplace] & (1 & lt; & lt; attribute));
}

euint8 ioman_getUseCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return(0x00);
return(ioman- & gt; usage[bufplace]);
}

void ioman_incUseCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return;
if(ioman- & gt; usage[bufplace]==0xFF)return;
else ioman- & gt; usage[bufplace]++;
}

void ioman_decUseCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return;
if(ioman- & gt; usage[bufplace]==0x0)return;
else ioman- & gt; usage[bufplace]--;
}

void ioman_resetUseCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return;
ioman- & gt; usage[bufplace]=0x00;
}

euint8 ioman_getRefCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return(0x00);
return(ioman- & gt; reference[bufplace]);
}

void ioman_incRefCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return;
if(ioman- & gt; reference[bufplace]==0xFF)return;
else ioman- & gt; reference[bufplace]++;
}

void ioman_decRefCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return;
if(ioman- & gt; reference[bufplace]==0x00)return;
else ioman- & gt; reference[bufplace]--;
}

void ioman_resetRefCnt(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return;
ioman- & gt; reference[bufplace]=0x00;
}

esint8 ioman_pop(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return(-1);
if(ioman- & gt; itptr[bufplace]==0 || ioman- & gt; itptr[bufplace] & gt; IOMAN_NUMITERATIONS)return(-1);
ioman- & gt; sector[bufplace] = ioman- & gt; stack[bufplace][ioman- & gt; itptr[bufplace]].sector;
ioman- & gt; status[bufplace] = ioman- & gt; stack[bufplace][ioman- & gt; itptr[bufplace]].status;
ioman- & gt; usage[bufplace] = ioman- & gt; stack[bufplace][ioman- & gt; itptr[bufplace]].usage;
ioman- & gt; itptr[bufplace]--;
return(0);
}

esint8 ioman_push(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return(-1);
if(ioman- & gt; itptr[bufplace] & gt; =IOMAN_NUMITERATIONS)return(-1);
ioman- & gt; itptr[bufplace]++;
ioman- & gt; stack[bufplace][ioman- & gt; itptr[bufplace]].sector = ioman- & gt; sector[bufplace];
ioman- & gt; stack[bufplace][ioman- & gt; itptr[bufplace]].status = ioman- & gt; status[bufplace];
ioman- & gt; stack[bufplace][ioman- & gt; itptr[bufplace]].usage = ioman- & gt; usage[bufplace];
return(0);
}

euint8* ioman_getPtr(IOManager *ioman,euint16 bufplace)
{
if(bufplace & gt; =ioman- & gt; numbuf)return(0);
return(ioman- & gt; bufptr+bufplace*512);
}

esint16 ioman_getBp(IOManager *ioman,euint8* buf)
{
if(buf & lt; (ioman- & gt; bufptr) || buf & gt; =( ioman- & gt; bufptr+(ioman- & gt; numbuf*512) )){
return(-1);
}
return((buf-(ioman- & gt; bufptr))/512);
}

esint8 ioman_readSector(IOManager *ioman,euint32 address,euint8* buf)
{
esint8 r;

/*DBG((TXT( " ioman_readSector::Requesting address %u to be put in %p.\n " ),address,buf));*/
if(buf==0){
/*DBG((TXT( " Refused to read sector, buf=0\n " )));*/
return(-1);
}

r=if_readBuf(ioman- & gt; iface,address,buf);

if(r!=0){
return(-1);
}
return(0);
}

esint8 ioman_writeSector(IOManager *ioman, euint32 address, euint8* buf)
{
esint8 r;

if(buf==0)return(-1);

r=if_writeBuf(ioman- & gt; iface,address,buf);

if(r & lt; =0){
return(-1);
}
return(0);
}

void ioman_resetCacheItem(IOManager *ioman,euint16 bufplace)
{
ioman- & gt; sector[bufplace] = 0;
ioman- & gt; status[bufplace] = 0;
ioman- & gt; usage[bufplace] = 0;
ioman- & gt; reference[bufplace] = 0;
}

esint32 ioman_findSectorInCache(IOManager *ioman, euint32 address)
{
euint16 c;

for(c=0;c & lt; ioman- & gt; numbuf;c++){
if(ioman_isValid(c) & & ioman- & gt; sector[c] == address)return(c);
}
return(-1);
}

esint32 ioman_findFreeSpot(IOManager *ioman)
{
euint16 c;

for(c=0;c & lt; ioman- & gt; numbuf;c++){
if(!ioman_isValid(c))return(c);
}
return(-1);
}

esint32 ioman_findUnusedSpot(IOManager *ioman)
{
esint32 r=-1;
euint16 c;
euint8 fr=0,lr=0xFF;

for(c=0;c & lt; ioman- & gt; numbuf;c++){
if(ioman_getUseCnt(ioman,c)==0){
if(!ioman_isWritable(c) & & !fr){
fr=1;
lr=0xFF;
r=-1;
}
if(ioman_isWritable(c) & & !fr){
if(ioman_getRefCnt(ioman,c) & lt; =lr){
r=c;
lr=ioman_getRefCnt(ioman,c);
}
}
if(fr & & !ioman_isWritable(c)){
if(ioman_getRefCnt(ioman,c) & lt; =lr){
r=c;
lr=ioman_getRefCnt(ioman,c);
}
}
}
}
return(r);
}

esint32 ioman_findOverallocableSpot(IOManager *ioman)
{
euint8 points,lp=0xFF;
euint16 c;
esint32 r=-1;

for(c=0;c & lt; ioman- & gt; numbuf;c++){
if(ioman- & gt; itptr[c] & lt; ioman- & gt; numit){
points = 0;
if(ioman_isWritable(c))points+=0x7F;
points += ((euint16)(ioman- & gt; itptr[c]*0x4D))/(ioman- & gt; numit);
points += ((euint16)(ioman_getRefCnt(ioman,c)*0x33))/0xFF;
if(points & lt; lp){
lp=points;
r=c;
}
}
}
return(r);
}

esint8 ioman_putSectorInCache(IOManager *ioman, euint32 address, euint16 bufplace)
{
euint8* buf;

if((buf = ioman_getPtr(ioman,bufplace))==0)return(-1);
if((ioman_readSector(ioman,address,buf)))return(-1);
ioman_setValid(bufplace);
ioman- & gt; sector[bufplace]=address;
return(0);
}

esint8 ioman_flushSector(IOManager *ioman, euint16 bufplace)
{
euint8* buf;

if((buf = ioman_getPtr(ioman,bufplace))==0)return(-1);
if(!ioman_isWritable(bufplace))return(-1);
if(!(ioman_writeSector(ioman,ioman- & gt; sector[bufplace],buf)))return(-1);
return(0);
}

euint8* ioman_getSector(IOManager *ioman,euint32 address, euint8 mode)
{
esint32 bp;

if((bp=ioman_findSectorInCache(ioman,address))!=-1){
if(mode==IOM_MODE_READWRITE){
ioman_setWritable(bp);
}
ioman_incUseCnt(ioman,bp);
ioman_incRefCnt(ioman,bp);
return(ioman_getPtr(ioman,bp));
}

if((bp=ioman_findFreeSpot(ioman))==-1){
if(((bp=ioman_findUnusedSpot(ioman))!=-1) & & (ioman_isWritable(bp))){
ioman_flushSector(ioman,bp);
}
}

if(bp!=-1){
ioman_resetCacheItem(ioman,bp);
if((ioman_putSectorInCache(ioman,address,bp))){
return(0);
}
if(mode==IOM_MODE_READWRITE){
ioman_setWritable(bp);
}
ioman_incUseCnt(ioman,bp);
ioman_incRefCnt(ioman,bp);
return(ioman_getPtr(ioman,bp));
}

if((bp=ioman_findOverallocableSpot(ioman))!=-1){
if(ioman_isWritable(bp)){
ioman_flushSector(ioman,bp);
}
if(ioman_push(ioman,bp)){
return(0);
}
ioman_resetCacheItem(ioman,bp);
if((ioman_putSectorInCache(ioman,address,bp))){
return(0);
}
if(mode==IOM_MODE_READWRITE){
ioman_setWritable(bp);
}
ioman_incUseCnt(ioman,bp);
ioman_incRefCnt(ioman,bp);
return(ioman_getPtr(ioman,bp));
}
return(0);
}

esint8 ioman_releaseSector(IOManager *ioman,euint8* buf)
{
euint16 bp;

bp=ioman_getBp(ioman,buf);
ioman_decUseCnt(ioman,bp);

if(ioman_getUseCnt(ioman,bp)==0 & & ioman- & gt; itptr!=0){
if(ioman_isWritable(bp)){
ioman_flushSector(ioman,bp);
}
ioman_pop(ioman,bp);
ioman_putSectorInCache(ioman,ioman- & gt; sector[bp],bp);
}
return(0);
}


void ioman_printStatus(IOManager *ioman)
{
euint16 c;

DBG((TXT( " IO-Manager -- Report\n====================\n\n " )));
DBG((TXT( " Buffer is %i sectors, from %p to %p\n " ),
ioman- & gt; numbuf,ioman- & gt; bufptr,ioman- & gt; bufptr+(ioman- & gt; numbuf*512)));
for(c=0;c & lt; ioman- & gt; numbuf;c++){
if(ioman_isValid(c)){
DBG((TXT( " BP %3i\t SC %i\t\t US %i\t RF %i\t %s %s\n " ),
c,ioman- & gt; sector[c],ioman_getUseCnt(ioman,c),ioman_getRefCnt(ioman,c),
ioman_isUserBuf(c) ? " USRBUF " : " " ,
ioman_isWritable(c) ? " WRITABLE " : " READONLY " ));
}
}
}


EFSL_SAM7_example.rar > at91_spi.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------------------------------------------- *
* *
* Filename : at91_spi.c *
* Description : This file contains the functions needed to use efs for *
* accessing files on an SD-card connected to an AT91(SAM7) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Martin Thomas *
\*****************************************************************************/

/*
TODO:
- Driver uses simple mode - & gt; implement " DMA "
- use 16-bit mode
- check CPOL
*/

/*****************************************************************************/
#include " AT91SAM7S_regs.h "
#include " config.h "
#include " arm_spi.h "
#include " sd.h "
/*****************************************************************************/

/* Define the following to enable fixed peripheral chip-select.
This is not a config.h-value since variable peripheral select
is prefered so other devices can be attached to the AT91 SPI-interface. */
/* #define FIXED_PERIPH */

/*
AT91SAM7S64 SPI Pins: Function (A/B)
PA12 - MISO - AT91C_PA12_MISO (1/0)
PA13 - MOSI - AT91C_PA13_MOSI (1/0)
PA14 - SCK - AT91C_PA14_SPCK (1/0)

Chip-Selects (available on different pins)
PA11 - NPCS0 - AT91C_PA11_NPCS0 (1/0)
PA31 - NPCS1 - AT91C_PA31_NPCS1 (1/0)
PA09 - NPCS1 - AT91C_PA9_NPCS1 (1/0)
...AT91C_PA3_NPCS3 (0/1)
...AT91C_PA5_NPCS3 (0/1)
...AT91C_PA10_NPCS2 (0/1)
...AT91C_PA22_NPCS3 (0/1)
...AT91C_PA30_NPCS2 (0/1)
*/

/* here: use NCPS0 @ PA11: */
#define NCPS_PDR_BIT AT91C_PA11_NPCS0
#define NCPS_ASR_BIT AT91C_PA11_NPCS0
#define NPCS_BSR_BIT 0
#define SPI_CSR_NUM 0

/* PCS_0 for NPCS0, PCS_1 for NPCS1 ... */
#define PCS_0 ((0 & lt; & lt; 0)|(1 & lt; & lt; 1)|(1 & lt; & lt; 2)|(1 & lt; & lt; 3))
#define PCS_1 ((1 & lt; & lt; 1)|(0 & lt; & lt; 1)|(1 & lt; & lt; 2)|(1 & lt; & lt; 3))
#define PCS_2 ((1 & lt; & lt; 1)|(1 & lt; & lt; 1)|(0 & lt; & lt; 2)|(1 & lt; & lt; 3))
#define PCS_3 ((1 & lt; & lt; 1)|(1 & lt; & lt; 1)|(1 & lt; & lt; 2)|(0 & lt; & lt; 3))
/* TODO: ## */
#if (SPI_CSR_NUM == 0)
#define SPI_MR_PCS PCS_0
#elif (SPI_CSR_NUM == 1)
#define SPI_MR_PCS PCS_1
#elif (SPI_CSR_NUM == 2)
#define SPI_MR_PCS PCS_2
#elif (SPI_CSR_NUM == 3)
#define SPI_MR_PCS PCS_3
#else
#error " SPI_CSR_NUM invalid "
// not realy - when using an external address decoder...
// but this code takes over the complete SPI-interace anyway
#endif

/* in variable periph. select PSDEC=1 is used
so the already defined values for SPC_MR_PCS can be
reused */
#define SPI_TDR_PCS SPI_MR_PCS

/* SPI prescaler lower limit (the smaller the faster) */
#define SPI_SCBR_MIN 2


esint8 if_initInterface(hwInterface* file, eint8* opts)
{
euint32 sc;

if_spiInit(file);

if(sd_Init(file) & lt; 0) {
DBG((TXT( " Card failed to init, breaking up...\n " )));
return(-1);
}

if(sd_State(file) & lt; 0){
DBG((TXT( " Card didn't return the ready state, breaking up...\n " )));
return(-2);
}

/* file- & gt; sectorCount=4; */ /* FIXME ASAP!! */
/* mthomas: - somehow done - see below */

sd_getDriveSize(file, & sc);
file- & gt; sectorCount = sc/512;
if( (sc%512) != 0) {
file- & gt; sectorCount--;
}
DBG((TXT( " Card Capacity is %lu Bytes (%lu Sectors)\n " ), sc, file- & gt; sectorCount));

if_spiSetSpeed(SPI_SCBR_MIN);
// if_spiSetSpeed(100); /* debug - slower */

return(0);
}

/*****************************************************************************/
/* parts of this function inspired by a spi example found at olimex.com
not much (nothing?) left from the olimex-code (since too many hardcoded values)
*/
void if_spiInit(hwInterface *iface)
{
euint8 i;

AT91PS_SPI pSPI = AT91C_BASE_SPI;
AT91PS_PIO pPIOA = AT91C_BASE_PIOA;
AT91PS_PMC pPMC = AT91C_BASE_PMC;
// not used: AT91PS_PDC pPDC_SPI = AT91C_BASE_PDC_SPI;

// disable PIO from controlling MOSI, MISO, SCK (=hand over to SPI)
// keep CS untouched - used as GPIO pin during init
pPIOA- & gt; PIO_PDR = AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK; // | NCPS_PDR_BIT;
// set pin-functions in PIO Controller
pPIOA- & gt; PIO_ASR = AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK; /// not here: | NCPS_ASR_BIT;
/// not here: pPIOA- & gt; PIO_BSR = NPCS_BSR_BIT;

// set chip-select as output high (unselect card)
pPIOA- & gt; PIO_PER = NCPS_PDR_BIT; // enable GPIO of CS-pin
pPIOA- & gt; PIO_SODR = NCPS_PDR_BIT; // set high
pPIOA- & gt; PIO_OER = NCPS_PDR_BIT; // output enable

// enable peripheral clock for SPI ( PID Bit 5 )
pPMC- & gt; PMC_PCER = ( (euint32) 1 & lt; & lt; AT91C_ID_SPI ); // n.b. IDs are just bit-numbers

// SPI enable and reset
pSPI- & gt; SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_SWRST;

#ifdef FIXED_PERIPH
// SPI mode: master, fixed periph. sel., FDIV=0, fault detection disabled
pSPI- & gt; SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | AT91C_SPI_MODFDIS;
// set PCS for fixed select
// pSPI- & gt; SPI_MR & = 0xFFF0FFFF; // clear old PCS - redundant (AT91lib)
pSPI- & gt; SPI_MR |= ( (SPI_MR_PCS & lt; & lt; 16) & AT91C_SPI_PCS ); // set PCS
#else
// SPI mode: master, variable periph. sel., FDIV=0, fault detection disabled
// Chip-Select-Decoder Mode (write state of CS-Lines in TDR)
pSPI- & gt; SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCSDEC ;
#endif

// set chip-select-register
// 8 bits per transfer, CPOL=1, ClockPhase=0, DLYBCT = 0
// TODO: Why has CPOL to be active here and non-active on LPC2000?
// Take closer look on timing diagrams in datasheets.
// not working pSPI- & gt; SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | AT91C_SPI_NCPHA;
// not working pSPI- & gt; SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_BITS_8 | AT91C_SPI_NCPHA;
pSPI- & gt; SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8;
// not working pSPI- & gt; SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_BITS_8;

// slow during init
if_spiSetSpeed(0xFE);

// enable
pSPI- & gt; SPI_CR = AT91C_SPI_SPIEN;

#if 0
// a PDC-init has been in the Olimex-code - not needed since
// the PDC is not used by this version of the interface
// (Olimex did not use PDC either)
// enable PDC transmit and receive in " PERIPH_PTCR " (SPI_PTCR)
pPDC_SPI- & gt; PDC_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
pSPI- & gt; SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
#endif

/* Send 20 spi commands with card not selected */
for(i=0;i & lt; 21;i++) {
if_spiSend(iface,0xFF);
}

/* enable automatic chip-select */
// reset PIO-registers of CS-pin to default
pPIOA- & gt; PIO_ODR = NCPS_PDR_BIT; // input
pPIOA- & gt; PIO_CODR = NCPS_PDR_BIT; // clear
// disable PIO from controlling the CS pin (=hand over to SPI)
pPIOA- & gt; PIO_PDR = NCPS_PDR_BIT;
// set pin-functions in PIO Controller (function NCPS for CS-pin)
pPIOA- & gt; PIO_ASR = NCPS_ASR_BIT;
pPIOA- & gt; PIO_BSR = NPCS_BSR_BIT;
}
/*****************************************************************************/

void if_spiSetSpeed(euint8 speed)
{
euint32 reg;
AT91PS_SPI pSPI = AT91C_BASE_SPI;

if ( speed & lt; SPI_SCBR_MIN ) speed = SPI_SCBR_MIN;
if ( speed & gt; 1 ) speed & = 0xFE;

reg = pSPI- & gt; SPI_CSR[SPI_CSR_NUM];
reg = ( reg & ~(AT91C_SPI_SCBR) ) | ( (euint32)speed & lt; & lt; 8 );
pSPI- & gt; SPI_CSR[SPI_CSR_NUM] = reg;
}
/*****************************************************************************/

euint8 if_spiSend(hwInterface *iface, euint8 outgoing)
{
euint8 incoming;

AT91PS_SPI pSPI = AT91C_BASE_SPI;

while( !( pSPI- & gt; SPI_SR & AT91C_SPI_TDRE ) ); // transfer compl. wait
#ifdef FIXED_PERIPH
pSPI- & gt; SPI_TDR = (euint16)( outgoing );
#else
pSPI- & gt; SPI_TDR = ( (euint16)(outgoing) | ((euint32)(SPI_TDR_PCS) & lt; & lt; 16) );
#endif

while( !( pSPI- & gt; SPI_SR & AT91C_SPI_RDRF ) ); // wait for char
incoming = (euint8)( pSPI- & gt; SPI_RDR );

return incoming;
}
/*****************************************************************************/

esint8 if_readBuf(hwInterface* file,euint32 address,euint8* buf)
{
return(sd_readSector(file,address,buf,512));
}
/*****************************************************************************/

esint8 if_writeBuf(hwInterface* file, euint32 address, euint8* buf)
{
return( sd_writeSector(file, address, buf) );
}
/*****************************************************************************/

esint8 if_setPos(hwInterface* file,euint32 address)
{
return(0);
}
/*****************************************************************************/


EFSL_SAM7_example.rar > extract.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : extract.c *
* Description : This file contains functions to copy structures that get *
* corrupted when using direct memory copy *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
*
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/

/*****************************************************************************/
#include " extract.h "
/*****************************************************************************/

/*****************************************************************************/
#ifdef BYTE_ALIGNMENT
/*****************************************************************************/

euint16 ex_getb16(euint8* buf,euint32 offset)
{
return(ltb_end16(*((euint16*)(buf+offset))));
}
/*****************************************************************************/

euint32 ex_getb32(euint8* buf,euint32 offset)
{
return(ltb_end32(*((euint32*)(buf+offset))));
}
/*****************************************************************************/

void ex_setb16(euint8* buf,euint32 offset,euint16 data)
{
*((euint16*)(buf+offset)) = btl_end16(data);
}
/*****************************************************************************/

void ex_setb32(euint8* buf,euint32 offset,euint32 data)
{
*((euint32*)(buf+offset)) = btl_end32(data);
}
/*****************************************************************************/

void ex_getPartitionField(euint8* buf,PartitionField* pf, euint32 offset)
{
*pf=*((PartitionField*)(buf+offset));
}
/*****************************************************************************/

void ex_setPartitionField(euint8* buf,PartitionField* pf, euint32 offset)
{

}
/*****************************************************************************/




/*****************************************************************************/
/*****************************************************************************/
#else
/*****************************************************************************/
/*****************************************************************************/

#if 0

euint16 ex_getb16(euint8* buf,euint32 offset)
{
return(ltb_end16(((*(buf+offset+1)) & lt; & lt; 8) + ((*(buf+offset+0)) & lt; & lt; 0)));
}

euint32 ex_getb32(euint8* buf,euint32 offset)
{
return(ltb_end32(((euint32)buf[offset+3] & lt; & lt; 24)+
((euint32)buf[offset+2] & lt; & lt; 16)+
((euint32)buf[offset+1] & lt; & lt; 8)+
((euint32)buf[offset+0] & lt; & lt; 0)));
}

#else
//#warning " mthomas - modification enabled "

euint32 ex_getb32(euint8* buf,euint32 offset)
{
#ifdef BIG_ENDIAN
return ((euint32)*(euint8*)(buf+offset) & lt; & lt; 24UL) |
((euint32)*(euint8*)(buf+offset+1) & lt; & lt; 16UL) |
((euint16)*(euint8*)(buf+offset+2) & lt; & lt; 8UL) |
(*(euint8*)(buf+offset+3)) ;
#else
return ((euint32)*(euint8*)(buf+offset+3) & lt; & lt; 24UL) |
((euint32)*(euint8*)(buf+offset+2) & lt; & lt; 16UL) |
((euint16)*(euint8*)(buf+offset+1) & lt; & lt; 8UL) |
(*(euint8*)(buf+offset)) ;
#endif
}

euint16 ex_getb16(euint8* buf,euint32 offset)
{
#ifdef BIG_ENDIAN
return ((euint16)*(euint8*)(buf+offset) & lt; & lt; 8UL) |
(*(euint8*)(buf+offset+1)) ;
#else
return ((euint16)*(euint8*)(buf+offset+1) & lt; & lt; 8UL) |
(*(euint8*)(buf+offset)) ;
#endif
}

#endif
/* end mod mthomas */


/*****************************************************************************/

void ex_setb16(euint8* buf,euint32 offset,euint16 data)
{
#ifdef BIG_ENDIAN
*(buf+offset+1) = data & gt; & gt; 0;
*(buf+offset+0) = data & gt; & gt; 8;
#else
*(buf+offset+0) = data & gt; & gt; 0;
*(buf+offset+1) = data & gt; & gt; 8;
#endif
}
/*****************************************************************************/

void ex_setb32(euint8* buf,euint32 offset,euint32 data)
{
#ifdef BIG_ENDIAN
*(buf+offset+3) = data & gt; & gt; 0;
*(buf+offset+2) = data & gt; & gt; 8;
*(buf+offset+1) = data & gt; & gt; 16;
*(buf+offset+0) = data & gt; & gt; 24;
#else
*(buf+offset+0) = data & gt; & gt; 0;
*(buf+offset+1) = data & gt; & gt; 8;
*(buf+offset+2) = data & gt; & gt; 16;
*(buf+offset+3) = data & gt; & gt; 24;
#endif
}
/*****************************************************************************/

void ex_getPartitionField(euint8* buf,PartitionField* pf, euint32 offset)
{
pf- & gt; bootFlag = *(buf + offset);
pf- & gt; CHS_begin[0] = *(buf + offset + 1);
pf- & gt; CHS_begin[1] = *(buf + offset + 2);
pf- & gt; CHS_begin[2] = *(buf + offset + 3);
pf- & gt; type = *(buf + offset + 4);
pf- & gt; CHS_end[0] = *(buf + offset + 5);
pf- & gt; CHS_end[1] = *(buf + offset + 6);
pf- & gt; CHS_end[2] = *(buf + offset + 7);
pf- & gt; LBA_begin = ex_getb32(buf + offset,8);
pf- & gt; numSectors = ex_getb32(buf + offset,12);
}
/*****************************************************************************/

void ex_setPartitionField(euint8* buf,PartitionField* pf, euint32 offset)
{

}
/*****************************************************************************/



/*****************************************************************************/
#endif
/*****************************************************************************/


EFSL_SAM7_example.rar > fat.c

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : fat.c *
* Description : This file contains all the functions dealing with the FAT *
* in a Microsoft FAT filesystem. It belongs under fs.c *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; version 2 *
* of the License. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or *
* use macros or inline functions from this file, or you compile this *
* file and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with section (3) of *
* the GNU General Public License. *
* *
* This exception does not invalidate any other reasons why a work based *
* on this file might be covered by the GNU General Public License. *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
* *
* mthomas: testing aligments *
\*****************************************************************************/

/*****************************************************************************/
#include " fs.h "
#include " fat.h "
/*****************************************************************************/


#define MT_MOD
#ifdef MT_MOD
//#warning " mthomas alignment tests "
#endif

/* ****************************************************************************
* unsigned long fat_getSectorAddressFatEntry(FileSystem *fs,unsigned long cluster_addr)
* Description: Returns the sectornumber that holds the fat entry for cluster cluster_addr.
* This works for all FAT types.
* Return value: Sectornumber, or 0. Warning, no boundary check.
*/
euint32 fat_getSectorAddressFatEntry(FileSystem *fs,euint32 cluster_addr)
{
euint32 base = fs- & gt; volumeId.ReservedSectorCount,res;

switch(fs- & gt; type){
case FAT12:
res=(cluster_addr*3/1024);
if(res & gt; =fs- & gt; FatSectorCount){
return(0);
}else{
return(base+res);
}
break;
case FAT16:
res=cluster_addr/256;
if(res & gt; =fs- & gt; FatSectorCount){
return(0);
}else{
return(base+res);
}
break;
case FAT32:
res=cluster_addr/128;
if(res & gt; =fs- & gt; FatSectorCount){
return(0);
}else{
return(base+res);
}
break;
}
return(0);
}
/*****************************************************************************/


/* ****************************************************************************
* unsigned long fat_getNextClusterAddress(FileSystem *fs,unsigned long cluster_addr
* Description: This function loads the sector of the fat which contains the entry
* for cluster_addr. It then fetches and (if required) calculates it's value.
* This value is the EoC marker -or- the number of the next cluster in the chain.
* Return value: Clusternumber or EoC
*/
euint32 fat_getNextClusterAddress(FileSystem *fs,euint32 cluster_addr,euint16 *linear)
{
euint8 *buf;
euint8 hb,lb;
euint16 offset;
euint32 sector;
euint32 nextcluster=0;

sector=fat_getSectorAddressFatEntry(fs,cluster_addr);
if( (fs- & gt; FatSectorCount & lt; = (sector-fs- & gt; volumeId.ReservedSectorCount)) || sector==0 )
{
return(0);
}

buf=part_getSect(fs- & gt; part,sector,IOM_MODE_READONLY);

switch(fs- & gt; type)
{
case FAT12:
offset = ((cluster_addr%1024)*3/2)%512;
hb = buf[offset];
if(offset == 511){
part_relSect(fs- & gt; part,buf);
buf=part_getSect(fs- & gt; part,sector+1,IOM_MODE_READONLY);
lb = buf[0];
}else{
lb = buf[offset + 1];
}
if(cluster_addr%2==0){
nextcluster = ( ((lb & 0x0F) & lt; & lt; 8) + (hb) );
}else{
nextcluster = ( (lb & lt; & lt; 4) + (hb & gt; & gt; 4) );
}
break;
case FAT16:
offset=cluster_addr%256;
#ifndef MT_MOD
nextcluster = *((euint16 *)buf + offset);
#else
nextcluster = ex_getb16( buf, offset*sizeof(euint16) );
#endif
break;
case FAT32:
offset=cluster_addr%128;
#ifndef MT_MOD
nextcluster = *((euint32 *)buf + offset);
#else
nextcluster = ex_getb32( buf, offset*sizeof(euint32) );
#endif
break;
}

part_relSect(fs- & gt; part,buf);

return(nextcluster);
}
/*****************************************************************************/


/* ****************************************************************************
* void fat_setNextClusterAddress(FileSystem *fs,unsigned long cluster_addr,unsigned long next_cluster_addr)
* Description: This function makes an entry in the fattable for cluster_addr. The value it puts there
* is next_cluster_addr.
*/
void fat_setNextClusterAddress(FileSystem *fs,euint32 cluster_addr,euint32 next_cluster_addr)
{
euint8 *buf,*buf2;
euint16 offset;
euint32 sector;

sector=fat_getSectorAddressFatEntry(fs,cluster_addr);
if(( fs- & gt; FatSectorCount & lt; = (sector - fs- & gt; volumeId.ReservedSectorCount )||(sector==0))){
DBG((TXT( " HARDERROR:::fat_getNextClusterAddress READ PAST FAT BOUNDARY\n " )));
return;
}

buf=part_getSect(fs- & gt; part,sector,IOM_MODE_READWRITE);

switch(fs- & gt; type){
case FAT12:
offset = ((cluster_addr%1024)*3/2)%512;
if(offset == 511){
if(cluster_addr%2==0){
buf[offset]=next_cluster_addr & 0xFF;
}else{
buf[offset]=(buf[offset] & 0xF)+((next_cluster_addr & lt; & lt; 4) & 0xF0);
}
buf2=part_getSect(fs- & gt; part,fat_getSectorAddressFatEntry(fs,cluster_addr)+1,IOM_MODE_READWRITE);
if(cluster_addr%2==0){
buf2[0]=(buf2[0] & 0xF0)+((next_cluster_addr & gt; & gt; 8) & 0xF);
}else{
buf2[0]=(next_cluster_addr & gt; & gt; 4) & 0xFF;
}
part_relSect(fs- & gt; part,buf2);
}else{
if(cluster_addr%2==0){
buf[offset]=next_cluster_addr & 0xFF;
buf[offset+1]=(buf[offset+1] & 0xF0)+((next_cluster_addr & gt; & gt; 8) & 0xF);
}else{
buf[offset]=(buf[offset] & 0xF)+((next_cluster_addr & lt; & lt; 4) & 0xF0);
buf[offset+1]=(next_cluster_addr & gt; & gt; 4) & 0xFF;
}
}
part_relSect(fs- & gt; part,buf);
break;
case FAT16:
offset=cluster_addr%256;
#ifndef MT_MOD
*((euint16*)buf+offset)=next_cluster_addr;
#else
ex_setb16( buf, offset*sizeof(euint16), next_cluster_addr );
#endif
part_relSect(fs- & gt; part,buf);
break;
case FAT32:
offset=cluster_addr%128;
#ifndef MT_MOD
*((euint32*)buf+offset)=next_cluster_addr;
#else
ex_setb32( buf, offset*sizeof(euint32), next_cluster_addr );
#endif
part_relSect(fs- & gt; part,buf);
break;
}

}
/*****************************************************************************/


/* ****************************************************************************
* short fat_isEocMarker(FileSystem *fs,unsigned long fat_entry)
* Description: Checks if a certain value is the EoC marker for the filesystem
* noted in fs- & gt; type.
* Return value: Returns 0 when it is the EoC marker, and 1 otherwise.
*/
eint16 fat_isEocMarker(FileSystem *fs,euint32 fat_entry)
{
switch(fs- & gt; type){
case FAT12:
if(fat_entry & lt; 0xFF8){
return(0);
}
break;
case FAT16:
if(fat_entry & lt; 0xFFF8){
return(0);
}
break;
case FAT32:
if((fat_entry & 0x0FFFFFFF) & lt; 0xFFFFFF8){
return(0);
}
break;
}
return(1);
}
/*****************************************************************************/


/* ****************************************************************************
* unsigned long fat_giveEocMarker(FileSystem *fs)
* Description: Returns an EoC markernumber valid for the filesystem noted in
* fs- & gt; type.
* Note, for FAT32, the upper 4 bits are set to zero, although they should be un
* touched according to MicroSoft specifications. I didn't care.
* Return value: The EoC marker cast to an ulong.
*/
euint32 fat_giveEocMarker(FileSystem *fs)
{
switch(fs- & gt; type)
{
case FAT12:
return(0xFFF);
break;
case FAT16:
return(0xFFFF);
break;
case FAT32:
return(0x0FFFFFFF);
break;
}
return(0);
}
/*****************************************************************************/

/* ****************************************************************************
* euint32 fat_getNextClusterAddressWBuf(FileSystem *fs,euint32 cluster_addr, euint8* buf)
* Description: This function retrieves the contents of a FAT field. It does not fetch
* it's own buffer, it is given as a parameter. (ioman makes this function rather obsolete)
* Only in the case of a FAT12 crosssector data entry a sector is retrieved here.
* Return value: The value of the clusterfield is returned.
*/
euint32 fat_getNextClusterAddressWBuf(FileSystem *fs,euint32 cluster_addr, euint8* buf)
{
euint8 *buf2; /* For FAT12 fallover only */
euint8 hb,lb;
euint16 offset;
euint32 nextcluster=0;

switch(fs- & gt; type)
{
case FAT12:
offset = ((cluster_addr%1024)*3/2)%512;
hb = buf[offset];
if(offset == 511){
buf2=part_getSect(fs- & gt; part,fat_getSectorAddressFatEntry(fs,cluster_addr)+1,IOM_MODE_READONLY);
lb = buf2[0];
part_relSect(fs- & gt; part,buf2);
}else{
lb = buf[offset + 1];
}
if(cluster_addr%2==0){
nextcluster = ( ((lb & 0x0F) & lt; & lt; 8) + (hb) );
}else{
nextcluster = ( (lb & lt; & lt; 4) + (hb & gt; & gt; 4) );
}
break;
case FAT16:
offset=cluster_addr%256;
#ifndef MT_MOD
nextcluster = *((euint16*)buf + offset);
#else
nextcluster = ex_getb16( buf, offset*sizeof(euint16) );
#endif
break;
case FAT32:
offset=cluster_addr%128;
#ifndef MT_MOD
nextcluster = *((euint32*)buf + offset);
#else
nextcluster = ex_getb32( buf, offset*sizeof(euint32) );
#endif
break;
}
return(nextcluster);
}
/*****************************************************************************/

/* ****************************************************************************
* void fat_setNextClusterAddressWBuf(FileSystem *fs,euint32 cluster_addr,euint32 next_cluster_addr,euint8* buf)
* Description: This function fills in a fat entry. The entry is cluster_addr and the
* data entered is next_cluster_addr. This function is also given a *buf, so it does
* not write the data itself, except in the case of FAT 12 cross sector data, where
* the second sector is handled by this function.
* Return value:
*/
void fat_setNextClusterAddressWBuf(FileSystem *fs,euint32 cluster_addr,euint32 next_cluster_addr,euint8* buf)
{
euint16 offset;
euint8 *buf2;

switch(fs- & gt; type)
{
case FAT12:
offset = ((cluster_addr%1024)*3/2)%512;
if(offset == 511){
if(cluster_addr%2==0){
buf[offset]=next_cluster_addr & 0xFF;
}else{
buf[offset]=(buf[offset] & 0xF)+((next_cluster_addr & lt; & lt; 4) & 0xF0);
}
buf2=part_getSect(fs- & gt; part,fat_getSectorAddressFatEntry(fs,cluster_addr)+1,IOM_MODE_READWRITE);
if(cluster_addr%2==0){
buf2[0]=(buf2[0] & 0xF0)+((next_cluster_addr & gt; & gt; 8) & 0xF);
}else{
buf2[0]=(next_cluster_addr & gt; & gt; 4) & 0xFF;
}
part_relSect(fs- & gt; part,buf2);
}else{
if(cluster_addr%2==0){
buf[offset]=next_cluster_addr & 0xFF;
buf[offset+1]=(buf[offset+1] & 0xF0)+((next_cluster_addr & gt; & gt; 8) & 0xF);
}else{
buf[offset]=(buf[offset] & 0xF)+((next_cluster_addr & lt; & lt; 4) & 0xF0);
buf[offset+1]=(next_cluster_addr & gt; & gt; 4) & 0xFF;
}
}
break;
case FAT16:
offset=cluster_addr%256;
#ifndef MT_MOD
*((euint16*)buf+offset)=next_cluster_addr;
#else
ex_setb16( buf, offset*sizeof(euint16), next_cluster_addr );
#endif
break;
case FAT32:
offset=cluster_addr%128;
#ifndef MT_MOD
*((euint32*)buf+offset)=next_cluster_addr;
#else
ex_setb32( buf, offset*sizeof(euint32), next_cluster_addr );
#endif
break;
}
}
/*****************************************************************************/

/* ****************************************************************************
* esint16 fat_getNextClusterChain(FileSystem *fs, ClusterChain *Cache)
* Description: This function is to advance the clusterchain of a Cache.
* First, the function verifies if the Cache is valid. It could correct it if it
* is not, but this is not done at the time. If the cachen is valid, the next step is
* to see what the next cluster is, if this is the End of Clustermark, the cache is
* updated to know the lastcluster but will remain untouched otherwise. -1 is returned.
* If there are more clusters the function scans the rest of the chain until the next
* cluster is no longer lineair, or until it has run out of fat data (only 1 sector) is
* examined, namely the one fetched to check for EoC.
* With lineair is meant that logical cluster n+1 should be 1 more than logical cluster n
* at the disc level.
* Return value: 0 on success, or -1 when EoC.
*/
esint16 fat_getNextClusterChain(FileSystem *fs, ClusterChain *Cache)
{
euint32 sect,lr,nlr,dc;
esint16 lin=0;
euint8 *buf;

if(Cache- & gt; DiscCluster==0)
{
return(-1);
}

sect=fat_getSectorAddressFatEntry(fs,Cache- & gt; DiscCluster);
buf=part_getSect(fs- & gt; part,sect,IOM_MODE_READONLY);
dc=fat_getNextClusterAddressWBuf(fs,Cache- & gt; DiscCluster,buf);
if(fat_isEocMarker(fs,dc))
{
Cache- & gt; LastCluster=Cache- & gt; DiscCluster;
part_relSect(fs- & gt; part,buf);
return(-1);
}

Cache- & gt; DiscCluster=dc;
Cache- & gt; LogicCluster++;

lr=Cache- & gt; DiscCluster-1;
nlr=lr+1;

while(nlr-1==lr & & fat_getSectorAddressFatEntry(fs,nlr)==sect)
{
lr=nlr;
nlr=fat_getNextClusterAddressWBuf(fs,lr,buf);
lin++;
}

Cache- & gt; Linear=lin-1 & lt; 0?0:lin-1;

part_relSect(fs- & gt; part,buf);
return(0);
}
/*****************************************************************************/


/* ****************************************************************************
* esint16 fat_LogicToDiscCluster(FileSystem *fs, ClusterChain *Cache,euint32 logiccluster)
* Description: This function is used to follow clusterchains. When called it will convert
* a logical cluster, to a disc cluster, using a Cache object. All it does is call
* getNextClusterChain in the proper manner, and rewind clusterchains if required.
* It is NOT recommended to go backwards in clusterchains, since this will require
* scanning the entire chain every time.
* Return value: 0 on success and -1 on failure (meaning out of bounds).
*/
esint16 fat_LogicToDiscCluster(FileSystem *fs, ClusterChain *Cache,euint32 logiccluster)
{
if(logiccluster & lt; Cache- & gt; LogicCluster || Cache- & gt; DiscCluster==0){
Cache- & gt; LogicCluster=0;
Cache- & gt; DiscCluster=Cache- & gt; FirstCluster;
Cache- & gt; Linear=0;
}

if(Cache- & gt; LogicCluster==logiccluster){
return(0);
}

while(Cache- & gt; LogicCluster!=logiccluster)
{
if(Cache- & gt; Linear!=0)
{
Cache- & gt; Linear--;
Cache- & gt; LogicCluster++;
Cache- & gt; DiscCluster++;
}
else
{
if((fat_getNextClusterChain(fs,Cache))!=0){
return(-1);
}
}
}
return(0);
}
/*****************************************************************************/

/* ****************************************************************************
* eint16 fat_allocClusterChain(FileSystem *fs,ClusterChain *Cache,euint32 num_clusters)
* Description: This function extends a clusterchain by num_clusters. It returns the
* number of clusters it *failed* to allocate.
* Return value: 0 on success, all other values are the number of clusters it could
* not allocate.
*/
eint16 fat_allocClusterChain(FileSystem *fs,ClusterChain *Cache,euint32 num_clusters)
{
euint32 cc,ncl=num_clusters,lc;
euint8 *bufa=0,*bufb=0;
euint8 overflow=0;

if(Cache- & gt; FirstCluster & lt; =1)return(num_clusters);

lc=fs_getLastCluster(fs,Cache);
cc=lc;

while(ncl & gt; 0){
cc++;
if(cc & gt; =fs- & gt; DataClusterCount+1){
if(overflow){
bufa=part_getSect(fs- & gt; part,fat_getSectorAddressFatEntry(fs,lc),IOM_MODE_READWRITE);
fat_setNextClusterAddressWBuf(fs,lc,fat_giveEocMarker(fs),bufa);
Cache- & gt; LastCluster=lc;
part_relSect(fs- & gt; part,bufa);
fs- & gt; FreeClusterCount-=num_clusters-ncl;
return(num_clusters-ncl);
}
cc=2;
overflow++;
}
bufa=part_getSect(fs- & gt; part,fat_getSectorAddressFatEntry(fs,cc),IOM_MODE_READONLY);
if(fat_getNextClusterAddressWBuf(fs,cc,bufa)==0){
bufb=part_getSect(fs- & gt; part,fat_getSectorAddressFatEntry(fs,lc),IOM_MODE_READWRITE);
fat_setNextClusterAddressWBuf(fs,lc,cc,bufb);
part_relSect(fs- & gt; part,bufb);
ncl--;
lc=cc;
}
part_relSect(fs- & gt; part,bufa);
if(ncl==0){
bufa=part_getSect(fs- & gt; part,fat_getSectorAddressFatEntry(fs,lc),IOM_MODE_READWRITE);
fat_setNextClusterAddressWBuf(fs,lc,fat_giveEocMarker(fs),bufa);
Cache- & gt; LastCluster=lc;
part_relSect(fs- & gt; part,bufa);
}
}
if(Cache- & gt; ClusterCount)Cache- & gt; ClusterCount+=num_clusters;
return(0);
}

/* ****************************************************************************
* eint16 fat_unlinkClusterChain(FileSystem *fs,ClusterChain *Cache)
* Description: This function removes a clusterchain. Starting at FirstCluster
* it follows the chain until the end, resetting all values to 0.
* Return value: 0 on success.
*/
eint16 fat_unlinkClusterChain(FileSystem *fs,ClusterChain *Cache)
{
euint32 c,tbd=0;

Cache- & gt; LogicCluster=0;
Cache- & gt; DiscCluster=Cache- & gt; FirstCluster;

c=0;

while(!fat_LogicToDiscCluster(fs,Cache,c++)){
if(tbd!=0){
fat_setNextClusterAddress(fs,tbd,0);
}
tbd=Cache- & gt; DiscCluster;
}
fat_setNextClusterAddress(fs,Cache- & gt; DiscCluster,0);
fs- & gt; FreeClusterCount+=c;
return(0);
}

euint32 fat_countClustersInChain(FileSystem *fs,euint32 firstcluster)
{
ClusterChain cache;
euint32 c=0;

if(firstcluster & lt; =1)return(0);

cache.DiscCluster = cache.LogicCluster = cache.LastCluster = cache.Linear = 0;
cache.FirstCluster = firstcluster;

while(!(fat_LogicToDiscCluster(fs, & cache,c++)));

return(c-1);
}

euint32 fat_DiscToLogicCluster(FileSystem *fs,euint32 firstcluster,euint32 disccluster)
{
ClusterChain cache;
euint32 c=0,r=0;

cache.DiscCluster = cache.LogicCluster = cache.LastCluster = cache.Linear = 0;
cache.FirstCluster = firstcluster;

while(!(fat_LogicToDiscCluster(fs, & cache,c++)) & & !r){
if(cache.DiscCluster == disccluster){
r = cache.LogicCluster;
}
}
return(r);
}

euint32 fat_countFreeClusters(FileSystem *fs)
{
euint32 c=2,fc=0;

while(c & lt; =fs- & gt; DataClusterCount+1){
if(fat_getNextClusterAddress(fs,c,0)==0)fc++;
c++;
}
return(fc);
}