o add fat filesystem test for arm lpc2148
This commit is contained in:
332
poc/lpc2148_efsl/src/debug.c
Normal file
332
poc/lpc2148_efsl/src/debug.c
Normal file
@@ -0,0 +1,332 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------------------------------------------- *
|
||||
* *
|
||||
* Filename : debug.c *
|
||||
* Description : These functions are used for debugging output on different *
|
||||
* environments *
|
||||
* *
|
||||
* 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 *
|
||||
\*****************************************************************************/
|
||||
|
||||
/* COMMENT REGARDING FUNCTION COMMENTS IN THIS FILE
|
||||
* Only the linuxfile debug functions are commented since all functions
|
||||
* perform the same logical task.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
#include "debug.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
#ifdef DEBUG
|
||||
#ifdef HW_ENDPOINT_LINUX_ALL
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void debug(const eint8 *format, ...)
|
||||
* Description: This function prints debug output to the screen (target dependant)
|
||||
* and if DO_FUNC_DEBUG is defined also to a localfile.
|
||||
* Return value: void
|
||||
*/
|
||||
|
||||
void debug(const eint8 *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
#ifdef DO_FUNC_DEBUG
|
||||
euint8 c;
|
||||
extern FILE* debugfile;
|
||||
extern volatile euint8 tw;
|
||||
#endif
|
||||
|
||||
va_start(ap, format);
|
||||
vprintf(format,ap);
|
||||
#ifdef DO_FUNC_DEBUG
|
||||
for(c=0;c<tw+1;c++)
|
||||
{
|
||||
fprintf(debugfile," ");
|
||||
}
|
||||
vfprintf(debugfile,format,ap);
|
||||
#endif
|
||||
va_end(ap);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void debug_funcin(const eint8 *format, ...)
|
||||
* Description: This function marks the entrance of a function, which
|
||||
* increments a tabfieldcounter. A tree like structure can the be found in the
|
||||
* debugging file.
|
||||
* Return value: void
|
||||
*/
|
||||
|
||||
void debug_funcin(const eint8 *format, ...)
|
||||
{
|
||||
#ifdef DO_FUNC_DEBUG
|
||||
eint8 c;
|
||||
va_list ap;
|
||||
extern FILE* debugfile;
|
||||
extern volatile unsigned char tw;
|
||||
|
||||
if(debugfile==NULL)return;
|
||||
|
||||
for(c=0;c<tw;c++){
|
||||
fprintf(debugfile," ");
|
||||
}
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(debugfile,format,ap);
|
||||
va_end(ap);
|
||||
fprintf(debugfile,"\n");
|
||||
|
||||
tw++;
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void debug_funcout(const eint8 *format, ...)
|
||||
* Description: Decrements the tabfieldcounter. This function is called everywhere
|
||||
* a function is left.
|
||||
* Return value: void
|
||||
*/
|
||||
|
||||
void debug_funcout(const eint8 *format, ...)
|
||||
{
|
||||
#ifdef DO_FUNC_DEBUG
|
||||
eint8 c;
|
||||
va_list ap;
|
||||
extern FILE* debugfile;
|
||||
extern volatile euint8 tw;
|
||||
|
||||
if(debugfile==NULL)return;
|
||||
|
||||
if(tw>0)tw--;
|
||||
|
||||
for(c=0;c<tw;c++){
|
||||
fprintf(debugfile," ");
|
||||
}
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(debugfile,format,ap);
|
||||
va_end(ap);
|
||||
fprintf(debugfile,"\n");
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void debug_init()
|
||||
* Description: This function optionally opens the debugfile, or does any other
|
||||
* initialisation to enable debugoutput.
|
||||
* Return value: void
|
||||
*/
|
||||
void debug_init()
|
||||
{
|
||||
#ifdef DO_FUNC_DEBUG
|
||||
extern FILE* debugfile;
|
||||
extern volatile unsigned char tw;
|
||||
|
||||
debugfile=NULL;
|
||||
tw=0;
|
||||
|
||||
debugfile=fopen("DBG.OUT","w");
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void debug_end()
|
||||
* Description: This function closes the debugfile.
|
||||
* Return value: void
|
||||
*/
|
||||
void debug_end()
|
||||
{
|
||||
#ifdef DO_FUNC_DEBUG
|
||||
extern FILE* debugfile;
|
||||
|
||||
fflush(debugfile);
|
||||
fclose(debugfile);
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
#endif
|
||||
#endif
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
#ifdef DEBUG
|
||||
#ifdef HW_ENDPOINT_ATMEGA128_SD
|
||||
/*****************************************************************************/
|
||||
|
||||
void debug(const eint8 *format, ...)
|
||||
{
|
||||
eint8 dbgstring[90];
|
||||
va_list ap;
|
||||
euint8 i=0;
|
||||
eint8 c;
|
||||
|
||||
va_start(ap, format);
|
||||
vsprintf_P(dbgstring, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
|
||||
while (( (c=dbgstring[i++]) && (i<90) ))
|
||||
debug_sendByte(c);
|
||||
|
||||
if(i>=90)
|
||||
debug(PSTR("<BREAK>\n"));
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void debug_init(void)
|
||||
{
|
||||
unsigned short ubrr;
|
||||
|
||||
ubrr = ((unsigned short)DEBUG_UBRR);
|
||||
|
||||
switch(DEBUG_PORT){
|
||||
case 0:
|
||||
UBRR0H = (euint8) (ubrr>>8);
|
||||
UBRR0L = (euint8) (ubrr);
|
||||
UCSR0B = ( (1<<RXEN) | (1<<TXEN) );
|
||||
break;
|
||||
case 1:
|
||||
UBRR1H = (euint8) (ubrr>>8);
|
||||
UBRR1L = (euint8) (ubrr);
|
||||
UCSR1B = ( (1<<RXEN) | (1<<TXEN) );
|
||||
break;
|
||||
default:
|
||||
/* INVALID CONFIG FILE */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void debug_end(void)
|
||||
{
|
||||
/* Nothing to do here, function is here for compatibility */
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void debug_sendByte(euint8 data)
|
||||
{
|
||||
/* If sending a newline, add a return first */
|
||||
if(data=='\n')
|
||||
debug_sendByte('\r');
|
||||
|
||||
switch(DEBUG_PORT){
|
||||
case 0:
|
||||
while ( !(UCSR0A & (1<<UDRE0)) )
|
||||
_NOP(); /* Wait for empty transmit buffer */
|
||||
UDR0 = data; /* Start transmittion */
|
||||
break;
|
||||
case 1:
|
||||
while ( !(UCSR1A & (1<<UDRE1)) )
|
||||
_NOP(); /* Wait for empty transmit buffer */
|
||||
UDR1 = data; /* Start transmittion */
|
||||
break;
|
||||
default:
|
||||
/* INVALID CONFIG FILE */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned char debug_getByte()
|
||||
{
|
||||
switch(DEBUG_PORT){
|
||||
case 0:
|
||||
while ( !(UCSR0A & (1<<RXC0)) )
|
||||
_NOP();
|
||||
return(UDR0);
|
||||
break;
|
||||
case 1:
|
||||
while ( !(UCSR1A & (1<<RXC1)) )
|
||||
_NOP();
|
||||
return(UDR1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 debug_getString(euint8 *data,euint16 length)
|
||||
{
|
||||
euint8 i=0;
|
||||
euint8 c;
|
||||
|
||||
do
|
||||
{
|
||||
c=debug_getByte();
|
||||
if(c!='\n' && c!='\r')
|
||||
data[i++]=c;
|
||||
debug_sendByte(c);
|
||||
}
|
||||
while(c!='\n' && c!='\r' && i<length);
|
||||
data[i]='\0';
|
||||
|
||||
return(i);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
#endif
|
||||
#endif
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
#ifdef DEBUG
|
||||
#ifdef HW_ENDPOINT_DSP_TI6713_SD
|
||||
/*****************************************************************************/
|
||||
|
||||
void dbg(const char *format, ...)
|
||||
{
|
||||
printf(format);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void debug_init()
|
||||
{
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void debug_end()
|
||||
{
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
#endif
|
||||
#endif
|
||||
/*****************************************************************************/
|
||||
|
||||
369
poc/lpc2148_efsl/src/dir.c
Normal file
369
poc/lpc2148_efsl/src/dir.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*****************************************************************************\
|
||||
* 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->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->volumeId.RootEntryCount/32);c++){ *
|
||||
* + for(c=fs->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->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->part,loc->Sector,IOM_MODE_READONLY);
|
||||
*filerec=*(((FileRecord*)buf)+loc->Offset);
|
||||
part_relSect(fs->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->part,loc->Sector,IOM_MODE_READWRITE);
|
||||
memCpy(filerec,buf+(loc->Offset*sizeof(*filerec)),sizeof(*filerec));
|
||||
part_relSect(fs->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->FileName,11);
|
||||
filerec->Attribute=0x00;
|
||||
filerec->NTReserved=0x00;
|
||||
filerec->MilliSecTimeStamp=0x00;
|
||||
filerec->CreatedTime=time_getTime();
|
||||
filerec->CreatedDate=time_getDate();
|
||||
filerec->AccessDate=filerec->CreatedDate;
|
||||
filerec->FirstClusterHigh=0x0000;
|
||||
filerec->WriteTime=filerec->CreatedTime;
|
||||
filerec->WriteDate=filerec->CreatedDate;
|
||||
filerec->FirstClusterLow=0x0000;
|
||||
filerec->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->part,loc->Sector,IOM_MODE_READWRITE);
|
||||
(((FileRecord*)buf)+loc->Offset)->FirstClusterHigh=cluster_addr>>16;
|
||||
(((FileRecord*)buf)+loc->Offset)->FirstClusterLow=cluster_addr&0xFFFF;
|
||||
part_relSect(fs->part,buf);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void dir_setFileSize(FileSystem *fs, FileLocation *loc,euint32 numbytes)
|
||||
* Description: This function changes the filesize recorded at loc->Sector
|
||||
* to 'numbytes'.
|
||||
* Return value: void
|
||||
*/
|
||||
void dir_setFileSize(FileSystem *fs, FileLocation *loc,euint32 numbytes)
|
||||
{
|
||||
euint8 *buf;
|
||||
|
||||
buf = part_getSect(fs->part,loc->Sector,IOM_MODE_READWRITE);
|
||||
(((FileRecord*)buf)+loc->Offset)->FileSize=numbytes;
|
||||
part_relSect(fs->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->part,loc->Sector,IOM_MODE_READWRITE);
|
||||
memCpy(entry,buf+(loc->Offset*sizeof(*entry)),sizeof(*entry));
|
||||
part_relSect(fs->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<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->Offset = c;
|
||||
if(loc)loc->attrib = fileEntry.Attribute;
|
||||
if((((euint32 )fileEntry.FirstClusterHigh)<<16)+ fileEntry.FirstClusterLow==0){
|
||||
return(1); /* Lie about cluster, 0 means not found! */
|
||||
}else{
|
||||
return
|
||||
(
|
||||
(((euint32 )fileEntry.FirstClusterHigh)<<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->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<16;c++){
|
||||
fileEntry = *(((FileRecord*)buf) + c);
|
||||
if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) ){
|
||||
if(fileEntry.FileName[0] == 0x00 ||
|
||||
fileEntry.FileName[0] == 0xE5 ){
|
||||
if(loc)loc->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<fs->volumeId.SectorsPerCluster;c++){
|
||||
buf = part_getSect(fs->part,fs_clusterToSector(fs,cluster)+c,IOM_MODE_READONLY);
|
||||
if((fclus=dir_findinBuf(buf,fatname,loc,mode))){
|
||||
if(loc)loc->Sector=fs_clusterToSector(fs,cluster)+c;
|
||||
part_relSect(fs->part,buf);
|
||||
return(fclus);
|
||||
}
|
||||
part_relSect(fs->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 <= 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->type != FAT12) && (fs->type != FAT16))return(0);
|
||||
|
||||
#warning "inofficial find in root patch included"
|
||||
/* for(c=fs->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->volumeId.RootEntryCount/32);c++){*/
|
||||
for(c=fs->FirstSectorRootDir;c<(fs->FirstSectorRootDir+fs->volumeId.RootEntryCount/16);c++) {
|
||||
buf = part_getSect(fs->part,c,IOM_MODE_READONLY);
|
||||
if((fclus=dir_findinBuf(buf,fatname,loc,mode))){
|
||||
if(loc)loc->Sector=c;
|
||||
part_relSect(fs->part,buf);
|
||||
return(fclus);
|
||||
}
|
||||
part_relSect(fs->part,buf);
|
||||
}
|
||||
part_relSect(fs->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);
|
||||
}
|
||||
|
||||
|
||||
68
poc/lpc2148_efsl/src/disc.c
Normal file
68
poc/lpc2148_efsl/src/disc.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : disc.c *
|
||||
* Description : This file contains the functions regarding the whole disc *
|
||||
* such as loading the MBR and performing read/write tests. *
|
||||
* *
|
||||
* 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 "disc.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void disc_initDisc(Disc *disc,hcInterface* source)
|
||||
* Description: This initialises the disc by loading the MBR and setting the
|
||||
* pointer to the hardware object.
|
||||
*/
|
||||
void disc_initDisc(Disc *disc,IOManager* ioman)
|
||||
{
|
||||
disc->ioman=ioman;
|
||||
disc_setError(disc,DISC_NOERROR);
|
||||
disc_loadMBR(disc);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void disc_loadMBR(Disc *disc)
|
||||
* Description: This functions copies the partitiontable to the partitions field.
|
||||
*/
|
||||
void disc_loadMBR(Disc *disc)
|
||||
{
|
||||
euint8 x;
|
||||
euint8 *buf;
|
||||
|
||||
buf=ioman_getSector(disc->ioman,LBA_ADDR_MBR,IOM_MODE_READONLY|IOM_MODE_EXP_REQ);
|
||||
for(x=0;x<4;x++){
|
||||
ex_getPartitionField(buf,&(disc->partitions[x]),PARTITION_TABLE_OFFSET+(x*SIZE_PARTITION_FIELD));
|
||||
}
|
||||
ioman_releaseSector(disc->ioman,buf);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
68
poc/lpc2148_efsl/src/efs.c
Normal file
68
poc/lpc2148_efsl/src/efs.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : efs.h *
|
||||
* Description : This should become the wrapper around efs. It will contain *
|
||||
* functions like efs_init etc. *
|
||||
* *
|
||||
* 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 "efs.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* esint8 efs_init(EmbeddedFileSystem * efs,eint8* opts)
|
||||
* Description: This function initialises all subelements of a filesystem.
|
||||
* It sets the pointerchain and verifies each step.
|
||||
* Return value: 0 on success and -1 on failure.
|
||||
*/
|
||||
esint8 efs_init(EmbeddedFileSystem * efs,eint8* opts)
|
||||
{
|
||||
if(if_initInterface(&efs->myCard, opts)==0)
|
||||
{
|
||||
ioman_init(&efs->myIOman,&efs->myCard,0);
|
||||
disc_initDisc(&efs->myDisc, &efs->myIOman);
|
||||
part_initPartition(&efs->myPart, &efs->myDisc);
|
||||
if(efs->myPart.activePartition==-1){
|
||||
efs->myDisc.partitions[0].type=0x0B;
|
||||
efs->myDisc.partitions[0].LBA_begin=0;
|
||||
efs->myDisc.partitions[0].numSectors=efs->myCard.sectorCount;
|
||||
/*efs->myPart.activePartition = 0;*/
|
||||
/*efs->myPart.disc = &(efs->myDisc);*/
|
||||
part_initPartition(&efs->myPart, &efs->myDisc);
|
||||
}
|
||||
/*part_initPartition(&efs->myPart, &efs->myDisc);*/
|
||||
if(fs_initFs(&efs->myFs, &efs->myPart))
|
||||
return(-2);
|
||||
return(0);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
191
poc/lpc2148_efsl/src/extract.c
Normal file
191
poc/lpc2148_efsl/src/extract.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/*****************************************************************************\
|
||||
* 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))<<8) + ((*(buf+offset+0))<<0)));
|
||||
}
|
||||
|
||||
euint32 ex_getb32(euint8* buf,euint32 offset)
|
||||
{
|
||||
return(ltb_end32(((euint32)buf[offset+3]<<24)+
|
||||
((euint32)buf[offset+2]<<16)+
|
||||
((euint32)buf[offset+1]<<8)+
|
||||
((euint32)buf[offset+0]<<0)));
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "mthomas - modification enabled"
|
||||
|
||||
euint32 ex_getb32(euint8* buf,euint32 offset)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
return ((euint32)*(euint8*)(buf+offset)<<24UL) |
|
||||
((euint32)*(euint8*)(buf+offset+1)<<16UL) |
|
||||
((euint16)*(euint8*)(buf+offset+2)<<8UL) |
|
||||
(*(euint8*)(buf+offset+3)) ;
|
||||
#else
|
||||
return ((euint32)*(euint8*)(buf+offset+3)<<24UL) |
|
||||
((euint32)*(euint8*)(buf+offset+2)<<16UL) |
|
||||
((euint16)*(euint8*)(buf+offset+1)<<8UL) |
|
||||
(*(euint8*)(buf+offset)) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
euint16 ex_getb16(euint8* buf,euint32 offset)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
return ((euint16)*(euint8*)(buf+offset)<<8UL) |
|
||||
(*(euint8*)(buf+offset+1)) ;
|
||||
#else
|
||||
return ((euint16)*(euint8*)(buf+offset+1)<<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>>0;
|
||||
*(buf+offset+0) = data>>8;
|
||||
#else
|
||||
*(buf+offset+0) = data>>0;
|
||||
*(buf+offset+1) = data>>8;
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ex_setb32(euint8* buf,euint32 offset,euint32 data)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
*(buf+offset+3) = data>> 0;
|
||||
*(buf+offset+2) = data>> 8;
|
||||
*(buf+offset+1) = data>>16;
|
||||
*(buf+offset+0) = data>>24;
|
||||
#else
|
||||
*(buf+offset+0) = data>> 0;
|
||||
*(buf+offset+1) = data>> 8;
|
||||
*(buf+offset+2) = data>>16;
|
||||
*(buf+offset+3) = data>>24;
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ex_getPartitionField(euint8* buf,PartitionField* pf, euint32 offset)
|
||||
{
|
||||
pf->bootFlag = *(buf + offset);
|
||||
pf->CHS_begin[0] = *(buf + offset + 1);
|
||||
pf->CHS_begin[1] = *(buf + offset + 2);
|
||||
pf->CHS_begin[2] = *(buf + offset + 3);
|
||||
pf->type = *(buf + offset + 4);
|
||||
pf->CHS_end[0] = *(buf + offset + 5);
|
||||
pf->CHS_end[1] = *(buf + offset + 6);
|
||||
pf->CHS_end[2] = *(buf + offset + 7);
|
||||
pf->LBA_begin = ex_getb32(buf + offset,8);
|
||||
pf->numSectors = ex_getb32(buf + offset,12);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ex_setPartitionField(euint8* buf,PartitionField* pf, euint32 offset)
|
||||
{
|
||||
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
#endif
|
||||
/*****************************************************************************/
|
||||
|
||||
607
poc/lpc2148_efsl/src/fat.c
Normal file
607
poc/lpc2148_efsl/src/fat.c
Normal file
@@ -0,0 +1,607 @@
|
||||
/*****************************************************************************\
|
||||
* 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->volumeId.ReservedSectorCount,res;
|
||||
|
||||
switch(fs->type){
|
||||
case FAT12:
|
||||
res=(cluster_addr*3/1024);
|
||||
if(res>=fs->FatSectorCount){
|
||||
return(0);
|
||||
}else{
|
||||
return(base+res);
|
||||
}
|
||||
break;
|
||||
case FAT16:
|
||||
res=cluster_addr/256;
|
||||
if(res>=fs->FatSectorCount){
|
||||
return(0);
|
||||
}else{
|
||||
return(base+res);
|
||||
}
|
||||
break;
|
||||
case FAT32:
|
||||
res=cluster_addr/128;
|
||||
if(res>=fs->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->FatSectorCount <= (sector-fs->volumeId.ReservedSectorCount)) || sector==0 )
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
buf=part_getSect(fs->part,sector,IOM_MODE_READONLY);
|
||||
|
||||
switch(fs->type)
|
||||
{
|
||||
case FAT12:
|
||||
offset = ((cluster_addr%1024)*3/2)%512;
|
||||
hb = buf[offset];
|
||||
if(offset == 511){
|
||||
part_relSect(fs->part,buf);
|
||||
buf=part_getSect(fs->part,sector+1,IOM_MODE_READONLY);
|
||||
lb = buf[0];
|
||||
}else{
|
||||
lb = buf[offset + 1];
|
||||
}
|
||||
if(cluster_addr%2==0){
|
||||
nextcluster = ( ((lb&0x0F)<<8) + (hb) );
|
||||
}else{
|
||||
nextcluster = ( (lb<<4) + (hb>>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->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->FatSectorCount <= (sector - fs->volumeId.ReservedSectorCount )||(sector==0))){
|
||||
DBG((TXT("HARDERROR:::fat_getNextClusterAddress READ PAST FAT BOUNDARY\n")));
|
||||
return;
|
||||
}
|
||||
|
||||
buf=part_getSect(fs->part,sector,IOM_MODE_READWRITE);
|
||||
|
||||
switch(fs->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<<4)&0xF0);
|
||||
}
|
||||
buf2=part_getSect(fs->part,fat_getSectorAddressFatEntry(fs,cluster_addr)+1,IOM_MODE_READWRITE);
|
||||
if(cluster_addr%2==0){
|
||||
buf2[0]=(buf2[0]&0xF0)+((next_cluster_addr>>8)&0xF);
|
||||
}else{
|
||||
buf2[0]=(next_cluster_addr>>4)&0xFF;
|
||||
}
|
||||
part_relSect(fs->part,buf2);
|
||||
}else{
|
||||
if(cluster_addr%2==0){
|
||||
buf[offset]=next_cluster_addr&0xFF;
|
||||
buf[offset+1]=(buf[offset+1]&0xF0)+((next_cluster_addr>>8)&0xF);
|
||||
}else{
|
||||
buf[offset]=(buf[offset]&0xF)+((next_cluster_addr<<4)&0xF0);
|
||||
buf[offset+1]=(next_cluster_addr>>4)&0xFF;
|
||||
}
|
||||
}
|
||||
part_relSect(fs->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->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->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->type.
|
||||
* Return value: Returns 0 when it is the EoC marker, and 1 otherwise.
|
||||
*/
|
||||
eint16 fat_isEocMarker(FileSystem *fs,euint32 fat_entry)
|
||||
{
|
||||
switch(fs->type){
|
||||
case FAT12:
|
||||
if(fat_entry<0xFF8){
|
||||
return(0);
|
||||
}
|
||||
break;
|
||||
case FAT16:
|
||||
if(fat_entry<0xFFF8){
|
||||
return(0);
|
||||
}
|
||||
break;
|
||||
case FAT32:
|
||||
if((fat_entry&0x0FFFFFFF)<0xFFFFFF8){
|
||||
return(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/* ****************************************************************************
|
||||
* unsigned long fat_giveEocMarker(FileSystem *fs)
|
||||
* Description: Returns an EoC markernumber valid for the filesystem noted in
|
||||
* fs->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->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->type)
|
||||
{
|
||||
case FAT12:
|
||||
offset = ((cluster_addr%1024)*3/2)%512;
|
||||
hb = buf[offset];
|
||||
if(offset == 511){
|
||||
buf2=part_getSect(fs->part,fat_getSectorAddressFatEntry(fs,cluster_addr)+1,IOM_MODE_READONLY);
|
||||
lb = buf2[0];
|
||||
part_relSect(fs->part,buf2);
|
||||
}else{
|
||||
lb = buf[offset + 1];
|
||||
}
|
||||
if(cluster_addr%2==0){
|
||||
nextcluster = ( ((lb&0x0F)<<8) + (hb) );
|
||||
}else{
|
||||
nextcluster = ( (lb<<4) + (hb>>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->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<<4)&0xF0);
|
||||
}
|
||||
buf2=part_getSect(fs->part,fat_getSectorAddressFatEntry(fs,cluster_addr)+1,IOM_MODE_READWRITE);
|
||||
if(cluster_addr%2==0){
|
||||
buf2[0]=(buf2[0]&0xF0)+((next_cluster_addr>>8)&0xF);
|
||||
}else{
|
||||
buf2[0]=(next_cluster_addr>>4)&0xFF;
|
||||
}
|
||||
part_relSect(fs->part,buf2);
|
||||
}else{
|
||||
if(cluster_addr%2==0){
|
||||
buf[offset]=next_cluster_addr&0xFF;
|
||||
buf[offset+1]=(buf[offset+1]&0xF0)+((next_cluster_addr>>8)&0xF);
|
||||
}else{
|
||||
buf[offset]=(buf[offset]&0xF)+((next_cluster_addr<<4)&0xF0);
|
||||
buf[offset+1]=(next_cluster_addr>>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->DiscCluster==0)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
sect=fat_getSectorAddressFatEntry(fs,Cache->DiscCluster);
|
||||
buf=part_getSect(fs->part,sect,IOM_MODE_READONLY);
|
||||
dc=fat_getNextClusterAddressWBuf(fs,Cache->DiscCluster,buf);
|
||||
if(fat_isEocMarker(fs,dc))
|
||||
{
|
||||
Cache->LastCluster=Cache->DiscCluster;
|
||||
part_relSect(fs->part,buf);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
Cache->DiscCluster=dc;
|
||||
Cache->LogicCluster++;
|
||||
|
||||
lr=Cache->DiscCluster-1;
|
||||
nlr=lr+1;
|
||||
|
||||
while(nlr-1==lr && fat_getSectorAddressFatEntry(fs,nlr)==sect)
|
||||
{
|
||||
lr=nlr;
|
||||
nlr=fat_getNextClusterAddressWBuf(fs,lr,buf);
|
||||
lin++;
|
||||
}
|
||||
|
||||
Cache->Linear=lin-1<0?0:lin-1;
|
||||
|
||||
part_relSect(fs->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<Cache->LogicCluster || Cache->DiscCluster==0){
|
||||
Cache->LogicCluster=0;
|
||||
Cache->DiscCluster=Cache->FirstCluster;
|
||||
Cache->Linear=0;
|
||||
}
|
||||
|
||||
if(Cache->LogicCluster==logiccluster){
|
||||
return(0);
|
||||
}
|
||||
|
||||
while(Cache->LogicCluster!=logiccluster)
|
||||
{
|
||||
if(Cache->Linear!=0)
|
||||
{
|
||||
Cache->Linear--;
|
||||
Cache->LogicCluster++;
|
||||
Cache->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->FirstCluster<=1)return(num_clusters);
|
||||
|
||||
lc=fs_getLastCluster(fs,Cache);
|
||||
cc=lc;
|
||||
|
||||
while(ncl > 0){
|
||||
cc++;
|
||||
if(cc>=fs->DataClusterCount+1){
|
||||
if(overflow){
|
||||
bufa=part_getSect(fs->part,fat_getSectorAddressFatEntry(fs,lc),IOM_MODE_READWRITE);
|
||||
fat_setNextClusterAddressWBuf(fs,lc,fat_giveEocMarker(fs),bufa);
|
||||
Cache->LastCluster=lc;
|
||||
part_relSect(fs->part,bufa);
|
||||
fs->FreeClusterCount-=num_clusters-ncl;
|
||||
return(num_clusters-ncl);
|
||||
}
|
||||
cc=2;
|
||||
overflow++;
|
||||
}
|
||||
bufa=part_getSect(fs->part,fat_getSectorAddressFatEntry(fs,cc),IOM_MODE_READONLY);
|
||||
if(fat_getNextClusterAddressWBuf(fs,cc,bufa)==0){
|
||||
bufb=part_getSect(fs->part,fat_getSectorAddressFatEntry(fs,lc),IOM_MODE_READWRITE);
|
||||
fat_setNextClusterAddressWBuf(fs,lc,cc,bufb);
|
||||
part_relSect(fs->part,bufb);
|
||||
ncl--;
|
||||
lc=cc;
|
||||
}
|
||||
part_relSect(fs->part,bufa);
|
||||
if(ncl==0){
|
||||
bufa=part_getSect(fs->part,fat_getSectorAddressFatEntry(fs,lc),IOM_MODE_READWRITE);
|
||||
fat_setNextClusterAddressWBuf(fs,lc,fat_giveEocMarker(fs),bufa);
|
||||
Cache->LastCluster=lc;
|
||||
part_relSect(fs->part,bufa);
|
||||
}
|
||||
}
|
||||
if(Cache->ClusterCount)Cache->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->LogicCluster=0;
|
||||
Cache->DiscCluster=Cache->FirstCluster;
|
||||
|
||||
c=0;
|
||||
|
||||
while(!fat_LogicToDiscCluster(fs,Cache,c++)){
|
||||
if(tbd!=0){
|
||||
fat_setNextClusterAddress(fs,tbd,0);
|
||||
}
|
||||
tbd=Cache->DiscCluster;
|
||||
}
|
||||
fat_setNextClusterAddress(fs,Cache->DiscCluster,0);
|
||||
fs->FreeClusterCount+=c;
|
||||
return(0);
|
||||
}
|
||||
|
||||
euint32 fat_countClustersInChain(FileSystem *fs,euint32 firstcluster)
|
||||
{
|
||||
ClusterChain cache;
|
||||
euint32 c=0;
|
||||
|
||||
if(firstcluster<=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<=fs->DataClusterCount+1){
|
||||
if(fat_getNextClusterAddress(fs,c,0)==0)fc++;
|
||||
c++;
|
||||
}
|
||||
return(fc);
|
||||
}
|
||||
510
poc/lpc2148_efsl/src/file.c
Normal file
510
poc/lpc2148_efsl/src/file.c
Normal file
@@ -0,0 +1,510 @@
|
||||
/*****************************************************************************\
|
||||
* 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>=file->FileSize)
|
||||
size_left=0; /* Offset check */
|
||||
|
||||
if( (offset+size > file->FileSize) && size_left!=0)
|
||||
size_left=file->FileSize-offset;
|
||||
|
||||
while(size_left>0){
|
||||
|
||||
cclus = coffset/(512*file->fs->volumeId.SectorsPerCluster);
|
||||
csec = (coffset/(512))%file->fs->volumeId.SectorsPerCluster;
|
||||
cbyte = coffset%512;
|
||||
|
||||
if(cbyte!=0 || size_left<512){
|
||||
btr = 512-(coffset%512)>=size_left?size_left:512-(coffset%512);
|
||||
}else{
|
||||
btr = 512;
|
||||
}
|
||||
|
||||
if((fat_LogicToDiscCluster(file->fs,&(file->Cache),cclus))!=0){
|
||||
return(0);
|
||||
}
|
||||
rclus=file->Cache.DiscCluster;
|
||||
rsec=fs_clusterToSector(file->fs,rclus);
|
||||
|
||||
|
||||
if(btr==512){
|
||||
/*part_readBuf(file->fs->part,rsec+csec,buf+bytes_read);*/
|
||||
part_directSectorRead(file->fs->part,rsec+csec,buf+bytes_read);
|
||||
}else{
|
||||
/*part_readBuf(file->fs->part,rsec+csec,tbuf);*/
|
||||
tbuf = part_getSect(file->fs->part,rsec+csec,IOM_MODE_READONLY);
|
||||
memCpy(tbuf+(coffset%512),buf+bytes_read,btr);
|
||||
part_relSect(file->fs->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->FilePtr,size,buf);
|
||||
file->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->FilePtr,size,buf);
|
||||
file->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<=file->FileSize){
|
||||
file->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>file->FileSize){
|
||||
offset=file->FileSize;
|
||||
}
|
||||
|
||||
need_cluster = file_requiredCluster(file,offset,size);
|
||||
|
||||
if(need_cluster){
|
||||
if(fat_allocClusterChain(file->fs,&(file->Cache),need_cluster+CLUSTER_PREALLOC_FILE)!=0){
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
while(size_left>0){
|
||||
|
||||
cclus = coffset/(512*file->fs->volumeId.SectorsPerCluster);
|
||||
csec = (coffset/(512))%file->fs->volumeId.SectorsPerCluster;
|
||||
cbyte = coffset%512;
|
||||
|
||||
if(cbyte!=0 || size_left<512){
|
||||
btr = 512-(coffset%512)>=size_left?size_left:512-(coffset%512);
|
||||
}else{
|
||||
btr = 512;
|
||||
}
|
||||
|
||||
if((fat_LogicToDiscCluster(file->fs,&(file->Cache),cclus))!=0){
|
||||
file->FileSize+=bytes_written;
|
||||
dir_setFileSize(file->fs,&(file->Location),file->FileSize);
|
||||
return(bytes_written);
|
||||
}
|
||||
rclus=file->Cache.DiscCluster;
|
||||
rsec=fs_clusterToSector(file->fs,rclus);
|
||||
|
||||
if(btr==512){
|
||||
/*part_writeBuf(file->fs->part,rsec+csec,buf+bytes_written);*/
|
||||
part_directSectorWrite(file->fs->part,rsec+csec,buf+bytes_written);
|
||||
}else{
|
||||
/*part_readBuf(file->fs->part,rsec+csec,tbuf);*/
|
||||
tbuf = part_getSect(file->fs->part,rsec+csec,IOM_MODE_READWRITE);
|
||||
memCpy(buf+bytes_written,tbuf+(coffset%512),btr);
|
||||
/*part_writeBuf(file->fs->part,rsec+csec,tbuf);*/
|
||||
part_relSect(file->fs->part,tbuf);
|
||||
}
|
||||
|
||||
coffset+=btr;
|
||||
bytes_written+=btr;
|
||||
size_left-=btr;
|
||||
}
|
||||
|
||||
if(bytes_written>file->FileSize-offset){
|
||||
file->FileSize+=bytes_written-(file->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->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->DirEntry),sizeof(wtmp));
|
||||
file_initFile(file,fs,&loc);
|
||||
sec=fs_getNextFreeCluster(file->fs,fs_giveFreeClusterHint(file->fs));
|
||||
dir_setFirstCluster(file->fs,&(file->Location),sec);
|
||||
fs_setFirstClusterInDirEntry(&(file->DirEntry),sec);
|
||||
fs_initClusterChain(fs,&(file->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->DirEntry), &loc);
|
||||
file_initFile(file,fs,&loc);
|
||||
if(file->Cache.FirstCluster==0){
|
||||
sec=fs_getNextFreeCluster(file->fs,fs_giveFreeClusterHint(file->fs));
|
||||
dir_setFirstCluster(file->fs,&(file->Location),sec);
|
||||
fs_setFirstClusterInDirEntry(&(file->DirEntry),sec);
|
||||
fat_setNextClusterAddress(fs,sec,fat_giveEocMarker(fs));
|
||||
file_initFile(file,fs,&loc);
|
||||
}
|
||||
file_setpos(file,file->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->DirEntry),sizeof(wtmp));
|
||||
file_initFile(file,fs,&loc);
|
||||
sec=fs_getNextFreeCluster(file->fs,fs_giveFreeClusterHint(file->fs));
|
||||
dir_setFirstCluster(file->fs,&(file->Location),sec);
|
||||
fs_setFirstClusterInDirEntry(&(file->DirEntry),sec);
|
||||
fs_initClusterChain(fs,&(file->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->DirEntry.AccessDate = time_getDate();
|
||||
if(file_getAttr(file,FILE_STATUS_WRITE)){
|
||||
file->DirEntry.FileSize = file->FileSize;
|
||||
file->DirEntry.WriteDate = file->DirEntry.AccessDate;
|
||||
file->DirEntry.WriteTime = time_getTime();
|
||||
}
|
||||
dir_updateDirectoryEntry(file->fs,&(file->DirEntry),&(file->Location));
|
||||
}else{
|
||||
if(file_getAttr(file,FILE_STATUS_WRITE)){
|
||||
dir_setFileSize(file->fs,&(file->Location),file->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->fs=fs;
|
||||
file->FileSize=file->DirEntry.FileSize;
|
||||
file->FilePtr=0;
|
||||
file->Location.Sector=loc->Sector;
|
||||
file->Location.Offset=loc->Offset;
|
||||
file->Cache.Linear=0;
|
||||
file->Cache.FirstCluster=(((euint32)file->DirEntry.FirstClusterHigh)<<16)+
|
||||
file->DirEntry.FirstClusterLow;
|
||||
file->Cache.LastCluster=0;
|
||||
file->Cache.LogicCluster=0;
|
||||
file->Cache.DiscCluster=file->Cache.FirstCluster;
|
||||
|
||||
#warning "non-official ClusterCount=0 patch by Mike Anton active"
|
||||
file->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<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<=10){
|
||||
fatfilename[c]=file_validateChar(*filename);
|
||||
c++;
|
||||
}
|
||||
}else{
|
||||
if(c<=7){
|
||||
fatfilename[c]=file_validateChar(*filename);
|
||||
c++; vc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
filename++;
|
||||
}
|
||||
}
|
||||
|
||||
if(vc>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<0x20) || (c>0x20&&c<0x30&&c!='-') || (c>0x39&&c<0x41) || (c>0x5A&&c<0x61&&c!='_') || (c>0x7A&&c!='~') )
|
||||
return(0x58);
|
||||
if( c>=0x61 && c<=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->FileStatus|=1<<attribute;
|
||||
}else{
|
||||
file->FileStatus&=~(1<<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->FileStatus&(1<<attribute));
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint32 file_requiredCluster(File *file,euint32 offset, euint32 size)
|
||||
{
|
||||
euint32 clusters_required,clustersize;
|
||||
euint32 hc;
|
||||
|
||||
if((offset+size)>file->FileSize){
|
||||
if(file->Cache.ClusterCount==0){ /* Number of cluster unknown */
|
||||
hc = fat_countClustersInChain(file->fs,file->Cache.FirstCluster);
|
||||
file->Cache.ClusterCount = hc;
|
||||
}else{
|
||||
hc = file->Cache.ClusterCount; /* This better be right */
|
||||
}
|
||||
clustersize = file->fs->volumeId.BytesPerSector * file->fs->volumeId.SectorsPerCluster;
|
||||
if((size-file->FileSize+offset)>
|
||||
((hc-((file->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);
|
||||
}
|
||||
523
poc/lpc2148_efsl/src/fs.c
Normal file
523
poc/lpc2148_efsl/src/fs.c
Normal file
@@ -0,0 +1,523 @@
|
||||
/*****************************************************************************\
|
||||
* 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->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->volumeId.BytesPerSector=ex_getb16(buf,0x0B);
|
||||
fs->volumeId.SectorsPerCluster=*((eint8*)(buf+0x0D));
|
||||
fs->volumeId.ReservedSectorCount=ex_getb16(buf,0x0E);
|
||||
fs->volumeId.NumberOfFats=*((eint8*)(buf+0x10));
|
||||
fs->volumeId.RootEntryCount=ex_getb16(buf,0x11);
|
||||
fs->volumeId.SectorCount16=ex_getb16(buf,0x13);
|
||||
fs->volumeId.FatSectorCount16=ex_getb16(buf,0x16);
|
||||
fs->volumeId.SectorCount32=ex_getb32(buf,0x20);
|
||||
fs->volumeId.FatSectorCount32=ex_getb32(buf,0x24);
|
||||
fs->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->volumeId.BytesPerSector!=512)sane=0;
|
||||
/* Check is SPC is valid (multiple of 2, and clustersize >=32KB */
|
||||
if(!((fs->volumeId.SectorsPerCluster == 1 ) |
|
||||
(fs->volumeId.SectorsPerCluster == 2 ) |
|
||||
(fs->volumeId.SectorsPerCluster == 4 ) |
|
||||
(fs->volumeId.SectorsPerCluster == 8 ) |
|
||||
(fs->volumeId.SectorsPerCluster == 16) |
|
||||
(fs->volumeId.SectorsPerCluster == 32) |
|
||||
(fs->volumeId.SectorsPerCluster == 64) ))sane=0;
|
||||
/* Any number of FAT's should be supported... (untested) */
|
||||
/* There should be at least 1 reserved sector */
|
||||
if(fs->volumeId.ReservedSectorCount==0)sane=0;
|
||||
if(fs->volumeId.FatSectorCount16 != 0){
|
||||
if(fs->volumeId.FatSectorCount16 > fs->part->disc->partitions[fs->part->activePartition].numSectors)sane=0;
|
||||
}else{
|
||||
if(fs->volumeId.FatSectorCount32 > fs->part->disc->partitions[fs->part->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->volumeId.RootEntryCount*32) +
|
||||
(fs->volumeId.BytesPerSector - 1)) /
|
||||
fs->volumeId.BytesPerSector;
|
||||
|
||||
if(fs->volumeId.FatSectorCount16 != 0)
|
||||
{
|
||||
fs->FatSectorCount=fs->volumeId.FatSectorCount16;
|
||||
fs->volumeId.FatSectorCount32=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs->FatSectorCount=fs->volumeId.FatSectorCount32;
|
||||
fs->volumeId.FatSectorCount16=0;
|
||||
}
|
||||
|
||||
if(fs->volumeId.SectorCount16!=0)
|
||||
{
|
||||
fs->SectorCount=fs->volumeId.SectorCount16;
|
||||
fs->volumeId.SectorCount32=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs->SectorCount=fs->volumeId.SectorCount32;
|
||||
fs->volumeId.SectorCount16=0;
|
||||
}
|
||||
|
||||
dataSectorCount=fs->SectorCount - (
|
||||
fs->volumeId.ReservedSectorCount +
|
||||
(fs->volumeId.NumberOfFats * fs->FatSectorCount) +
|
||||
rootDirSectors);
|
||||
|
||||
fs->DataClusterCount=dataSectorCount/fs->volumeId.SectorsPerCluster;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void fs_determineFatType(FileSystem *fs)
|
||||
* Description: This function looks af the Dataclustercount and determines the
|
||||
* FAT type. It fills in fs->type.
|
||||
*/
|
||||
void fs_determineFatType(FileSystem *fs)
|
||||
{
|
||||
if(fs->DataClusterCount < 4085)
|
||||
{
|
||||
fs->type=FAT12;
|
||||
fs->volumeId.RootCluster=0;
|
||||
}
|
||||
else if(fs->DataClusterCount < 65525)
|
||||
{
|
||||
fs->type=FAT16;
|
||||
fs->volumeId.RootCluster=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs->type=FAT32;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void fs_findFirstSectorRootDir(FileSystem *fs)
|
||||
* Description: This functions fills in the fs->FirstSectorRootDir field, even
|
||||
* for FAT32, although that is not necessary (because you have FirstClusterRootDir).
|
||||
*/
|
||||
void fs_findFirstSectorRootDir(FileSystem *fs)
|
||||
{
|
||||
if(fs->type==FAT32)
|
||||
fs->FirstSectorRootDir = fs->volumeId.ReservedSectorCount +
|
||||
(fs->volumeId.NumberOfFats*fs->volumeId.FatSectorCount32) +
|
||||
(fs->volumeId.RootCluster-2)*fs->volumeId.SectorsPerCluster;
|
||||
else
|
||||
fs->FirstSectorRootDir = fs->volumeId.ReservedSectorCount +
|
||||
(fs->volumeId.NumberOfFats*fs->volumeId.FatSectorCount16);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void fs_initCurrentDir(FileSystem *fs)
|
||||
{
|
||||
fs->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->type==FAT32)
|
||||
{
|
||||
base=
|
||||
fs->volumeId.ReservedSectorCount+
|
||||
fs->FatSectorCount*fs->volumeId.NumberOfFats;
|
||||
}
|
||||
else
|
||||
{
|
||||
base=
|
||||
fs->volumeId.ReservedSectorCount+
|
||||
fs->FatSectorCount*fs->volumeId.NumberOfFats+
|
||||
fs->volumeId.RootEntryCount/16;
|
||||
}
|
||||
return( base + (cluster-2)*fs->volumeId.SectorsPerCluster );
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Function is unused, but may be usefull */
|
||||
euint32 fs_sectorToCluster(FileSystem *fs,euint32 sector)
|
||||
{
|
||||
eint32 base;
|
||||
|
||||
if(fs->type==FAT32)
|
||||
{
|
||||
base=
|
||||
fs->volumeId.ReservedSectorCount+
|
||||
fs->FatSectorCount*fs->volumeId.NumberOfFats;
|
||||
}
|
||||
else
|
||||
{
|
||||
base=
|
||||
fs->volumeId.ReservedSectorCount+
|
||||
fs->FatSectorCount*fs->volumeId.NumberOfFats+
|
||||
fs->volumeId.RootEntryCount/16;
|
||||
}
|
||||
return(((sector-base)-((sector-base)%fs->volumeId.SectorsPerCluster))/fs->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<fs->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->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->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->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->DiscCluster==0){
|
||||
Cache->DiscCluster=Cache->FirstCluster;
|
||||
Cache->LogicCluster=0;
|
||||
}
|
||||
|
||||
if(Cache->LastCluster==0)
|
||||
{
|
||||
while(fat_getNextClusterChain(fs, Cache)==0)
|
||||
{
|
||||
Cache->LogicCluster+=Cache->Linear;
|
||||
Cache->DiscCluster+=Cache->Linear;
|
||||
Cache->Linear=0;
|
||||
}
|
||||
}
|
||||
return(Cache->LastCluster);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint32 fs_getFirstClusterRootDir(FileSystem *fs)
|
||||
{
|
||||
switch(fs->type){
|
||||
case FAT32:
|
||||
return(fs->volumeId.RootCluster);
|
||||
break;
|
||||
default:
|
||||
return(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void fs_initClusterChain(FileSystem *fs,ClusterChain *cache,euint32 cluster_addr)
|
||||
{
|
||||
cache->FirstCluster=cluster_addr;
|
||||
cache->DiscCluster=cluster_addr;
|
||||
cache->LogicCluster=0;
|
||||
cache->LastCluster=0; /* Warning flag here */
|
||||
cache->Linear=0;
|
||||
cache->ClusterCount=0; /* 0 means NOT known */
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void fs_setFirstClusterInDirEntry(FileRecord *rec,euint32 cluster_addr)
|
||||
{
|
||||
rec->FirstClusterHigh=cluster_addr>>16;
|
||||
rec->FirstClusterLow=cluster_addr&0xFFFF;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 fs_flushFs(FileSystem *fs)
|
||||
{
|
||||
return(part_flushPart(fs->part,0,fs->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<(fs->volumeId.SectorsPerCluster);c++){
|
||||
buf = part_getSect(fs->part,fs_clusterToSector(fs,cluster)+c,IOM_MODE_READWRITE);
|
||||
memClr(buf,512);
|
||||
part_relSect(fs->part,buf);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
esint8 fs_getFsInfo(FileSystem *fs,euint8 force_update)
|
||||
{
|
||||
euint8 *buf;
|
||||
|
||||
if(!fs->type==FAT32)return(0);
|
||||
buf = part_getSect(fs->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->part,buf);
|
||||
return(-1);
|
||||
}
|
||||
fs->FreeClusterCount = ex_getb32(buf,488);
|
||||
fs->NextFreeCluster = ex_getb32(buf,492);
|
||||
part_relSect(fs->part,buf);
|
||||
if(force_update){
|
||||
fs->FreeClusterCount=fat_countFreeClusters(fs);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
esint8 fs_setFsInfo(FileSystem *fs)
|
||||
{
|
||||
euint8* buf;
|
||||
|
||||
if(!fs->type==FAT32)return(0);
|
||||
buf = part_getSect(fs->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->part,buf);
|
||||
return(-1);
|
||||
}
|
||||
ex_setb32(buf,488,fs->FreeClusterCount);
|
||||
ex_setb32(buf,492,fs->NextFreeCluster);
|
||||
part_relSect(fs->part,buf);
|
||||
return(0);
|
||||
}
|
||||
|
||||
270
poc/lpc2148_efsl/src/interfaces/at91_spi.c
Normal file
270
poc/lpc2148_efsl/src/interfaces/at91_spi.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*****************************************************************************\
|
||||
* 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 -> implement "DMA"
|
||||
- use 16-bit mode
|
||||
- check CPOL
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
#include "interfaces/AT91SAM7S_regs.h"
|
||||
#include "config.h"
|
||||
#include "interfaces/arm_spi.h"
|
||||
#include "interfaces/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<<0)|(1<<1)|(1<<2)|(1<<3))
|
||||
#define PCS_1 ((1<<1)|(0<<1)|(1<<2)|(1<<3))
|
||||
#define PCS_2 ((1<<1)|(1<<1)|(0<<2)|(1<<3))
|
||||
#define PCS_3 ((1<<1)|(1<<1)|(1<<2)|(0<<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)<0) {
|
||||
DBG((TXT("Card failed to init, breaking up...\n")));
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(sd_State(file)<0){
|
||||
DBG((TXT("Card didn't return the ready state, breaking up...\n")));
|
||||
return(-2);
|
||||
}
|
||||
|
||||
/* file->sectorCount=4; */ /* FIXME ASAP!! */
|
||||
/* mthomas: - somehow done - see below */
|
||||
|
||||
sd_getDriveSize(file, &sc);
|
||||
file->sectorCount = sc/512;
|
||||
if( (sc%512) != 0) {
|
||||
file->sectorCount--;
|
||||
}
|
||||
DBG((TXT("Card Capacity is %lu Bytes (%lu Sectors)\n"), sc, file->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->PIO_PDR = AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK; // | NCPS_PDR_BIT;
|
||||
// set pin-functions in PIO Controller
|
||||
pPIOA->PIO_ASR = AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK; /// not here: | NCPS_ASR_BIT;
|
||||
/// not here: pPIOA->PIO_BSR = NPCS_BSR_BIT;
|
||||
|
||||
// set chip-select as output high (unselect card)
|
||||
pPIOA->PIO_PER = NCPS_PDR_BIT; // enable GPIO of CS-pin
|
||||
pPIOA->PIO_SODR = NCPS_PDR_BIT; // set high
|
||||
pPIOA->PIO_OER = NCPS_PDR_BIT; // output enable
|
||||
|
||||
// enable peripheral clock for SPI ( PID Bit 5 )
|
||||
pPMC->PMC_PCER = ( (euint32) 1 << AT91C_ID_SPI ); // n.b. IDs are just bit-numbers
|
||||
|
||||
// SPI enable and reset
|
||||
pSPI->SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_SWRST;
|
||||
|
||||
#ifdef FIXED_PERIPH
|
||||
// SPI mode: master, fixed periph. sel., FDIV=0, fault detection disabled
|
||||
pSPI->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | AT91C_SPI_MODFDIS;
|
||||
// set PCS for fixed select
|
||||
// pSPI->SPI_MR &= 0xFFF0FFFF; // clear old PCS - redundant (AT91lib)
|
||||
pSPI->SPI_MR |= ( (SPI_MR_PCS<<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->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->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | AT91C_SPI_NCPHA;
|
||||
// not working pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_BITS_8 | AT91C_SPI_NCPHA;
|
||||
pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8;
|
||||
// not working pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_BITS_8;
|
||||
|
||||
// slow during init
|
||||
if_spiSetSpeed(0xFE);
|
||||
|
||||
// enable
|
||||
pSPI->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->PDC_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
|
||||
pSPI->SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
|
||||
#endif
|
||||
|
||||
/* Send 20 spi commands with card not selected */
|
||||
for(i=0;i<21;i++) {
|
||||
if_spiSend(iface,0xFF);
|
||||
}
|
||||
|
||||
/* enable automatic chip-select */
|
||||
// reset PIO-registers of CS-pin to default
|
||||
pPIOA->PIO_ODR = NCPS_PDR_BIT; // input
|
||||
pPIOA->PIO_CODR = NCPS_PDR_BIT; // clear
|
||||
// disable PIO from controlling the CS pin (=hand over to SPI)
|
||||
pPIOA->PIO_PDR = NCPS_PDR_BIT;
|
||||
// set pin-functions in PIO Controller (function NCPS for CS-pin)
|
||||
pPIOA->PIO_ASR = NCPS_ASR_BIT;
|
||||
pPIOA->PIO_BSR = NPCS_BSR_BIT;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void if_spiSetSpeed(euint8 speed)
|
||||
{
|
||||
euint32 reg;
|
||||
AT91PS_SPI pSPI = AT91C_BASE_SPI;
|
||||
|
||||
if ( speed < SPI_SCBR_MIN ) speed = SPI_SCBR_MIN;
|
||||
if ( speed > 1 ) speed &= 0xFE;
|
||||
|
||||
reg = pSPI->SPI_CSR[SPI_CSR_NUM];
|
||||
reg = ( reg & ~(AT91C_SPI_SCBR) ) | ( (euint32)speed << 8 );
|
||||
pSPI->SPI_CSR[SPI_CSR_NUM] = reg;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 if_spiSend(hwInterface *iface, euint8 outgoing)
|
||||
{
|
||||
euint8 incoming;
|
||||
|
||||
AT91PS_SPI pSPI = AT91C_BASE_SPI;
|
||||
|
||||
while( !( pSPI->SPI_SR & AT91C_SPI_TDRE ) ); // transfer compl. wait
|
||||
#ifdef FIXED_PERIPH
|
||||
pSPI->SPI_TDR = (euint16)( outgoing );
|
||||
#else
|
||||
pSPI->SPI_TDR = ( (euint16)(outgoing) | ((euint32)(SPI_TDR_PCS)<<16) );
|
||||
#endif
|
||||
|
||||
while( !( pSPI->SPI_SR & AT91C_SPI_RDRF ) ); // wait for char
|
||||
incoming = (euint8)( pSPI->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);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
110
poc/lpc2148_efsl/src/interfaces/atmega128.c
Normal file
110
poc/lpc2148_efsl/src/interfaces/atmega128.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : atmega128.c *
|
||||
* Description : This file contains the functions needed to use efs for *
|
||||
* accessing files on an SD-card connected to an ATMega128. *
|
||||
* *
|
||||
* 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 "interfaces/atmega128.h"
|
||||
#include "interfaces/sd.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 if_initInterface(hwInterface* file, eint8* opts)
|
||||
{
|
||||
if_spiInit(file);
|
||||
if(sd_Init(file)<0) {
|
||||
DBG((TXT("Card failed to init, breaking up...\n")));
|
||||
return(-1);
|
||||
}
|
||||
if(sd_State(file)<0){
|
||||
DBG((TXT("Card didn't return the ready state, breaking up...\n")));
|
||||
return(-2);
|
||||
}
|
||||
file->sectorCount=4; /* FIXME ASAP!! */
|
||||
DBG((TXT("Init done...\n")));
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
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);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void if_spiInit(hwInterface *iface)
|
||||
{
|
||||
euint8 i;
|
||||
|
||||
/* Unselect card */
|
||||
PORTB |= 0x01;
|
||||
|
||||
/* Set as master, clock and chip select output */
|
||||
DDR_SPI = (1<<DD_MOSI) | (1<<DD_SCK) | 1;
|
||||
|
||||
/* Enable SPI, master, set clock rate to fck/2 */
|
||||
SPCR = (1<<SPE) | (1<<MSTR); /* fsck / 4 */
|
||||
SPSR = 1; /* fsck / 2 */
|
||||
|
||||
/* Send 10 spi commands with card not selected */
|
||||
for(i=0;i<10;i++)
|
||||
if_spiSend(iface,0xff);
|
||||
|
||||
/* Select card */
|
||||
PORTB &= 0xFE;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 if_spiSend(hwInterface *iface, euint8 outgoing)
|
||||
{
|
||||
euint8 incoming=0;
|
||||
|
||||
PORTB &= 0xFE;
|
||||
SPDR = outgoing;
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
incoming = SPDR;
|
||||
PORTB |= 0x01;
|
||||
|
||||
return(incoming);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
93
poc/lpc2148_efsl/src/interfaces/dsp67xx.c
Normal file
93
poc/lpc2148_efsl/src/interfaces/dsp67xx.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : dsp67xx.c *
|
||||
* Revision : Initial developement *
|
||||
* Description : This file contains the functions needed to use efs for *
|
||||
* accessing files on an SD-card connected to a TI 67 *
|
||||
* series DSP. *
|
||||
* *
|
||||
* 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 "interfaces/dsp67xx.h"
|
||||
#include "interfaces/sd.h"
|
||||
#include <stdio.h>
|
||||
/*****************************************************************************/
|
||||
|
||||
short if_initInterface(hwInterface* file, char* opts)
|
||||
{
|
||||
file->sectorCount=0;
|
||||
return(if_spiInit(file));
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
short if_writeBuf(hwInterface* file,unsigned long address,unsigned char* buf)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
short if_setPos(hwInterface* file,unsigned long address)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
signed char if_spiInit(hwInterface *iface)
|
||||
{
|
||||
return(sd_Init(iface));
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned char if_spiSend(hwInterface *iface, euint8 outgoing)
|
||||
{
|
||||
unsigned char r;
|
||||
|
||||
/* while((*(unsigned volatile long*)McBSP0_SPCR & 0x20000)==0);
|
||||
*(unsigned volatile char*)McBSP0_DXR=outgoing;
|
||||
while(((*(unsigned volatile long*)McBSP0_SPCR & 0x2)==0));
|
||||
r=*(unsigned volatile char*)McBSP0_DRR; */
|
||||
|
||||
while(!MCBSP_xrdy(iface->port->hBsp));
|
||||
MCBSP_write(iface->port->hBsp,outgoing);
|
||||
while(!MCBSP_rrdy(iface->port->hBsp));
|
||||
r=MCBSP_read(iface->port->hBsp);
|
||||
|
||||
return(r);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
short if_readBuf(hwInterface* file,euint32 address,unsigned char* buf)
|
||||
{
|
||||
short r;
|
||||
r=sd_readSector(file,address,buf,512);
|
||||
if(r!=0)printf("ERROR READING SECTOR %i\n",address);
|
||||
return(r);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
243
poc/lpc2148_efsl/src/interfaces/efsl_dbg_printf_arm.c
Normal file
243
poc/lpc2148_efsl/src/interfaces/efsl_dbg_printf_arm.c
Normal file
@@ -0,0 +1,243 @@
|
||||
//#########################################################################
|
||||
// printf.c
|
||||
//
|
||||
// *** printf() based on sprintf() from gcctest9.c Volker Oth
|
||||
//
|
||||
// *** Changes made by Holger Klabunde
|
||||
// Now takes format strings from FLASH (was into RAM ! before)
|
||||
// Fixed bug for %i, %I. u_val was used before it had the right value
|
||||
// Added %d, %D (is same as %i, %I)
|
||||
// Support for long variables %li, %ld, %Lu, %LX ....
|
||||
// %x, %X now gives upper case hex characters A,B,C,D,E,F
|
||||
// Output can be redirected in a single function: myputchar()
|
||||
// Make printf() smaller by commenting out a few #defines
|
||||
// Added some SPACE and ZERO padding %02x or % 3u up to 9 characters
|
||||
//
|
||||
// Todo:
|
||||
// %f, %F for floating point numbers
|
||||
//
|
||||
// *** Changes made by Martin Thomas for the efsl debug output:
|
||||
// - removed AVR "progmem"
|
||||
// - added function pointer for "putchar"
|
||||
// - devopen function
|
||||
//
|
||||
//#########################################################################
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "interfaces/efsl_dbg_printf_arm.h"
|
||||
|
||||
#define SCRATCH 12 //32Bits go up to 4GB + 1 Byte for \0
|
||||
|
||||
//Spare some program space by making a comment of all not used format flag lines
|
||||
#define USE_LONG // %lx, %Lu and so on, else only 16 bit integer is allowed
|
||||
//#define USE_OCTAL // %o, %O Octal output. Who needs this ?
|
||||
#define USE_STRING // %s, %S Strings as parameters
|
||||
#define USE_CHAR // %c, %C Chars as parameters
|
||||
#define USE_INTEGER // %i, %I Remove this format flag. %d, %D does the same
|
||||
#define USE_HEX // %x, %X Hexadezimal output
|
||||
#define USE_UPPERHEX // %x, %X outputs A,B,C... else a,b,c...
|
||||
#ifndef USE_HEX
|
||||
#undef USE_UPPERHEX // ;)
|
||||
#endif
|
||||
#define USE_UPPER // uncommenting this removes %C,%D,%I,%O,%S,%U,%X and %L..
|
||||
// only lowercase format flags are used
|
||||
#define PADDING //SPACE and ZERO padding
|
||||
|
||||
|
||||
static int (*putcharfunc)(int c);
|
||||
|
||||
void efsl_debug_devopen_arm( int(*put)(int) )
|
||||
{
|
||||
putcharfunc = put;
|
||||
}
|
||||
|
||||
static void myputchar(unsigned char c)
|
||||
{
|
||||
if(c == '\n') putcharfunc('\r');
|
||||
putcharfunc(c);
|
||||
}
|
||||
|
||||
void efsl_debug_printf_arm(char const *format, ...)
|
||||
{
|
||||
unsigned char scratch[SCRATCH];
|
||||
unsigned char format_flag;
|
||||
unsigned short base;
|
||||
unsigned char *ptr;
|
||||
unsigned char issigned=0;
|
||||
va_list ap;
|
||||
|
||||
#ifdef USE_LONG
|
||||
unsigned char islong=0;
|
||||
unsigned long u_val=0;
|
||||
long s_val=0;
|
||||
#else
|
||||
unsigned int u_val=0;
|
||||
int s_val=0;
|
||||
#endif
|
||||
|
||||
unsigned char fill;
|
||||
unsigned char width;
|
||||
|
||||
va_start (ap, format);
|
||||
for (;;){
|
||||
while ((format_flag = *(format++)) != '%'){ // Until '%' or '\0'
|
||||
if (!format_flag){va_end (ap); return;}
|
||||
myputchar(format_flag);
|
||||
}
|
||||
|
||||
issigned=0; //default unsigned
|
||||
base = 10;
|
||||
|
||||
format_flag = *format++; //get char after '%'
|
||||
|
||||
#ifdef PADDING
|
||||
width=0; //no formatting
|
||||
fill=0; //no formatting
|
||||
if(format_flag=='0' || format_flag==' ') //SPACE or ZERO padding ?
|
||||
{
|
||||
fill=format_flag;
|
||||
format_flag = *format++; //get char after padding char
|
||||
if(format_flag>='0' && format_flag<='9')
|
||||
{
|
||||
width=format_flag-'0';
|
||||
format_flag = *format++; //get char after width char
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LONG
|
||||
islong=0; //default int value
|
||||
#ifdef USE_UPPER
|
||||
if(format_flag=='l' || format_flag=='L') //Long value
|
||||
#else
|
||||
if(format_flag=='l') //Long value
|
||||
#endif
|
||||
{
|
||||
islong=1;
|
||||
format_flag = *format++; //get char after 'l' or 'L'
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (format_flag)
|
||||
{
|
||||
#ifdef USE_CHAR
|
||||
case 'c':
|
||||
#ifdef USE_UPPER
|
||||
case 'C':
|
||||
#endif
|
||||
format_flag = va_arg(ap,int);
|
||||
// no break -> run into default
|
||||
#endif
|
||||
|
||||
default:
|
||||
myputchar(format_flag);
|
||||
continue;
|
||||
|
||||
#ifdef USE_STRING
|
||||
#ifdef USE_UPPER
|
||||
case 'S':
|
||||
#endif
|
||||
case 's':
|
||||
ptr = (unsigned char*)va_arg(ap,char *);
|
||||
while(*ptr) { myputchar(*ptr); ptr++; }
|
||||
continue;
|
||||
#endif
|
||||
|
||||
#ifdef USE_OCTAL
|
||||
case 'o':
|
||||
#ifdef USE_UPPER
|
||||
case 'O':
|
||||
#endif
|
||||
base = 8;
|
||||
myputchar('0');
|
||||
goto CONVERSION_LOOP;
|
||||
#endif
|
||||
|
||||
#ifdef USE_INTEGER //don't use %i, is same as %d
|
||||
case 'i':
|
||||
#ifdef USE_UPPER
|
||||
case 'I':
|
||||
#endif
|
||||
#endif
|
||||
case 'd':
|
||||
#ifdef USE_UPPER
|
||||
case 'D':
|
||||
#endif
|
||||
issigned=1;
|
||||
// no break -> run into next case
|
||||
case 'u':
|
||||
#ifdef USE_UPPER
|
||||
case 'U':
|
||||
#endif
|
||||
|
||||
//don't insert some case below this if USE_HEX is undefined !
|
||||
//or put goto CONVERSION_LOOP; before next case.
|
||||
#ifdef USE_HEX
|
||||
goto CONVERSION_LOOP;
|
||||
case 'x':
|
||||
#ifdef USE_UPPER
|
||||
case 'X':
|
||||
#endif
|
||||
base = 16;
|
||||
#endif
|
||||
|
||||
CONVERSION_LOOP:
|
||||
|
||||
if(issigned) //Signed types
|
||||
{
|
||||
#ifdef USE_LONG
|
||||
if(islong) { s_val = va_arg(ap,long); }
|
||||
else { s_val = va_arg(ap,int); }
|
||||
#else
|
||||
s_val = va_arg(ap,int);
|
||||
#endif
|
||||
|
||||
if(s_val < 0) //Value negativ ?
|
||||
{
|
||||
s_val = - s_val; //Make it positiv
|
||||
myputchar('-'); //Output sign
|
||||
}
|
||||
|
||||
u_val = (unsigned long)s_val;
|
||||
}
|
||||
else //Unsigned types
|
||||
{
|
||||
#ifdef USE_LONG
|
||||
if(islong) { u_val = va_arg(ap,unsigned long); }
|
||||
else { u_val = va_arg(ap,unsigned int); }
|
||||
#else
|
||||
u_val = va_arg(ap,unsigned int);
|
||||
#endif
|
||||
}
|
||||
|
||||
ptr = scratch + SCRATCH;
|
||||
*--ptr = 0;
|
||||
do
|
||||
{
|
||||
char ch = u_val % base + '0';
|
||||
#ifdef USE_HEX
|
||||
if (ch > '9')
|
||||
{
|
||||
ch += 'a' - '9' - 1;
|
||||
#ifdef USE_UPPERHEX
|
||||
ch-=0x20;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
*--ptr = ch;
|
||||
u_val /= base;
|
||||
|
||||
#ifdef PADDING
|
||||
if(width) width--; //calculate number of padding chars
|
||||
#endif
|
||||
} while (u_val);
|
||||
|
||||
#ifdef PADDING
|
||||
while(width--) *--ptr = fill; //insert padding chars
|
||||
#endif
|
||||
|
||||
while(*ptr) { myputchar(*ptr); ptr++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
94
poc/lpc2148_efsl/src/interfaces/helper.c
Normal file
94
poc/lpc2148_efsl/src/interfaces/helper.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : helper.c *
|
||||
* Description : These functions may NOT BE USED ANYWHERE ! They are helper *
|
||||
* functions for the Linux based developement. They use the GNU *
|
||||
* C library and headers. *
|
||||
* *
|
||||
* 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 "interfaces/helper.h"
|
||||
|
||||
void* Malloc(eint32 size)
|
||||
{
|
||||
void*x;
|
||||
|
||||
if((x=malloc(size))==NULL){
|
||||
perror("Malloc: ");
|
||||
exit(-1);
|
||||
}
|
||||
return(x);
|
||||
}
|
||||
|
||||
void Fopen(FILE **f,eint8* filename)
|
||||
{
|
||||
*f=fopen(filename,"r+");
|
||||
if(*f==NULL){
|
||||
perror("Fopen: ");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void MMap(eint8* filename,void**x,eint32 *size)
|
||||
{
|
||||
FILE *tmp;
|
||||
eint32 filesize,c;
|
||||
|
||||
Fopen(&tmp,filename);
|
||||
filesize=getFileSize(tmp);
|
||||
*x=Malloc(filesize);
|
||||
for(c=0;c<filesize;c++)*((char*)(*x)+c)=fgetc(tmp);
|
||||
*size=filesize;
|
||||
fclose(tmp);
|
||||
}
|
||||
|
||||
int getFileSize(FILE* file)
|
||||
{
|
||||
eint32 c=0;
|
||||
|
||||
fseek(file,0,SEEK_END);
|
||||
c=ftell(file);
|
||||
return(c);
|
||||
}
|
||||
|
||||
void PrintBuf(euint8* buf)
|
||||
{
|
||||
euint16 c,cc;
|
||||
|
||||
for(c=0 ; c<32 ; c++){
|
||||
printf("\n%4x : ",c*16);
|
||||
for(cc=0;cc<16;cc++){
|
||||
printf("%2x ",buf[c*16+cc]);
|
||||
}
|
||||
printf(" ");
|
||||
for(cc=0;cc<16;cc++){
|
||||
printf("%c",buf[c*16+cc]>=32?buf[c*16+cc]:'*');
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
112
poc/lpc2148_efsl/src/interfaces/linuxfile.c
Normal file
112
poc/lpc2148_efsl/src/interfaces/linuxfile.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : linuxfile.c *
|
||||
* Description : This file contains the functions needed to use efs for *
|
||||
* accessing files under linux. This interface is meant *
|
||||
* to be used for debugging purposes. *
|
||||
* *
|
||||
* 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 "interfaces/linuxfile.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* short if_initInterface(hwInterface* file, char* fileName)
|
||||
* Description: This function should bring the hardware described in file in a
|
||||
* ready state to receive and retrieve data.
|
||||
* Return value: Return 0 on succes and -1 on failure.
|
||||
*/
|
||||
esint8 if_initInterface(hwInterface* file, eint8* fileName)
|
||||
{
|
||||
eint32 sc;
|
||||
Fopen(&(file->imageFile),fileName);
|
||||
sc=getFileSize(file->imageFile);
|
||||
file->sectorCount=sc/512;
|
||||
file->readCount=file->writeCount=0;
|
||||
if(sc%512!=0)
|
||||
file->sectorCount--;
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* short if_readBuf(hwInterface* file,unsigned long address,unsigned char* buf)
|
||||
* Description: This function should fill the characterpointer buf with 512
|
||||
* bytes, offset by address*512 bytes. Adress is thus a LBA address.
|
||||
* Return value: Return 0 on success and -1 on failure.
|
||||
*/
|
||||
esint8 if_readBuf(hwInterface* file,euint32 address,euint8* buf)
|
||||
{
|
||||
/*printf("READ %li\n",address);*/
|
||||
if(if_setPos(file,address))return(-1);
|
||||
if( fread((void*)buf,512,1,file->imageFile) != 1) return(-1);
|
||||
file->readCount++;
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* short if_writeBuf(hwInterface* file,unsigned long address,unsigned char* buf)
|
||||
* Description: This function writes 512 bytes from uchar* buf to the hardware
|
||||
* disc described in file. The write offset should be address sectors of 512 bytes.
|
||||
* Return value: Return 0 on success and -1 on failure.
|
||||
*/
|
||||
esint8 if_writeBuf(hwInterface* file,euint32 address,euint8* buf)
|
||||
{
|
||||
/*printf("WRITE %li\n",address);*/
|
||||
if_setPos(file,address);
|
||||
if((fwrite((void*)buf,512,1,file->imageFile))!=1){
|
||||
perror("cf_writeBuf:");
|
||||
exit(-1);
|
||||
}
|
||||
fflush(file->imageFile);
|
||||
file->writeCount++;
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* short if_setPos(hwInterface* file,unsigned long address)
|
||||
* Description: This function may or may not be required. It would set the write
|
||||
* or read buffer offset by 512*address bytes from the beginning of the disc.
|
||||
* Return value: Return 0 on success and -1 on failure.
|
||||
*/
|
||||
esint8 if_setPos(hwInterface* file,euint32 address)
|
||||
{
|
||||
if(address>(file->sectorCount-1)){
|
||||
DBG((TXT("Illegal address\n")));
|
||||
exit(-1);
|
||||
}
|
||||
if((fseek(file->imageFile,512*address,SEEK_SET))!=0){
|
||||
perror("cf_setPos:");
|
||||
exit(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
291
poc/lpc2148_efsl/src/interfaces/lpc2000_spi.c
Normal file
291
poc/lpc2148_efsl/src/interfaces/lpc2000_spi.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : lpc2000_spi.c *
|
||||
* Description : This file contains the functions needed to use efs for *
|
||||
* accessing files on an SD-card connected to an LPC2xxx. *
|
||||
* *
|
||||
* 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)2005 Martin Thomas *
|
||||
\*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
#include "interfaces/LPC2000_regs.h"
|
||||
#include "interfaces/arm_spi.h"
|
||||
#include "interfaces/sd.h"
|
||||
#include "config.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef HW_ENDPOINT_LPC2000_SPINUM
|
||||
#error "HW_ENDPOINT_LPC2000_SPINUM has to be defined in config.h"
|
||||
#endif
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 0 )
|
||||
// LPC213x ### SPI0 ###
|
||||
|
||||
// SP0SPCR Bit-Definitions
|
||||
#define CPHA 3
|
||||
#define CPOL 4
|
||||
#define MSTR 5
|
||||
// SP0SPSR Bit-Definitions
|
||||
#define SPIF 7
|
||||
|
||||
#define SPI_IODIR IODIR0
|
||||
#define SPI_SCK_PIN 4 /* Clock P0.4 out */
|
||||
#define SPI_MISO_PIN 5 /* from Card P0.5 in */
|
||||
#define SPI_MOSI_PIN 6 /* to Card P0.6 out */
|
||||
#define SPI_SS_PIN 7 /* Card-Select P0.7 - GPIO out */
|
||||
|
||||
#define SPI_PINSEL PINSEL0
|
||||
#define SPI_SCK_FUNCBIT 8
|
||||
#define SPI_MISO_FUNCBIT 10
|
||||
#define SPI_MOSI_FUNCBIT 12
|
||||
#define SPI_SS_FUNCBIT 14
|
||||
|
||||
#define SPI_PRESCALE_REG S0SPCCR
|
||||
#define SPI_PRESCALE_MIN 8
|
||||
|
||||
#define SELECT_CARD() IOCLR0 = (1<<SPI_SS_PIN)
|
||||
#define UNSELECT_CARD() IOSET0 = (1<<SPI_SS_PIN)
|
||||
|
||||
#elif ( HW_ENDPOINT_LPC2000_SPINUM == 1 )
|
||||
// LPC213x ### SSP ### ("SPI1")
|
||||
|
||||
// SSPCR0 Bit-Definitions
|
||||
#define CPOL 6
|
||||
#define CPHA 7
|
||||
// SSPCR1 Bit-Defintions
|
||||
#define SSE 1
|
||||
#define MS 2
|
||||
#define SCR 8
|
||||
// SSPSR Bit-Definitions
|
||||
#define TNF 1
|
||||
#define RNE 2
|
||||
#define BSY 4
|
||||
|
||||
#define SPI_IODIR IODIR0
|
||||
#define SPI_SCK_PIN 17 /* Clock P0.17 out */
|
||||
#define SPI_MISO_PIN 18 /* from Card P0.18 in */
|
||||
#define SPI_MOSI_PIN 19 /* to Card P0.19 out */
|
||||
/* Card-Select P0.20 - GPIO out during startup
|
||||
Function 03 during normal operation */
|
||||
#define SPI_SS_PIN 20
|
||||
|
||||
#define SPI_PINSEL PINSEL1
|
||||
#define SPI_SCK_FUNCBIT 2
|
||||
#define SPI_MISO_FUNCBIT 4
|
||||
#define SPI_MOSI_FUNCBIT 6
|
||||
#define SPI_SS_FUNCBIT 8
|
||||
|
||||
#define SPI_PRESCALE_REG SSPCPSR
|
||||
/// TODO: too fast on prototyp wires #define SPI_PRESCALE_MIN 2
|
||||
#define SPI_PRESCALE_MIN 4
|
||||
|
||||
/* only needed during init: */
|
||||
#define SELECT_CARD() IOCLR0 = (1<<SPI_SS_PIN)
|
||||
#define UNSELECT_CARD() IOSET0 = (1<<SPI_SS_PIN)
|
||||
|
||||
|
||||
#else
|
||||
#error "Invalid Interface-Number"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
esint8 if_initInterface(hwInterface* file, eint8* opts)
|
||||
{
|
||||
euint32 sc;
|
||||
|
||||
if_spiInit(file); /* init at low speed */
|
||||
|
||||
if(sd_Init(file)<0) {
|
||||
DBG((TXT("Card failed to init, breaking up...\n")));
|
||||
return(-1);
|
||||
}
|
||||
if(sd_State(file)<0){
|
||||
DBG((TXT("Card didn't return the ready state, breaking up...\n")));
|
||||
return(-2);
|
||||
}
|
||||
|
||||
// file->sectorCount=4; /* FIXME ASAP!! */
|
||||
|
||||
sd_getDriveSize(file, &sc);
|
||||
file->sectorCount = sc/512;
|
||||
if( (sc%512) != 0) {
|
||||
file->sectorCount--;
|
||||
}
|
||||
DBG((TXT("Drive Size is %lu Bytes (%lu Sectors)\n"), sc, file->sectorCount));
|
||||
|
||||
/* increase speed after init */
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 1 )
|
||||
SSPCR0 = ((8-1)<<0) | (0<<CPOL);
|
||||
#endif
|
||||
if_spiSetSpeed(SPI_PRESCALE_MIN);
|
||||
// if_spiSetSpeed(100); /* debug - slower */
|
||||
|
||||
DBG((TXT("Init done...\n")));
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
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);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
// Utility-functions which does not toogle CS.
|
||||
// Only needed during card-init. During init
|
||||
// the automatic chip-select is disabled for SSP
|
||||
|
||||
static euint8 my_if_spiSend(hwInterface *iface, euint8 outgoing)
|
||||
{
|
||||
euint8 incoming;
|
||||
|
||||
// SELECT_CARD(); // not here!
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 0 )
|
||||
S0SPDR = outgoing;
|
||||
while( !(S0SPSR & (1<<SPIF)) ) ;
|
||||
incoming = S0SPDR;
|
||||
#endif
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 1 )
|
||||
while( !(SSPSR & (1<<TNF)) ) ;
|
||||
SSPDR = outgoing;
|
||||
while( !(SSPSR & (1<<RNE)) ) ;
|
||||
incoming = SSPDR;
|
||||
#endif
|
||||
|
||||
// UNSELECT_CARD(); // not here!
|
||||
|
||||
return(incoming);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void if_spiInit(hwInterface *iface)
|
||||
{
|
||||
euint8 i;
|
||||
|
||||
// setup GPIO
|
||||
SPI_IODIR |= (1<<SPI_SCK_PIN)|(1<<SPI_MOSI_PIN)|(1<<SPI_SS_PIN);
|
||||
SPI_IODIR &= ~(1<<SPI_MISO_PIN);
|
||||
|
||||
// set Chip-Select high - unselect card
|
||||
UNSELECT_CARD();
|
||||
|
||||
// reset Pin-Functions
|
||||
SPI_PINSEL &= ~( (3<<SPI_SCK_FUNCBIT) | (3<<SPI_MISO_FUNCBIT) |
|
||||
(3<<SPI_MOSI_FUNCBIT) | (3<<SPI_SS_FUNCBIT) );
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 0 )
|
||||
DBG((TXT("spiInit for SPI(0)\n")));
|
||||
SPI_PINSEL |= ( (1<<SPI_SCK_FUNCBIT) | (1<<SPI_MISO_FUNCBIT) |
|
||||
(1<<SPI_MOSI_FUNCBIT) );
|
||||
// enable SPI-Master
|
||||
S0SPCR = (1<<MSTR)|(0<<CPOL); // TODO: check CPOL
|
||||
#endif
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 1 )
|
||||
DBG((TXT("spiInit for SSP/SPI1\n")));
|
||||
// setup Pin-Functions - keep automatic CS disabled during init
|
||||
SPI_PINSEL |= ( (2<<SPI_SCK_FUNCBIT) | (2<<SPI_MISO_FUNCBIT) |
|
||||
(2<<SPI_MOSI_FUNCBIT) | (0<<SPI_SS_FUNCBIT) );
|
||||
// enable SPI-Master - slowest speed
|
||||
SSPCR0 = ((8-1)<<0) | (0<<CPOL) | (0x20<<SCR); // (0xff<<SCR);
|
||||
SSPCR1 = (1<<SSE);
|
||||
#endif
|
||||
|
||||
// low speed during init
|
||||
if_spiSetSpeed(254);
|
||||
|
||||
/* Send 20 spi commands with card not selected */
|
||||
for(i=0;i<21;i++)
|
||||
my_if_spiSend(iface,0xff);
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 0 )
|
||||
// SPI0 does not offer automatic CS for slaves on LPC2138
|
||||
// ( the SSEL-Pin is input-only )
|
||||
// SELECT_CARD();
|
||||
#endif
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 1 )
|
||||
// enable automatic slave CS for SSP
|
||||
SSPCR1 &= ~(1<<SSE); // disable interface
|
||||
SPI_PINSEL |= ( (2<<SPI_SCK_FUNCBIT) | (2<<SPI_MISO_FUNCBIT) |
|
||||
(2<<SPI_MOSI_FUNCBIT) | (2<<SPI_SS_FUNCBIT) );
|
||||
SSPCR1 |= (1<<SSE); // enable interface
|
||||
#endif
|
||||
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void if_spiSetSpeed(euint8 speed)
|
||||
{
|
||||
speed &= 0xFE;
|
||||
if ( speed < SPI_PRESCALE_MIN ) speed = SPI_PRESCALE_MIN ;
|
||||
SPI_PRESCALE_REG = speed;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 if_spiSend(hwInterface *iface, euint8 outgoing)
|
||||
{
|
||||
euint8 incoming;
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 0 )
|
||||
SELECT_CARD();
|
||||
S0SPDR = outgoing;
|
||||
while( !(S0SPSR & (1<<SPIF)) ) ;
|
||||
incoming = S0SPDR;
|
||||
UNSELECT_CARD();
|
||||
#endif
|
||||
|
||||
#if ( HW_ENDPOINT_LPC2000_SPINUM == 1 )
|
||||
// SELECT_CARD(); // done by hardware
|
||||
while( !(SSPSR & (1<<TNF)) ) ;
|
||||
SSPDR = outgoing;
|
||||
while( !(SSPSR & (1<<RNE)) ) ;
|
||||
incoming = SSPDR;
|
||||
// UNSELECT_CARD(); // done by hardware
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
return(incoming);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
124
poc/lpc2148_efsl/src/interfaces/nios2.c
Normal file
124
poc/lpc2148_efsl/src/interfaces/nios2.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : nios2.c *
|
||||
* Description : This file contains the functions needed to use efs for *
|
||||
* accessing files on an SD-card connected to an Altera FPGA *
|
||||
* running on NIOS2. *
|
||||
* *
|
||||
* 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)2005 Marcio Troccoli *
|
||||
\*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
#include "interfaces/nios2.h"
|
||||
#include "interfaces/sd.h"
|
||||
|
||||
#include "altera_avalon_spi_regs.h"
|
||||
#include "altera_avalon_spi.h"
|
||||
#include "system.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 if_initInterface(hwInterface* file, eint8* opts)
|
||||
{
|
||||
if_spiInit(file);
|
||||
if(sd_Init(file)<0) {
|
||||
DBG((TXT("Card failed to init, breaking up...\n")));
|
||||
return(-1);
|
||||
}
|
||||
if(sd_State(file)<0){
|
||||
DBG((TXT("Card didn't return the ready state, breaking up...\n")));
|
||||
return(-2);
|
||||
}
|
||||
file->sectorCount=4; /* FIXME ASAP!! */
|
||||
DBG((TXT("Init done...\n")));
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
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);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void if_spiInit(hwInterface *iface)
|
||||
{
|
||||
euint8 i;
|
||||
|
||||
printf("\n spi ini");
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 if_spiSend(hwInterface *iface, euint8 outgoing)
|
||||
{
|
||||
euint8 incoming=0;
|
||||
alt_u8 SD_Data=0,status;
|
||||
|
||||
IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SD_SPI_BASE, 1 );
|
||||
/* Set the SSO bit (force chipselect) */
|
||||
IOWR_ALTERA_AVALON_SPI_CONTROL(SD_SPI_BASE, 0x400);
|
||||
|
||||
do{
|
||||
status = IORD_ALTERA_AVALON_SPI_STATUS(SD_SPI_BASE);//get status
|
||||
}while (((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0 ) &&
|
||||
(status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) == 0);
|
||||
/* wait till transmit and ready ok */
|
||||
|
||||
IOWR_ALTERA_AVALON_SPI_TXDATA(SD_SPI_BASE, outgoing);
|
||||
|
||||
/* Wait until the interface has finished transmitting */
|
||||
do{status = IORD_ALTERA_AVALON_SPI_STATUS(SD_SPI_BASE);}
|
||||
while ((status & ALTERA_AVALON_SPI_STATUS_TMT_MSK) == 0);
|
||||
|
||||
/* reciver ready */
|
||||
if (((status & 0x80) != 0) ){
|
||||
SD_Data = IORD_ALTERA_AVALON_SPI_RXDATA(SD_SPI_BASE);
|
||||
}
|
||||
else{
|
||||
printf("\n no recive after transmit");
|
||||
}
|
||||
|
||||
IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SD_SPI_BASE, 1);
|
||||
IOWR_ALTERA_AVALON_SPI_CONTROL(SD_SPI_BASE, 0);
|
||||
|
||||
if( (status & 0x100) !=0)
|
||||
printf("\n error in spi error in spi");
|
||||
|
||||
return (SD_Data);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
350
poc/lpc2148_efsl/src/interfaces/sd.c
Normal file
350
poc/lpc2148_efsl/src/interfaces/sd.c
Normal file
@@ -0,0 +1,350 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : sd.c *
|
||||
* Revision : Initial developement *
|
||||
* Description : This file contains the functions needed to use efs for *
|
||||
* accessing files on an SD-card. *
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
* in Driver-Size: use if_spiSend instead for sd_Resp8b as proposed in *
|
||||
* sf.net bug-tracker (applied by mthomas) *
|
||||
\*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
#include "interfaces/sd.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 sd_Init(hwInterface *iface)
|
||||
{
|
||||
esint16 i;
|
||||
euint8 resp;
|
||||
|
||||
/* Try to send reset command up to 100 times */
|
||||
i=100;
|
||||
do {
|
||||
sd_Command(iface, 0, 0, 0);
|
||||
resp=sd_Resp8b(iface);
|
||||
}
|
||||
while(resp!=1 && i--);
|
||||
|
||||
if(resp!=1){
|
||||
DBG((TXT("CMD0 fail.\n")));
|
||||
if(resp==0xff){
|
||||
return(-1);
|
||||
}
|
||||
else{
|
||||
sd_Resp8bError(iface,resp);
|
||||
return(-2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait till card is ready initialising (returns 0 on CMD1) */
|
||||
/* Try up to 32000 times. */
|
||||
i=32000;
|
||||
do{
|
||||
sd_Command(iface,1, 0, 0);
|
||||
|
||||
resp=sd_Resp8b(iface);
|
||||
if(resp!=0)
|
||||
sd_Resp8bError(iface,resp);
|
||||
}
|
||||
while(resp==1 && i--);
|
||||
|
||||
if(resp!=0){
|
||||
sd_Resp8bError(iface,resp);
|
||||
return(-3);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void sd_Command(hwInterface *iface,euint8 cmd, euint16 paramx, euint16 paramy)
|
||||
{
|
||||
if_spiSend(iface,0xff);
|
||||
|
||||
if_spiSend(iface,0x40 | cmd);
|
||||
if_spiSend(iface,(euint8) (paramx >> 8)); /* MSB of parameter x */
|
||||
if_spiSend(iface,(euint8) (paramx)); /* LSB of parameter x */
|
||||
if_spiSend(iface,(euint8) (paramy >> 8)); /* MSB of parameter y */
|
||||
if_spiSend(iface,(euint8) (paramy)); /* LSB of parameter y */
|
||||
|
||||
if_spiSend(iface,0x95); /* Checksum (should be only valid for first command (0) */
|
||||
|
||||
if_spiSend(iface,0xff); /* eat empty command - response */
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 sd_Resp8b(hwInterface *iface)
|
||||
{
|
||||
euint8 i;
|
||||
euint8 resp;
|
||||
|
||||
/* Respone will come after 1 - 8 pings */
|
||||
for ( i=0; i<8; i++ ) {
|
||||
resp = if_spiSend(iface,0xff);
|
||||
if(resp != 0xff)
|
||||
return(resp);
|
||||
}
|
||||
|
||||
return(resp);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint16 sd_Resp16b(hwInterface *iface)
|
||||
{
|
||||
euint16 resp;
|
||||
|
||||
resp = ( sd_Resp8b(iface) << 8 ) & 0xff00;
|
||||
resp |= if_spiSend(iface,0xff);
|
||||
|
||||
return(resp);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void sd_Resp8bError(hwInterface *iface,euint8 value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case 0x40:
|
||||
DBG((TXT("Argument out of bounds.\n")));
|
||||
break;
|
||||
case 0x20:
|
||||
DBG((TXT("Address out of bounds.\n")));
|
||||
break;
|
||||
case 0x10:
|
||||
DBG((TXT("Error during erase sequence.\n")));
|
||||
break;
|
||||
case 0x08:
|
||||
DBG((TXT("CRC failed.\n")));
|
||||
break;
|
||||
case 0x04:
|
||||
DBG((TXT("Illegal command.\n")));
|
||||
break;
|
||||
case 0x02:
|
||||
DBG((TXT("Erase reset (see SanDisk docs p5-13).\n")));
|
||||
break;
|
||||
case 0x01:
|
||||
DBG((TXT("Card is initialising.\n")));
|
||||
break;
|
||||
default:
|
||||
DBG((TXT("Unknown error 0x%x (see SanDisk docs p5-13).\n"),value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 sd_State(hwInterface *iface)
|
||||
{
|
||||
eint16 value;
|
||||
|
||||
sd_Command(iface,13, 0, 0);
|
||||
value=sd_Resp16b(iface);
|
||||
|
||||
switch(value)
|
||||
{
|
||||
case 0x000:
|
||||
return(1);
|
||||
break;
|
||||
case 0x0001:
|
||||
DBG((TXT("Card is Locked.\n")));
|
||||
break;
|
||||
case 0x0002:
|
||||
DBG((TXT("WP Erase Skip, Lock/Unlock Cmd Failed.\n")));
|
||||
break;
|
||||
case 0x0004:
|
||||
DBG((TXT("General / Unknown error -- card broken?.\n")));
|
||||
break;
|
||||
case 0x0008:
|
||||
DBG((TXT("Internal card controller error.\n")));
|
||||
break;
|
||||
case 0x0010:
|
||||
DBG((TXT("Card internal ECC was applied, but failed to correct the data.\n")));
|
||||
break;
|
||||
case 0x0020:
|
||||
DBG((TXT("Write protect violation.\n")));
|
||||
break;
|
||||
case 0x0040:
|
||||
DBG((TXT("An invalid selection, sectors for erase.\n")));
|
||||
break;
|
||||
case 0x0080:
|
||||
DBG((TXT("Out of Range, CSD_Overwrite.\n")));
|
||||
break;
|
||||
default:
|
||||
if(value>0x00FF)
|
||||
sd_Resp8bError(iface,(euint8) (value>>8));
|
||||
else
|
||||
DBG((TXT("Unknown error: 0x%x (see SanDisk docs p5-14).\n"),value));
|
||||
break;
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* WAIT ?? -- FIXME
|
||||
* CMDWRITE
|
||||
* WAIT
|
||||
* CARD RESP
|
||||
* WAIT
|
||||
* DATA BLOCK OUT
|
||||
* START BLOCK
|
||||
* DATA
|
||||
* CHKS (2B)
|
||||
* BUSY...
|
||||
*/
|
||||
|
||||
esint8 sd_writeSector(hwInterface *iface,euint32 address, euint8* buf)
|
||||
{
|
||||
euint32 place;
|
||||
euint16 i;
|
||||
euint16 t=0;
|
||||
|
||||
/*DBG((TXT("Trying to write %u to sector %u.\n"),(void *)&buf,address));*/
|
||||
place=512*address;
|
||||
sd_Command(iface,CMDWRITE, (euint16) (place >> 16), (euint16) place);
|
||||
|
||||
sd_Resp8b(iface); /* Card response */
|
||||
|
||||
if_spiSend(iface,0xfe); /* Start block */
|
||||
for(i=0;i<512;i++)
|
||||
if_spiSend(iface,buf[i]); /* Send data */
|
||||
if_spiSend(iface,0xff); /* Checksum part 1 */
|
||||
if_spiSend(iface,0xff); /* Checksum part 2 */
|
||||
|
||||
if_spiSend(iface,0xff);
|
||||
|
||||
while(if_spiSend(iface,0xff)!=0xff){
|
||||
t++;
|
||||
/* Removed NOP */
|
||||
}
|
||||
/*DBG((TXT("Nopp'ed %u times.\n"),t));*/
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* WAIT ?? -- FIXME
|
||||
* CMDCMD
|
||||
* WAIT
|
||||
* CARD RESP
|
||||
* WAIT
|
||||
* DATA BLOCK IN
|
||||
* START BLOCK
|
||||
* DATA
|
||||
* CHKS (2B)
|
||||
*/
|
||||
|
||||
esint8 sd_readSector(hwInterface *iface,euint32 address, euint8* buf, euint16 len)
|
||||
{
|
||||
euint8 cardresp;
|
||||
euint8 firstblock;
|
||||
euint8 c;
|
||||
euint16 fb_timeout=0xffff;
|
||||
euint32 i;
|
||||
euint32 place;
|
||||
|
||||
/*DBG((TXT("sd_readSector::Trying to read sector %u and store it at %p.\n"),address,&buf[0]));*/
|
||||
place=512*address;
|
||||
sd_Command(iface,CMDREAD, (euint16) (place >> 16), (euint16) place);
|
||||
|
||||
cardresp=sd_Resp8b(iface); /* Card response */
|
||||
|
||||
/* Wait for startblock */
|
||||
do
|
||||
firstblock=sd_Resp8b(iface);
|
||||
while(firstblock==0xff && fb_timeout--);
|
||||
|
||||
if(cardresp!=0x00 || firstblock!=0xfe){
|
||||
sd_Resp8bError(iface,firstblock);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
for(i=0;i<512;i++){
|
||||
c = if_spiSend(iface,0xff);
|
||||
if(i<len)
|
||||
buf[i] = c;
|
||||
}
|
||||
|
||||
/* Checksum (2 byte) - ignore for now */
|
||||
if_spiSend(iface,0xff);
|
||||
if_spiSend(iface,0xff);
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
calculates size of card from CSD
|
||||
(extension by Martin Thomas, inspired by code from Holger Klabunde)
|
||||
*/
|
||||
esint8 sd_getDriveSize(hwInterface *iface, euint32* drive_size )
|
||||
{
|
||||
euint8 cardresp, i, by;
|
||||
euint8 iob[16];
|
||||
euint16 c_size, c_size_mult, read_bl_len;
|
||||
|
||||
sd_Command(iface, CMDREADCSD, 0, 0);
|
||||
|
||||
do {
|
||||
cardresp = sd_Resp8b(iface);
|
||||
} while ( cardresp != 0xFE );
|
||||
|
||||
DBG((TXT("CSD:")));
|
||||
for( i=0; i<16; i++) {
|
||||
#warning "inofficial CSD-read patch active sd_Resp8b->if_spiSend"
|
||||
/* iob[i] = sd_Resp8b(iface); */
|
||||
iob[i] = if_spiSend(iface,0xff);
|
||||
DBG((TXT(" %02x"), iob[i]));
|
||||
}
|
||||
DBG((TXT("\n")));
|
||||
|
||||
if_spiSend(iface,0xff);
|
||||
if_spiSend(iface,0xff);
|
||||
|
||||
c_size = iob[6] & 0x03; // bits 1..0
|
||||
c_size <<= 10;
|
||||
c_size += (euint16)iob[7]<<2;
|
||||
c_size += iob[8]>>6;
|
||||
|
||||
by= iob[5] & 0x0F;
|
||||
read_bl_len = 1;
|
||||
read_bl_len <<= by;
|
||||
|
||||
by=iob[9] & 0x03;
|
||||
by <<= 1;
|
||||
by += iob[10] >> 7;
|
||||
|
||||
c_size_mult = 1;
|
||||
c_size_mult <<= (2+by);
|
||||
|
||||
*drive_size = (euint32)(c_size+1) * (euint32)c_size_mult * (euint32)read_bl_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
611
poc/lpc2148_efsl/src/ioman.c
Normal file
611
poc/lpc2148_efsl/src/ioman.c
Normal file
@@ -0,0 +1,611 @@
|
||||
/*****************************************************************************\
|
||||
* 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 *
|
||||
\*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Revisions applied by Mike Anton:
|
||||
* 06/05/26 - In ioman_writeSector(): return value of if_writeBuf()
|
||||
* is zero if the function succeeded, but the test done is
|
||||
* less than or equal to zero, so it always fails.
|
||||
* 06/08/25 - In ioman_flushSector(): the test on ioman_writeSector() is
|
||||
* incorrect now that ioman_writeSector() return value has
|
||||
* been corrected. Interestingly the call to
|
||||
* ioman_writeSector() in ioman_directSectorWrite() is correct.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
#include "ioman.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_init(IOManager *ioman, hwInterface *iface, euint8* bufferarea)
|
||||
{
|
||||
ioman->iface=iface;
|
||||
|
||||
ioman->bufptr = ioman_getBuffer(ioman,bufferarea);
|
||||
ioman->numbuf = IOMAN_NUMBUFFER;
|
||||
ioman->numit = IOMAN_NUMITERATIONS;
|
||||
|
||||
ioman_reset(ioman);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_reset(IOManager *ioman)
|
||||
{
|
||||
euint16 nb,ni;
|
||||
|
||||
memClr(ioman->sector,sizeof(euint32)*ioman->numbuf);
|
||||
memClr(ioman->status,sizeof(euint8) *ioman->numbuf);
|
||||
memClr(ioman->usage ,sizeof(euint8) *ioman->numbuf);
|
||||
memClr(ioman->itptr ,sizeof(euint8) *ioman->numbuf);
|
||||
ioman_setError(ioman,IOMAN_NOERROR);
|
||||
|
||||
for(nb=0;nb<ioman->numbuf;nb++){
|
||||
for(ni=0;ni<ioman->numit;ni++){
|
||||
ioman->stack[nb][ni].sector=0;
|
||||
ioman->stack[nb][ni].status=0;
|
||||
ioman->stack[nb][ni].usage =0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8* ioman_getBuffer(IOManager *ioman,euint8* bufferarea)
|
||||
{
|
||||
#ifdef IOMAN_DO_MEMALLOC
|
||||
return(ioman->cache_mem);
|
||||
#else
|
||||
return(bufferarea);
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_setAttr(IOManager *ioman,euint16 bufplace,euint8 attribute,euint8 val)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_SETATTROUTOFBOUNDS);
|
||||
return; /* Out of bounds */
|
||||
}
|
||||
|
||||
if(val){
|
||||
ioman->status[bufplace]|=1<<attribute;
|
||||
}else{
|
||||
ioman->status[bufplace]&=~(1<<attribute);
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 ioman_getAttr(IOManager *ioman,euint16 bufplace,euint8 attribute)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_GETATTROUTOFBOUNDS);
|
||||
return(0xFF); /* Out of bounds */
|
||||
}
|
||||
|
||||
return(ioman->status[bufplace]&(1<<attribute));
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 ioman_getUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return(0x00);
|
||||
}
|
||||
return(ioman->usage[bufplace]);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
void ioman_incUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return;
|
||||
}
|
||||
if(ioman->usage[bufplace]==0xFF)return;
|
||||
else ioman->usage[bufplace]++;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_decUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return;
|
||||
}
|
||||
if(ioman->usage[bufplace]==0x0)return;
|
||||
else ioman->usage[bufplace]--;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_resetUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return;
|
||||
}
|
||||
ioman->usage[bufplace]=0x00;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 ioman_getRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return(0x00);
|
||||
}
|
||||
return(ioman->reference[bufplace]);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_incRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return;
|
||||
}
|
||||
if(ioman->reference[bufplace]==0xFF)return;
|
||||
else ioman->reference[bufplace]++;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_decRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return;
|
||||
}
|
||||
if(ioman->reference[bufplace]==0x00)return;
|
||||
else ioman->reference[bufplace]--;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_resetRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return;
|
||||
}
|
||||
ioman->reference[bufplace]=0x00;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_pop(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_POPEMPTYSTACK);
|
||||
return(-1);
|
||||
}
|
||||
if(ioman->itptr[bufplace]==0 || ioman->itptr[bufplace]>IOMAN_NUMITERATIONS)return(-1);
|
||||
ioman->sector[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].sector;
|
||||
ioman->status[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].status;
|
||||
ioman->usage[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].usage;
|
||||
ioman->itptr[bufplace]--;
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_push(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return(-1);
|
||||
}
|
||||
if(ioman->itptr[bufplace]>=IOMAN_NUMITERATIONS){
|
||||
ioman_setError(ioman,IOMAN_ERR_PUSHBEYONDSTACK);
|
||||
return(-1);
|
||||
}
|
||||
ioman->itptr[bufplace]++;
|
||||
ioman->stack[bufplace][ioman->itptr[bufplace]].sector = ioman->sector[bufplace];
|
||||
ioman->stack[bufplace][ioman->itptr[bufplace]].status = ioman->status[bufplace];
|
||||
ioman->stack[bufplace][ioman->itptr[bufplace]].usage = ioman->usage[bufplace];
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8* ioman_getPtr(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return(0);
|
||||
}
|
||||
return(ioman->bufptr+bufplace*512);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint16 ioman_getBp(IOManager *ioman,euint8* buf)
|
||||
{
|
||||
if(buf<(ioman->bufptr) || buf>=( ioman->bufptr+(ioman->numbuf*512) )){
|
||||
ioman_setError(ioman,IOMAN_ERR_CACHEPTROUTOFRANGE);
|
||||
return(-1);
|
||||
}
|
||||
return((buf-(ioman->bufptr))/512);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_readSector(IOManager *ioman,euint32 address,euint8* buf)
|
||||
{
|
||||
esint8 r;
|
||||
|
||||
if(buf==0){
|
||||
return(-1);
|
||||
}
|
||||
|
||||
r=if_readBuf(ioman->iface,address,buf);
|
||||
|
||||
if(r!=0){
|
||||
ioman_setError(ioman,IOMAN_ERR_READFAIL);
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_writeSector(IOManager *ioman, euint32 address, euint8* buf)
|
||||
{
|
||||
esint8 r;
|
||||
|
||||
if(buf==0)return(-1);
|
||||
|
||||
r=if_writeBuf(ioman->iface,address,buf);
|
||||
|
||||
#warning "M. Anton: Unofficial ioman_writeSector() patch active if(r<=0){ -> if(r!=0){"
|
||||
// if(r<=0){
|
||||
if(r!=0){
|
||||
|
||||
ioman_setError(ioman,IOMAN_ERR_WRITEFAIL);
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_resetCacheItem(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf){
|
||||
ioman_setError(ioman,IOMAN_ERR_OPOUTOFBOUNDS);
|
||||
return;
|
||||
}
|
||||
ioman->sector[bufplace] = 0;
|
||||
ioman->status[bufplace] = 0;
|
||||
ioman->usage[bufplace] = 0;
|
||||
ioman->reference[bufplace] = 0;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint32 ioman_findSectorInCache(IOManager *ioman, euint32 address)
|
||||
{
|
||||
euint16 c;
|
||||
|
||||
for(c=0;c<ioman->numbuf;c++){
|
||||
if(ioman_isValid(c) && ioman->sector[c] == address)return(c);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint32 ioman_findFreeSpot(IOManager *ioman)
|
||||
{
|
||||
euint16 c;
|
||||
|
||||
for(c=0;c<ioman->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<ioman->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)<=lr){
|
||||
r=c;
|
||||
lr=ioman_getRefCnt(ioman,c);
|
||||
}
|
||||
}
|
||||
if(fr && !ioman_isWritable(c)){
|
||||
if(ioman_getRefCnt(ioman,c)<=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<ioman->numbuf;c++){
|
||||
if(ioman->itptr[c]<ioman->numit){
|
||||
points = 0;
|
||||
if(ioman_isWritable(c))points+=0x7F;
|
||||
points += ((euint16)(ioman->itptr[c]*0x4D))/(ioman->numit);
|
||||
points += ((euint16)(ioman_getRefCnt(ioman,c)*0x33))/0xFF;
|
||||
if(points<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){
|
||||
ioman_setError(ioman,IOMAN_ERR_CACHEPTROUTOFRANGE);
|
||||
return(-1);
|
||||
}
|
||||
if((ioman_readSector(ioman,address,buf))){
|
||||
ioman_setError(ioman,IOMAN_ERR_READFAIL);
|
||||
return(-1);
|
||||
}
|
||||
ioman_setValid(bufplace);
|
||||
ioman->sector[bufplace]=address;
|
||||
return(0);
|
||||
}
|
||||
/***************** if(bufplace>=ioman->numbuf)return;
|
||||
************************************************************/
|
||||
|
||||
esint8 ioman_flushSector(IOManager *ioman, euint16 bufplace)
|
||||
{
|
||||
euint8* buf;
|
||||
|
||||
if((buf = ioman_getPtr(ioman,bufplace))==0){
|
||||
ioman_setError(ioman,IOMAN_ERR_CACHEPTROUTOFRANGE);
|
||||
return(-1);
|
||||
}
|
||||
if(!ioman_isWritable(bufplace)){
|
||||
ioman_setError(ioman,IOMAN_ERR_WRITEREADONLYSECTOR);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
#warning "M. Anton: Unofficial ioman_flushSector() patch active - ioman_writeSector() test was incorrect"
|
||||
// if(!(ioman_writeSector(ioman,ioman->sector[bufplace],buf))){
|
||||
if(ioman_writeSector(ioman,ioman->sector[bufplace],buf)){
|
||||
ioman_setError(ioman,IOMAN_ERR_WRITEFAIL);
|
||||
return(-1);
|
||||
}
|
||||
if(ioman->usage==0)ioman_setNotWritable(bufplace);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_flushRange(IOManager *ioman,euint32 address_low, euint32 address_high)
|
||||
{
|
||||
euint32 c;
|
||||
|
||||
if(address_low>address_high){
|
||||
c=address_low; address_low=address_high;address_high=c;
|
||||
}
|
||||
|
||||
for(c=0;c<ioman->numbuf;c++){
|
||||
if((ioman->sector[c]>=address_low) && (ioman->sector[c]<=address_high) && (ioman_isWritable(c))){
|
||||
if(ioman_flushSector(ioman,c)){
|
||||
return(-1);
|
||||
}
|
||||
if(ioman->usage[c]==0)ioman_setNotWritable(c);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_flushAll(IOManager *ioman)
|
||||
{
|
||||
euint16 c;
|
||||
|
||||
for(c=0;c<ioman->numbuf;c++){
|
||||
if(ioman_isWritable(c)){
|
||||
if(ioman_flushSector(ioman,c)){
|
||||
return(-1);
|
||||
}
|
||||
if(ioman->usage[c]==0)ioman_setNotWritable(c);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8* ioman_getSector(IOManager *ioman,euint32 address, euint8 mode)
|
||||
{
|
||||
esint32 bp;
|
||||
|
||||
if((bp=ioman_findSectorInCache(ioman,address))!=-1){
|
||||
if(ioman_isReqRw(mode)){
|
||||
ioman_setWritable(bp);
|
||||
}
|
||||
ioman_incUseCnt(ioman,bp);
|
||||
if(!ioman_isReqExp(mode))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);
|
||||
if(!ioman_isReqExp(mode))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(ioman_isReqRw(mode)){
|
||||
ioman_setWritable(bp);
|
||||
}
|
||||
ioman_incUseCnt(ioman,bp);
|
||||
if(!ioman_isReqExp(mode))ioman_incRefCnt(ioman,bp);
|
||||
return(ioman_getPtr(ioman,bp));
|
||||
}
|
||||
ioman_setError(ioman,IOMAN_ERR_NOMEMORY);
|
||||
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->itptr[bp]!=0){
|
||||
if(ioman_isWritable(bp)){
|
||||
ioman_flushSector(ioman,bp);
|
||||
}
|
||||
ioman_pop(ioman,bp);
|
||||
ioman_putSectorInCache(ioman,ioman->sector[bp],bp);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_directSectorRead(IOManager *ioman,euint32 address, euint8* buf)
|
||||
{
|
||||
euint8* ibuf;
|
||||
esint16 bp;
|
||||
|
||||
if((bp=ioman_findSectorInCache(ioman,address))!=-1){
|
||||
ibuf=ioman_getPtr(ioman,bp);
|
||||
memCpy(ibuf,buf,512);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if((bp=ioman_findFreeSpot(ioman))!=-1){
|
||||
if((ioman_putSectorInCache(ioman,address,bp))){
|
||||
return(-1);
|
||||
}
|
||||
ibuf=ioman_getPtr(ioman,bp);
|
||||
memCpy(ibuf,buf,512);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(ioman_readSector(ioman,address,buf)){
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ioman_directSectorWrite(IOManager *ioman,euint32 address, euint8* buf)
|
||||
{
|
||||
euint8* ibuf;
|
||||
esint16 bp;
|
||||
|
||||
if((bp=ioman_findSectorInCache(ioman,address))!=-1){
|
||||
ibuf=ioman_getPtr(ioman,bp);
|
||||
memCpy(buf,ibuf,512);
|
||||
ioman_setWritable(bp);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if((bp=ioman_findFreeSpot(ioman))!=-1){
|
||||
ibuf=ioman_getPtr(ioman,bp);
|
||||
memCpy(buf,ibuf,512);
|
||||
ioman_resetCacheItem(ioman,bp);
|
||||
ioman->sector[bp]=address;
|
||||
ioman_setWritable(bp);
|
||||
ioman_setValid(bp);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(ioman_writeSector(ioman,address,buf)){
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ioman_printStatus(IOManager *ioman)
|
||||
{
|
||||
euint16 c;
|
||||
|
||||
DBG((TXT("IO-Manager -- Report\n====================\n")));
|
||||
DBG((TXT("Buffer is %i sectors, from %p to %p\n"),
|
||||
ioman->numbuf,ioman->bufptr,ioman->bufptr+(ioman->numbuf*512)));
|
||||
for(c=0;c<ioman->numbuf;c++){
|
||||
if(ioman_isValid(c)){
|
||||
DBG((TXT("BP %3i\t SC %8li\t\t US %i\t RF %i\t %s %s\n"),
|
||||
c,ioman->sector[c],ioman_getUseCnt(ioman,c),ioman_getRefCnt(ioman,c),
|
||||
ioman_isUserBuf(c) ? "USRBUF" : " ",
|
||||
ioman_isWritable(c) ? "WRITABLE" : "READONLY"));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
402
poc/lpc2148_efsl/src/ioman_v2.c
Normal file
402
poc/lpc2148_efsl/src/ioman_v2.c
Normal file
@@ -0,0 +1,402 @@
|
||||
/*****************************************************************************\
|
||||
* 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->iface=iface;
|
||||
|
||||
ioman->bufptr = ioman_getBuffer(ioman,bufferarea);
|
||||
ioman->numbuf = IOMAN_NUMBUFFER;
|
||||
ioman->numit = IOMAN_NUMITERATIONS;
|
||||
|
||||
ioman_reset(ioman);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void ioman_reset(IOManager *ioman)
|
||||
{
|
||||
euint16 nb,ni;
|
||||
|
||||
memClr(ioman->sector,sizeof(euint32)*ioman->numbuf);
|
||||
memClr(ioman->status,sizeof(euint8) *ioman->numbuf);
|
||||
memClr(ioman->usage ,sizeof(euint8) *ioman->numbuf);
|
||||
memClr(ioman->itptr ,sizeof(euint8) *ioman->numbuf);
|
||||
|
||||
for(nb=0;nb<ioman->numbuf;nb++){
|
||||
for(ni=0;ni<ioman->numit;ni++){
|
||||
ioman->stack[nb][ni].sector=0;
|
||||
ioman->stack[nb][ni].status=0;
|
||||
ioman->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>=ioman->numbuf)return; /* Out of bounds */
|
||||
|
||||
if(val){
|
||||
ioman->status[bufplace]|=1<<attribute;
|
||||
}else{
|
||||
ioman->status[bufplace]&=~(1<<attribute);
|
||||
}
|
||||
}
|
||||
|
||||
euint8 ioman_getAttr(IOManager *ioman,euint16 bufplace,euint8 attribute)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)
|
||||
return(0xFF); /* Out of bounds */
|
||||
|
||||
return(ioman->status[bufplace]&(1<<attribute));
|
||||
}
|
||||
|
||||
euint8 ioman_getUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return(0x00);
|
||||
return(ioman->usage[bufplace]);
|
||||
}
|
||||
|
||||
void ioman_incUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return;
|
||||
if(ioman->usage[bufplace]==0xFF)return;
|
||||
else ioman->usage[bufplace]++;
|
||||
}
|
||||
|
||||
void ioman_decUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return;
|
||||
if(ioman->usage[bufplace]==0x0)return;
|
||||
else ioman->usage[bufplace]--;
|
||||
}
|
||||
|
||||
void ioman_resetUseCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return;
|
||||
ioman->usage[bufplace]=0x00;
|
||||
}
|
||||
|
||||
euint8 ioman_getRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return(0x00);
|
||||
return(ioman->reference[bufplace]);
|
||||
}
|
||||
|
||||
void ioman_incRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return;
|
||||
if(ioman->reference[bufplace]==0xFF)return;
|
||||
else ioman->reference[bufplace]++;
|
||||
}
|
||||
|
||||
void ioman_decRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return;
|
||||
if(ioman->reference[bufplace]==0x00)return;
|
||||
else ioman->reference[bufplace]--;
|
||||
}
|
||||
|
||||
void ioman_resetRefCnt(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return;
|
||||
ioman->reference[bufplace]=0x00;
|
||||
}
|
||||
|
||||
esint8 ioman_pop(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return(-1);
|
||||
if(ioman->itptr[bufplace]==0 || ioman->itptr[bufplace]>IOMAN_NUMITERATIONS)return(-1);
|
||||
ioman->sector[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].sector;
|
||||
ioman->status[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].status;
|
||||
ioman->usage[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].usage;
|
||||
ioman->itptr[bufplace]--;
|
||||
return(0);
|
||||
}
|
||||
|
||||
esint8 ioman_push(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return(-1);
|
||||
if(ioman->itptr[bufplace]>=IOMAN_NUMITERATIONS)return(-1);
|
||||
ioman->itptr[bufplace]++;
|
||||
ioman->stack[bufplace][ioman->itptr[bufplace]].sector = ioman->sector[bufplace];
|
||||
ioman->stack[bufplace][ioman->itptr[bufplace]].status = ioman->status[bufplace];
|
||||
ioman->stack[bufplace][ioman->itptr[bufplace]].usage = ioman->usage[bufplace];
|
||||
return(0);
|
||||
}
|
||||
|
||||
euint8* ioman_getPtr(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
if(bufplace>=ioman->numbuf)return(0);
|
||||
return(ioman->bufptr+bufplace*512);
|
||||
}
|
||||
|
||||
esint16 ioman_getBp(IOManager *ioman,euint8* buf)
|
||||
{
|
||||
if(buf<(ioman->bufptr) || buf>=( ioman->bufptr+(ioman->numbuf*512) )){
|
||||
return(-1);
|
||||
}
|
||||
return((buf-(ioman->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->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->iface,address,buf);
|
||||
|
||||
if(r<=0){
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void ioman_resetCacheItem(IOManager *ioman,euint16 bufplace)
|
||||
{
|
||||
ioman->sector[bufplace] = 0;
|
||||
ioman->status[bufplace] = 0;
|
||||
ioman->usage[bufplace] = 0;
|
||||
ioman->reference[bufplace] = 0;
|
||||
}
|
||||
|
||||
esint32 ioman_findSectorInCache(IOManager *ioman, euint32 address)
|
||||
{
|
||||
euint16 c;
|
||||
|
||||
for(c=0;c<ioman->numbuf;c++){
|
||||
if(ioman_isValid(c) && ioman->sector[c] == address)return(c);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
esint32 ioman_findFreeSpot(IOManager *ioman)
|
||||
{
|
||||
euint16 c;
|
||||
|
||||
for(c=0;c<ioman->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<ioman->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)<=lr){
|
||||
r=c;
|
||||
lr=ioman_getRefCnt(ioman,c);
|
||||
}
|
||||
}
|
||||
if(fr && !ioman_isWritable(c)){
|
||||
if(ioman_getRefCnt(ioman,c)<=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<ioman->numbuf;c++){
|
||||
if(ioman->itptr[c]<ioman->numit){
|
||||
points = 0;
|
||||
if(ioman_isWritable(c))points+=0x7F;
|
||||
points += ((euint16)(ioman->itptr[c]*0x4D))/(ioman->numit);
|
||||
points += ((euint16)(ioman_getRefCnt(ioman,c)*0x33))/0xFF;
|
||||
if(points<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->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->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->itptr!=0){
|
||||
if(ioman_isWritable(bp)){
|
||||
ioman_flushSector(ioman,bp);
|
||||
}
|
||||
ioman_pop(ioman,bp);
|
||||
ioman_putSectorInCache(ioman,ioman->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->numbuf,ioman->bufptr,ioman->bufptr+(ioman->numbuf*512)));
|
||||
for(c=0;c<ioman->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->sector[c],ioman_getUseCnt(ioman,c),ioman_getRefCnt(ioman,c),
|
||||
ioman_isUserBuf(c) ? "USRBUF" : " ",
|
||||
ioman_isWritable(c) ? "WRITABLE" : "READONLY"));
|
||||
}
|
||||
}
|
||||
}
|
||||
140
poc/lpc2148_efsl/src/ls.c
Normal file
140
poc/lpc2148_efsl/src/ls.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/*****************************************************************************\
|
||||
* 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->fs=fs;
|
||||
|
||||
if(fs_findFile(dlist->fs,dirname,&loc,&fc)!=2)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
fs_initClusterChain(dlist->fs,&(dlist->Cache),fc);
|
||||
memClr(&(dlist->currentEntry),sizeof(dlist->currentEntry));
|
||||
dlist->rEntry=0;
|
||||
dlist->cEntry=0xFFFF;
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ls_getDirEntry(DirList *dlist)
|
||||
{
|
||||
if(dlist->Cache.FirstCluster == 1){
|
||||
return(ls_getRootAreaEntry(dlist));
|
||||
}else if(dlist->Cache.FirstCluster){
|
||||
return(ls_getRealDirEntry(dlist));
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ls_getNext(DirList *dlist)
|
||||
{
|
||||
do{
|
||||
if(ls_getDirEntry(dlist))return(-1);
|
||||
dlist->rEntry++;
|
||||
}while(!ls_isValidFileEntry(&(dlist->currentEntry)));
|
||||
dlist->cEntry++;
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ls_getRealDirEntry(DirList *dlist)
|
||||
{
|
||||
euint8* buf;
|
||||
|
||||
if(dlist->Cache.FirstCluster<=1)return(-1);
|
||||
|
||||
if(fat_LogicToDiscCluster(dlist->fs,
|
||||
&(dlist->Cache),
|
||||
(dlist->rEntry)/(16 * dlist->fs->volumeId.SectorsPerCluster))){
|
||||
return(-1);
|
||||
}
|
||||
|
||||
buf = part_getSect(dlist->fs->part,
|
||||
fs_clusterToSector(dlist->fs,dlist->Cache.DiscCluster) + (dlist->rEntry/16)%dlist->fs->volumeId.SectorsPerCluster,
|
||||
IOM_MODE_READONLY);
|
||||
|
||||
/*memCpy(buf+(dlist->rEntry%16)*32,&(dlist->currentEntry),32);*/
|
||||
ls_fileEntryToDirListEntry(dlist,buf,32*(dlist->rEntry%16));
|
||||
|
||||
part_relSect(dlist->fs->part,buf);
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ls_getRootAreaEntry(DirList *dlist)
|
||||
{
|
||||
euint8 *buf=0;
|
||||
|
||||
if((dlist->fs->type != FAT12) && (dlist->fs->type != FAT16))return(-1);
|
||||
if(dlist->rEntry>=dlist->fs->volumeId.RootEntryCount)return(-1);
|
||||
|
||||
buf = part_getSect(dlist->fs->part,
|
||||
dlist->fs->FirstSectorRootDir+dlist->rEntry/16,
|
||||
IOM_MODE_READONLY);
|
||||
/*memCpy(buf+32*(dlist->rEntry%16),&(dlist->currentEntry),32);*/
|
||||
ls_fileEntryToDirListEntry(dlist,buf,32*(dlist->rEntry%16));
|
||||
part_relSect(dlist->fs->part,buf);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 ls_isValidFileEntry(ListDirEntry *entry)
|
||||
{
|
||||
if(entry->FileName[0] == 0 || entry->FileName[0] == 0xE5 || entry->FileName[0] == '.')return(0);
|
||||
if((entry->Attribute&0x0F)==0x0F)return(0);
|
||||
return(1);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void ls_fileEntryToDirListEntry(DirList *dlist, euint8* buf, euint16 offset)
|
||||
{
|
||||
if(offset>480 || offset%32)return;
|
||||
|
||||
buf+=offset;
|
||||
memCpy(buf+OFFSET_DE_FILENAME,dlist->currentEntry.FileName,LIST_MAXLENFILENAME);
|
||||
dlist->currentEntry.Attribute = *(buf+OFFSET_DE_ATTRIBUTE);
|
||||
dlist->currentEntry.FileSize = ex_getb32(buf,OFFSET_DE_FILESIZE);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
301
poc/lpc2148_efsl/src/mkfs.c
Normal file
301
poc/lpc2148_efsl/src/mkfs.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : mkfs.c *
|
||||
* Description : These functions are used for creating an empty filesystem. *
|
||||
* *
|
||||
* 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: alignment modifications for arm-elf-gcc *
|
||||
* - should be portable *
|
||||
\*****************************************************************************/
|
||||
|
||||
#define MT_MOD
|
||||
|
||||
/*****************************************************************************/
|
||||
#include "mkfs.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef MT_MOD
|
||||
signed short mkfs_makevfat(Partition *part)
|
||||
{
|
||||
unsigned long c,cc,ret;
|
||||
unsigned long ns,fs,ds,dc;
|
||||
unsigned char buf[512];
|
||||
|
||||
ns=part->disc->partitions[part->activePartition].numSectors;
|
||||
|
||||
if( ns < 66581 ){
|
||||
DBG((TXT("This is not possible due to insufficient sectors. Sorry\n")));
|
||||
return(MKFS_ERR_TOOLITTLESECTORS);
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
for(c=1<<6;c>=1;c>>=1){
|
||||
|
||||
/* First guess */
|
||||
ds = ns - 32;
|
||||
fs = ((ds/c)+127)/128;
|
||||
/* ds was guess too large, so fs is too large now too. */
|
||||
|
||||
for(cc=0;cc<2;cc++){
|
||||
|
||||
/* Round 2, error round */
|
||||
ds = ns - 32 - 2*fs;
|
||||
fs = ((ds/c)+127)/128;
|
||||
/* Since fs was too large, ds became too small. So the fs for this small ds is too small as well. */
|
||||
|
||||
/* Round 3, correction round */
|
||||
ds = ns - 32 - 2*fs;
|
||||
fs = ((ds/c)+127)/128;
|
||||
/* The fs was too small, so ds was too large. The calculated fs should be slightly too large. */
|
||||
|
||||
}
|
||||
|
||||
/* Round 4, finalise */
|
||||
ds = ns - 32 - 2*fs;
|
||||
|
||||
dc = ds / c;
|
||||
if(ret<(fs*128-dc)/128)ret=(fs*128-dc)/128;
|
||||
|
||||
/* Check if with current setting we have a valid fat ? */
|
||||
|
||||
if(dc >= 65525 + 16){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate BPB */
|
||||
memClr(buf,512);
|
||||
|
||||
/* Boot code */
|
||||
*(buf+0)=0xE9; *(buf+1)=0x00; *(buf+2)=0x00; /* RESET */
|
||||
|
||||
/* OEM name */
|
||||
memCpy("DSCOSMSH",buf+3,8);
|
||||
|
||||
/* Bytes/Sector */
|
||||
*((unsigned short*)(buf+11)) = 512;
|
||||
|
||||
/* Sectors/Cluster */
|
||||
*(buf+13) = c;
|
||||
|
||||
/* Reserved Sectors */
|
||||
*((unsigned short*)(buf+14)) = 32;
|
||||
|
||||
/* Number of FAT Tables */
|
||||
*(buf+16) = 2;
|
||||
|
||||
/* RootEntryCount */
|
||||
*((unsigned short*)(buf+17)) = 0;
|
||||
|
||||
/* Total Sector Count __16 */
|
||||
*((unsigned short*)(buf+19)) = 0;
|
||||
|
||||
/* Media (crap) */
|
||||
*(buf+21) = 0xF8;
|
||||
|
||||
/* FAT size 16 */
|
||||
*((unsigned short*)(buf+22)) = 0;
|
||||
|
||||
/* Total Sector Count __32 */
|
||||
*((unsigned long*)(buf+32)) = ns;
|
||||
|
||||
/* Fat Size 32 */
|
||||
*((unsigned long*)(buf+36)) = fs;
|
||||
|
||||
/* First Cluster Root Dir */
|
||||
*((unsigned long*)(buf+44)) = 2;
|
||||
|
||||
/* VolumeID */
|
||||
*((unsigned long*)(buf+67)) = 0x13371337;
|
||||
|
||||
/* Volume Label */
|
||||
memCpy("DISCOSMASH!",buf+71,11);
|
||||
|
||||
/* Filesystemtype */
|
||||
memCpy("FAT32 ",buf+82,8);
|
||||
|
||||
/* Magic */
|
||||
*(buf+510) = 0x55; *(buf+511) = 0xAA;
|
||||
|
||||
part_writeBuf(part,0,buf);
|
||||
|
||||
memClr(buf,512);
|
||||
for(c=32;c<(32+2*fs);c++){
|
||||
part_writeBuf(part,c,buf);
|
||||
}
|
||||
*(((unsigned long*)buf) )=0x0FFFFFF8;
|
||||
*(((unsigned long*)buf)+1)=0x0FFFFFFF;
|
||||
*(((unsigned long*)buf)+2)=0x0FFFFFF8;
|
||||
part_writeBuf(part,32,buf);
|
||||
part_writeBuf(part,32+fs,buf);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#warning "mthomas - modifications alignment"
|
||||
|
||||
signed short mkfs_makevfat(Partition *part)
|
||||
{
|
||||
unsigned long c,cc,ret;
|
||||
unsigned long ns,fs,ds,dc;
|
||||
unsigned char buf[512];
|
||||
|
||||
ns=part->disc->partitions[part->activePartition].numSectors;
|
||||
|
||||
if( ns < 66581 ){
|
||||
DBG((TXT("This is not possible due to insufficient sectors. Sorry\n")));
|
||||
return(MKFS_ERR_TOOLITTLESECTORS);
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
for(c=1<<6;c>=1;c>>=1){
|
||||
|
||||
/* First guess */
|
||||
ds = ns - 32;
|
||||
fs = ((ds/c)+127)/128;
|
||||
/* ds was guess too large, so fs is too large now too. */
|
||||
|
||||
for(cc=0;cc<2;cc++){
|
||||
|
||||
/* Round 2, error round */
|
||||
ds = ns - 32 - 2*fs;
|
||||
fs = ((ds/c)+127)/128;
|
||||
/* Since fs was too large, ds became too small. So the fs for this small ds is too small as well. */
|
||||
|
||||
/* Round 3, correction round */
|
||||
ds = ns - 32 - 2*fs;
|
||||
fs = ((ds/c)+127)/128;
|
||||
/* The fs was too small, so ds was too large. The calculated fs should be slightly too large. */
|
||||
|
||||
}
|
||||
|
||||
/* Round 4, finalise */
|
||||
ds = ns - 32 - 2*fs;
|
||||
|
||||
dc = ds / c;
|
||||
if(ret<(fs*128-dc)/128)ret=(fs*128-dc)/128;
|
||||
|
||||
/* Check if with current setting we have a valid fat ? */
|
||||
|
||||
if(dc >= 65525 + 16){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate BPB */
|
||||
memClr(buf,512);
|
||||
|
||||
/* Boot code */
|
||||
*(buf+0)=0xE9; *(buf+1)=0x00; *(buf+2)=0x00; /* RESET */
|
||||
|
||||
/* OEM name */
|
||||
memCpy("DSCOSMSH",buf+3,8);
|
||||
|
||||
/* Bytes/Sector */
|
||||
// mtmt *((unsigned short*)(buf+11)) = 512;
|
||||
ex_setb16(buf, 11, 512);
|
||||
|
||||
/* Sectors/Cluster */
|
||||
*(buf+13) = c;
|
||||
|
||||
/* Reserved Sectors */
|
||||
// mtmt *((unsigned short*)(buf+14)) = 32;
|
||||
ex_setb16(buf, 14, 32);
|
||||
|
||||
/* Number of FAT Tables */
|
||||
*(buf+16) = 2;
|
||||
|
||||
/* RootEntryCount */
|
||||
// mtmt *((unsigned short*)(buf+17)) = 0;
|
||||
ex_setb16(buf, 17, 0);
|
||||
|
||||
/* Total Sector Count __16 */
|
||||
// mtmt *((unsigned short*)(buf+19)) = 0;
|
||||
ex_setb16(buf, 19, 0);
|
||||
|
||||
/* Media (crap) */
|
||||
*(buf+21) = 0xF8;
|
||||
|
||||
/* FAT size 16 */
|
||||
// mtmt *((unsigned short*)(buf+22)) = 0;
|
||||
ex_setb16(buf, 22, 0);
|
||||
|
||||
/* Total Sector Count __32 */
|
||||
// mtmt *((unsigned long*)(buf+32)) = ns;
|
||||
ex_setb32(buf, 32, ns);
|
||||
|
||||
/* Fat Size 32 */
|
||||
// mtmt *((unsigned long*)(buf+36)) = fs;
|
||||
ex_setb32(buf, 26, fs);
|
||||
|
||||
/* First Cluster Root Dir */
|
||||
// mtmt *((unsigned long*)(buf+44)) = 2;
|
||||
ex_setb32(buf, 44, 2);
|
||||
|
||||
/* VolumeID */
|
||||
// mtmt *((unsigned long*)(buf+67)) = 0x13371337;
|
||||
ex_setb32(buf, 67, 0x13371337);
|
||||
|
||||
/* Volume Label */
|
||||
memCpy("DISCOSMASH!",buf+71,11);
|
||||
|
||||
/* Filesystemtype */
|
||||
memCpy("FAT32 ",buf+82,8);
|
||||
|
||||
/* Magic */
|
||||
*(buf+510) = 0x55; *(buf+511) = 0xAA;
|
||||
|
||||
part_writeBuf(part,0,buf);
|
||||
|
||||
memClr(buf,512);
|
||||
for(c=32;c<(32+2*fs);c++){
|
||||
part_writeBuf(part,c,buf);
|
||||
}
|
||||
|
||||
/* mtmt
|
||||
*(((unsigned long*)buf) )=0x0FFFFFF8;
|
||||
*(((unsigned long*)buf)+1)=0x0FFFFFFF;
|
||||
*(((unsigned long*)buf)+2)=0x0FFFFFF8;
|
||||
*/
|
||||
ex_setb32(buf, 0, 0x0FFFFFF8);
|
||||
ex_setb32(buf, 4, 0x0FFFFFFF);
|
||||
ex_setb32(buf, 8, 0x0FFFFFF8);
|
||||
|
||||
|
||||
part_writeBuf(part,32,buf);
|
||||
part_writeBuf(part,32+fs,buf);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
152
poc/lpc2148_efsl/src/partition.c
Normal file
152
poc/lpc2148_efsl/src/partition.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : partition.c *
|
||||
* Description : These functions are partition specific. Searching FAT type *
|
||||
* partitions and read/write functions to partitions. *
|
||||
* *
|
||||
* 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 "partition.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* void part_initPartition(Partition *part,Disc* refDisc)
|
||||
* Description: This function searches the 4 partitions for a FAT class partition
|
||||
* and marks the first one found as the active to be used partition.
|
||||
*/
|
||||
void part_initPartition(Partition *part,Disc* refDisc)
|
||||
{
|
||||
eint16 c;
|
||||
|
||||
part->disc=refDisc;
|
||||
part->activePartition=-1; /* No partition selected */
|
||||
part_setError(part,PART_NOERROR);
|
||||
for(c=3;c>=0;c--){
|
||||
if(part_isFatPart(part->disc->partitions[c].type))
|
||||
part->activePartition=c;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/* ****************************************************************************
|
||||
* eint16 part_isFatPart(euint8 type)
|
||||
* Description: This functions checks if a partitiontype (eint8) is of the FAT
|
||||
* type in the broadest sense. I
|
||||
* Return value: If it is FAT, returns 1, otherwise 0.
|
||||
*/
|
||||
eint16 part_isFatPart(euint8 type)
|
||||
{
|
||||
if(type == PT_FAT12 ||
|
||||
type == PT_FAT16A ||
|
||||
type == PT_FAT16 ||
|
||||
type == PT_FAT32 ||
|
||||
type == PT_FAT32A ||
|
||||
type == PT_FAT16B )
|
||||
{
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
esint8 part_readBuf(Partition *part, euint32 address, euint8* buf)
|
||||
{
|
||||
return(if_readBuf(part->disc->ioman->iface,part_getRealLBA(part,address), buf));
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* eint16 part_writeBuf(Partition *part,euint32 address,euint8* buf)
|
||||
* Description: This function writes 512 bytes, from buf. It's offset is address
|
||||
* sectors from the beginning of the partition.
|
||||
* Return value: It returns whatever the hardware function returns. (-1=error)
|
||||
*/
|
||||
eint16 part_writeBuf(Partition *part,euint32 address,euint8* buf)
|
||||
{
|
||||
/*DBG((TXT("part_writeBuf :: %li\n"),address));*/
|
||||
return(if_writeBuf(part->disc->ioman->iface,part_getRealLBA(part,address),buf));
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/* ****************************************************************************
|
||||
* euint32 part_getRealLBA(Partition *part,euint32 address)
|
||||
* Description: This function calculates what the partition offset for
|
||||
* a partition is + the address.
|
||||
* Return value: Sector address.
|
||||
*/
|
||||
euint32 part_getRealLBA(Partition *part,euint32 address)
|
||||
{
|
||||
return(part->disc->partitions[part->activePartition].LBA_begin+address);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/* ****************************************************************************
|
||||
* euint8* part_getSect(Partition *part, euint32 address, euint8 mode)
|
||||
* Description: This function calls ioman_getSector, but recalculates the sector
|
||||
* address to be partition relative.
|
||||
* Return value: Whatever getSector returns. (pointer or 0)
|
||||
*/
|
||||
euint8* part_getSect(Partition *part, euint32 address, euint8 mode)
|
||||
{
|
||||
return(ioman_getSector(part->disc->ioman,part_getRealLBA(part,address),mode));
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* esint8 part_relSect(Partition *part, euint8* buf)
|
||||
* Description: This function calls ioman_releaseSector.
|
||||
* Return value: Whatever releaseSector returns.
|
||||
*/
|
||||
esint8 part_relSect(Partition *part, euint8* buf)
|
||||
{
|
||||
return(ioman_releaseSector(part->disc->ioman,buf));
|
||||
}
|
||||
|
||||
esint8 part_flushPart(Partition *part,euint32 addr_l, euint32 addr_h)
|
||||
{
|
||||
return(
|
||||
ioman_flushRange(part->disc->ioman,part_getRealLBA(part,addr_l),part_getRealLBA(part,addr_h))
|
||||
);
|
||||
}
|
||||
|
||||
esint8 part_directSectorRead(Partition *part,euint32 address, euint8* buf)
|
||||
{
|
||||
return(
|
||||
ioman_directSectorRead(part->disc->ioman,part_getRealLBA(part,address),buf)
|
||||
);
|
||||
}
|
||||
|
||||
esint8 part_directSectorWrite(Partition *part,euint32 address, euint8* buf)
|
||||
{
|
||||
return(
|
||||
ioman_directSectorWrite(part->disc->ioman,part_getRealLBA(part,address),buf)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
82
poc/lpc2148_efsl/src/plibc.c
Normal file
82
poc/lpc2148_efsl/src/plibc.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*****************************************************************************\
|
||||
* 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<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>0){
|
||||
*((eint8*)pdest+size-1)=*((eint8*)psrc+size-1);
|
||||
size--;
|
||||
}
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void memClr(void *pdest,euint32 size)
|
||||
{
|
||||
while(size>0){
|
||||
*(((eint8*)pdest)+size-1)=0x00;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
void memSet(void *pdest,euint32 size,euint8 data)
|
||||
{
|
||||
while(size>0){
|
||||
*(((eint8*)pdest)+size-1)=data;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
352
poc/lpc2148_efsl/src/regressiontest.c
Normal file
352
poc/lpc2148_efsl/src/regressiontest.c
Normal file
@@ -0,0 +1,352 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------- ----------------------------------- *
|
||||
* *
|
||||
* Filename : regressiontest.c *
|
||||
* Description : This file contains a regressiontest (obsolete) *
|
||||
* *
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "interfaces/helper.h"
|
||||
#include "interfaces/linuxfile.h"
|
||||
#include "disc.h"
|
||||
#include "partition.h"
|
||||
#include "fs.h"
|
||||
#include "file.h"
|
||||
#include "mkfs.h"
|
||||
#include "ioman.h"
|
||||
#include "debug.h"
|
||||
#include "extract.h"
|
||||
#include "plibc.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
hwInterface *lfile=0;
|
||||
IOManager *ioman=0;
|
||||
Disc *disc=0;
|
||||
Partition *part=0;
|
||||
FileSystem *fs=0;
|
||||
File *fr=0;
|
||||
File *fw=0;
|
||||
FILE *out=0;
|
||||
unsigned char buf[4096];
|
||||
|
||||
int c,r,ir;
|
||||
|
||||
/*debug_init();*/
|
||||
|
||||
switch(argv[1][0]){
|
||||
case '0':
|
||||
lfile = malloc(sizeof(*lfile));
|
||||
ioman = malloc(sizeof(*ioman));
|
||||
disc = malloc(sizeof(*disc));
|
||||
part = malloc(sizeof(*part));
|
||||
|
||||
if_initInterface(lfile,"regtest.16");
|
||||
ioman_init(ioman,lfile,0);
|
||||
disc_initDisc(disc,ioman);
|
||||
memClr(disc->partitions,sizeof(PartitionField)*4);
|
||||
disc->partitions[0].type=0x0B;
|
||||
disc->partitions[0].LBA_begin=0;
|
||||
disc->partitions[0].numSectors=lfile->sectorCount;
|
||||
part_initPartition(part,disc);
|
||||
|
||||
fs = malloc(sizeof(*fs));
|
||||
if( (fs_initFs(fs,part)) != 0){
|
||||
printf("Unable to init the filesystem\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
fr = malloc(sizeof(*fr));
|
||||
if ( (file_fopen(fr,fs,"file.r",MODE_READ)) != 0){
|
||||
printf("Unable to open the file file.r\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
out=fopen("REG_FILE_16_OUT","w");
|
||||
|
||||
c=0;
|
||||
while( (r=file_fread(fr,c,4096,buf)) != 0){
|
||||
c+=r;
|
||||
fwrite(buf,r,1,out);
|
||||
}
|
||||
file_fclose(fr);
|
||||
fclose(out);
|
||||
fs_umount(fs);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
|
||||
lfile = malloc(sizeof(*lfile));
|
||||
ioman = malloc(sizeof(*ioman));
|
||||
disc = malloc(sizeof(*disc));
|
||||
part = malloc(sizeof(*part));
|
||||
|
||||
if_initInterface(lfile,"regtest.32");
|
||||
ioman_init(ioman,lfile,0);
|
||||
disc_initDisc(disc,ioman);
|
||||
memClr(disc->partitions,sizeof(PartitionField)*4);
|
||||
disc->partitions[0].type=0x0B;
|
||||
disc->partitions[0].LBA_begin=0;
|
||||
disc->partitions[0].numSectors=lfile->sectorCount;
|
||||
part_initPartition(part,disc);
|
||||
|
||||
fs = malloc(sizeof(*fs));
|
||||
if( (fs_initFs(fs,part)) != 0){
|
||||
printf("Unable to init the filesystem\n");
|
||||
return(-1);
|
||||
}
|
||||
fr = malloc(sizeof(*fr));
|
||||
if ( (file_fopen(fr,fs,"file.r",MODE_READ)) != 0){
|
||||
printf("Unable to open the file file.r\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
out=fopen("REG_FILE_32_OUT","w");
|
||||
|
||||
c=0;
|
||||
while( (r=file_fread(fr,c,4096,buf)) != 0){
|
||||
c+=r;
|
||||
fwrite(buf,r,1,out);
|
||||
}
|
||||
file_fclose(fr);
|
||||
fclose(out);
|
||||
fs_umount(fs);
|
||||
|
||||
break;
|
||||
|
||||
case '2':
|
||||
|
||||
lfile = malloc(sizeof(*lfile));
|
||||
ioman = malloc(sizeof(*ioman));
|
||||
disc = malloc(sizeof(*disc));
|
||||
part = malloc(sizeof(*part));
|
||||
fs = malloc(sizeof(*fs));
|
||||
fr = malloc(sizeof(*fr));
|
||||
fw = malloc(sizeof(*fw));
|
||||
|
||||
if_initInterface(lfile,"regtestrw.32");
|
||||
ioman_init(ioman,lfile,0);
|
||||
disc_initDisc(disc,ioman);
|
||||
memClr(disc->partitions,sizeof(PartitionField)*4);
|
||||
disc->partitions[0].type=0x0B;
|
||||
disc->partitions[0].LBA_begin=0;
|
||||
disc->partitions[0].numSectors=lfile->sectorCount;
|
||||
part_initPartition(part,disc);
|
||||
|
||||
fs = malloc(sizeof(*fs));
|
||||
if( (fs_initFs(fs,part)) != 0){
|
||||
printf("Unable to init the filesystem\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if((file_fopen(fr,fs,"file.r",'r'))!=0){
|
||||
printf("Unable to open %s for reading...\n","file.r");
|
||||
exit(0);
|
||||
}
|
||||
if((file_fopen(fw,fs,"file.w",'w'))!=0){
|
||||
printf("Unable to open %s for writing...\n","file.w");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ir = atoi(argv[2]);
|
||||
|
||||
while((r = file_read(fr,ir,buf))>0){
|
||||
file_write(fw,r,buf);
|
||||
}
|
||||
|
||||
file_fclose(fr);
|
||||
file_fclose(fw);
|
||||
|
||||
if((file_fopen(fr,fs,"file.w",'r'))!=0){
|
||||
printf("Unable to open %s for reading...\n","file.w");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
out=fopen("REG_FILE_RW32_OUT","w");
|
||||
|
||||
while((r = file_read(fr,ir/2+3,buf))>0){
|
||||
fwrite(buf,1,r,out);
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
file_fclose(fr);
|
||||
fs_umount(fs);
|
||||
|
||||
break;
|
||||
|
||||
case '3':
|
||||
lfile = malloc(sizeof(*lfile));
|
||||
ioman = malloc(sizeof(*ioman));
|
||||
disc = malloc(sizeof(*disc));
|
||||
part = malloc(sizeof(*part));
|
||||
|
||||
if_initInterface(lfile,"regtest.12");
|
||||
ioman_init(ioman,lfile,0);
|
||||
disc_initDisc(disc,ioman);
|
||||
memClr(disc->partitions,sizeof(PartitionField)*4);
|
||||
disc->partitions[0].type=0x0B;
|
||||
disc->partitions[0].LBA_begin=0;
|
||||
disc->partitions[0].numSectors=lfile->sectorCount;
|
||||
part_initPartition(part,disc);
|
||||
|
||||
fs = malloc(sizeof(*fs));
|
||||
if( (fs_initFs(fs,part)) != 0){
|
||||
printf("Unable to init the filesystem\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
fr = malloc(sizeof(*fr));
|
||||
if ( (file_fopen(fr,fs,"file.r",MODE_READ)) != 0){
|
||||
printf("Unable to open the file file.r\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
out=fopen("REG_FILE_12_OUT","w");
|
||||
|
||||
c=0;
|
||||
while( (r=file_fread(fr,c,4096,buf)) != 0){
|
||||
c+=r;
|
||||
fwrite(buf,r,1,out);
|
||||
}
|
||||
file_fclose(fr);
|
||||
fclose(out);
|
||||
fs_umount(fs);
|
||||
|
||||
break;
|
||||
|
||||
case '4':
|
||||
|
||||
lfile = malloc(sizeof(*lfile));
|
||||
ioman = malloc(sizeof(*ioman));
|
||||
disc = malloc(sizeof(*disc));
|
||||
part = malloc(sizeof(*part));
|
||||
fs = malloc(sizeof(*fs));
|
||||
fr = malloc(sizeof(*fr));
|
||||
fw = malloc(sizeof(*fw));
|
||||
|
||||
if_initInterface(lfile,"regtestrw.12");
|
||||
ioman_init(ioman,lfile,0);
|
||||
disc_initDisc(disc,ioman);
|
||||
memClr(disc->partitions,sizeof(PartitionField)*4);
|
||||
disc->partitions[0].type=0x0B;
|
||||
disc->partitions[0].LBA_begin=0;
|
||||
disc->partitions[0].numSectors=lfile->sectorCount;
|
||||
part_initPartition(part,disc);
|
||||
|
||||
fs = malloc(sizeof(*fs));
|
||||
if( (fs_initFs(fs,part)) != 0){
|
||||
printf("Unable to init the filesystem\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if((file_fopen(fr,fs,"file.r",'r'))!=0){
|
||||
printf("Unable to open %s for reading...\n","file.r");
|
||||
exit(0);
|
||||
}
|
||||
if((file_fopen(fw,fs,"file.w",'w'))!=0){
|
||||
printf("Unable to open %s for writing...\n","file.w");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ir = atoi(argv[2]);
|
||||
|
||||
while((r = file_read(fr,ir,buf))>0){
|
||||
file_write(fw,r,buf);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
file_fclose(fr);
|
||||
file_fclose(fw);
|
||||
|
||||
if((file_fopen(fr,fs,"file.w",'r'))!=0){
|
||||
printf("Unable to open %s for reading...\n","file.w");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
out=fopen("REG_FILE_RW12_OUT","w");
|
||||
|
||||
while((r = file_read(fr,ir/2+3,buf))>0){
|
||||
fwrite(buf,1,r,out);
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
file_fclose(fr);
|
||||
fs_umount(fs);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown test\n");
|
||||
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint16 efsl_getYear(void)
|
||||
{
|
||||
return(2005);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 efsl_getMonth(void)
|
||||
{
|
||||
return(5);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 efsl_getDay(void)
|
||||
{
|
||||
return(11);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 efsl_getHour(void)
|
||||
{
|
||||
return(13);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 efsl_getMinute(void)
|
||||
{
|
||||
return(14);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 efsl_getSecond(void)
|
||||
{
|
||||
return(40);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
89
poc/lpc2148_efsl/src/time.c
Normal file
89
poc/lpc2148_efsl/src/time.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*****************************************************************************\
|
||||
* 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>127?127<<9:(y&0x3F)<<9) |
|
||||
((m==0||m>12)?1:(m&0xF)<<5) |
|
||||
((d==0||d>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>23?0:(h&0x1F)<<11) |
|
||||
(m>59?0:(m&0x3F)<<5) |
|
||||
(s>59?0:(s-s%2)/2)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
euint8 fs_hasTimeSupport(void)
|
||||
{
|
||||
#ifdef DATE_TIME_SUPPORT
|
||||
return(1);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
230
poc/lpc2148_efsl/src/ui.c
Normal file
230
poc/lpc2148_efsl/src/ui.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*****************************************************************************\
|
||||
* 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->type == FAT12) || (fs->type == FAT16) )
|
||||
{
|
||||
for(i=0;i<=(fs->volumeId.RootEntryCount/16);i++)
|
||||
{
|
||||
loc.Sector=fs->FirstSectorRootDir + i;
|
||||
part_readBuf(fs->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->part,loc.Sector, buf);
|
||||
fileEntry = *(((FileRecord*)buf) + loc.Offset);
|
||||
startCluster = (((unsigned long)fileEntry.FirstClusterHigh)<<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<16;fileEntryCount++)
|
||||
{
|
||||
fileEntry = *(((FileRecord*)buf) + fileEntryCount);
|
||||
if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) )
|
||||
{
|
||||
if
|
||||
(
|
||||
(fileEntry.FileName[0]>='A' && fileEntry.FileName[0]<='Z')
|
||||
||
|
||||
(fileEntry.FileName[0]>='0' && fileEntry.FileName[0]<='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->part,loc.Sector,IOM_MODE_READWRITE);
|
||||
firstCluster = ex_getb16(buf,loc.Offset*32+20);
|
||||
firstCluster <<= 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->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->part,loc.Sector,IOM_MODE_READWRITE);
|
||||
|
||||
dir_getFatFileName(dirname,ffname);
|
||||
memClr(&direntry,sizeof(direntry));
|
||||
memCpy(ffname,&direntry,11);
|
||||
direntry.FileSize = 0;
|
||||
direntry.FirstClusterHigh=nc>>16;
|
||||
direntry.FirstClusterLow=nc&0xFFFF;
|
||||
direntry.Attribute = ATTR_DIRECTORY;
|
||||
memCpy(&direntry,buf+(32*loc.Offset),32);
|
||||
|
||||
part_relSect(fs->part,buf);
|
||||
|
||||
buf = part_getSect(fs->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>>16;
|
||||
direntry.FirstClusterLow=nc&0xFFFF;
|
||||
memCpy(&direntry,buf,32);
|
||||
|
||||
if(fs->type == FAT32 && parentdir == fs->volumeId.RootCluster){
|
||||
parentdir = 0;
|
||||
}
|
||||
if(fs->type != FAT32 && parentdir<=1){
|
||||
parentdir = 0;
|
||||
}
|
||||
|
||||
memClr(&direntry,sizeof(direntry));
|
||||
memCpy(".. ",&direntry,11);
|
||||
direntry.Attribute = ATTR_DIRECTORY;
|
||||
direntry.FileSize = 0;
|
||||
direntry.FirstClusterHigh=parentdir>>16;
|
||||
direntry.FirstClusterLow=parentdir&0xFFFF;
|
||||
memCpy(&direntry,buf+32,32);
|
||||
|
||||
part_relSect(fs->part,buf);
|
||||
|
||||
fat_setNextClusterAddress(fs,nc,fat_giveEocMarker(fs));
|
||||
|
||||
return(0);
|
||||
}
|
||||
Reference in New Issue
Block a user