You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
598 lines
14 KiB
C
598 lines
14 KiB
C
/*
|
|
* FreeRTOS+FAT SL V1.0.1 (C) 2014 HCC Embedded
|
|
*
|
|
* The FreeRTOS+FAT SL license terms are different to the FreeRTOS license
|
|
* terms.
|
|
*
|
|
* FreeRTOS+FAT SL uses a dual license model that allows the software to be used
|
|
* under a standard GPL open source license, or a commercial license. The
|
|
* standard GPL license (unlike the modified GPL license under which FreeRTOS
|
|
* itself is distributed) requires that all software statically linked with
|
|
* FreeRTOS+FAT SL is also distributed under the same GPL V2 license terms.
|
|
* Details of both license options follow:
|
|
*
|
|
* - Open source licensing -
|
|
* FreeRTOS+FAT SL is a free download and may be used, modified, evaluated and
|
|
* distributed without charge provided the user adheres to version two of the
|
|
* GNU General Public License (GPL) and does not remove the copyright notice or
|
|
* this text. The GPL V2 text is available on the gnu.org web site, and on the
|
|
* following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
|
|
*
|
|
* - Commercial licensing -
|
|
* Businesses and individuals who for commercial or other reasons cannot comply
|
|
* with the terms of the GPL V2 license must obtain a commercial license before
|
|
* incorporating FreeRTOS+FAT SL into proprietary software for distribution in
|
|
* any form. Commercial licenses can be purchased from
|
|
* http://shop.freertos.org/fat_sl and do not require any source files to be
|
|
* changed.
|
|
*
|
|
* FreeRTOS+FAT SL is distributed in the hope that it will be useful. You
|
|
* cannot use FreeRTOS+FAT SL unless you agree that you use the software 'as
|
|
* is'. FreeRTOS+FAT SL is provided WITHOUT ANY WARRANTY; without even the
|
|
* implied warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A
|
|
* PARTICULAR PURPOSE. Real Time Engineers Ltd. and HCC Embedded disclaims all
|
|
* conditions and terms, be they implied, expressed, or statutory.
|
|
*
|
|
* http://www.FreeRTOS.org
|
|
* http://www.FreeRTOS.org/FreeRTOS-Plus
|
|
*
|
|
*/
|
|
#include "../../api/fat_sl.h"
|
|
|
|
#include "fat.h"
|
|
#include "util.h"
|
|
#include "volume.h"
|
|
#include "drv.h"
|
|
|
|
#include "../../version/ver_fat_sl.h"
|
|
#if VER_FAT_SL_MAJOR != 5 || VER_FAT_SL_MINOR != 2
|
|
#error Incompatible FAT_SL version number!
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_writefatsector
|
|
*
|
|
* writing fat sector into volume, this function check if fat was modified
|
|
* and writes data
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_writefatsector ( void )
|
|
{
|
|
unsigned char a;
|
|
|
|
if ( gl_volume.modified )
|
|
{
|
|
unsigned long fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;
|
|
|
|
if ( gl_volume.fatsector >= gl_volume.firstfat.num )
|
|
{
|
|
return F_ERR_INVALIDSECTOR;
|
|
}
|
|
|
|
for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )
|
|
{
|
|
unsigned char ret;
|
|
ret = _f_writeglsector( fatsector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
fatsector += gl_volume.firstfat.num;
|
|
}
|
|
|
|
gl_volume.modified = 0;
|
|
}
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_writefatsector */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_getfatsector
|
|
*
|
|
* read a fat sector from media
|
|
*
|
|
* INPUTS
|
|
*
|
|
* sector - which fat sector is needed, this sector number is zero based
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_getfatsector ( unsigned long sector )
|
|
{
|
|
unsigned char a;
|
|
|
|
if ( gl_volume.fatsector != sector )
|
|
{
|
|
unsigned long fatsector;
|
|
|
|
gl_volume.fatsector = sector;
|
|
|
|
if ( gl_volume.fatsector >= gl_volume.firstfat.num )
|
|
{
|
|
return F_ERR_INVALIDSECTOR;
|
|
}
|
|
|
|
fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;
|
|
|
|
for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )
|
|
{
|
|
if ( !_f_readglsector( fatsector ) )
|
|
{
|
|
return F_NO_ERROR;
|
|
}
|
|
|
|
fatsector += gl_volume.firstfat.num;
|
|
}
|
|
|
|
return F_ERR_READ;
|
|
}
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_getfatsector */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_setclustervalue
|
|
*
|
|
* set a cluster value in the FAT
|
|
*
|
|
* INPUTS
|
|
*
|
|
* cluster - which cluster's value need to be modified
|
|
* data - new value of the cluster
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_setclustervalue ( unsigned long cluster, unsigned long _tdata )
|
|
{
|
|
unsigned char ret;
|
|
|
|
switch ( gl_volume.mediatype )
|
|
{
|
|
case F_FAT16_MEDIA:
|
|
{
|
|
unsigned long sector = cluster;
|
|
unsigned short s_data = (unsigned short)( _tdata & 0xffff ); /*keep 16 bit only*/
|
|
|
|
sector /= ( F_SECTOR_SIZE / 2 );
|
|
cluster -= sector * ( F_SECTOR_SIZE / 2 );
|
|
|
|
ret = _f_getfatsector( sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( _f_getword( &gl_sector[cluster << 1] ) != s_data )
|
|
{
|
|
_f_setword( &gl_sector[cluster << 1], s_data );
|
|
gl_volume.modified = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case F_FAT12_MEDIA:
|
|
{
|
|
unsigned char f12new[2];
|
|
unsigned long sector = cluster;
|
|
unsigned short pos;
|
|
unsigned short s_data = (unsigned short)( _tdata & 0x0fff ); /*keep 12 bit only*/
|
|
|
|
if ( cluster & 1 )
|
|
{
|
|
s_data <<= 4;
|
|
}
|
|
|
|
_f_setword( f12new, s_data ); /*create new data*/
|
|
|
|
sector += sector / 2; /*1.5 bytes*/
|
|
pos = (unsigned short)( sector % F_SECTOR_SIZE );
|
|
sector /= F_SECTOR_SIZE;
|
|
|
|
ret = _f_getfatsector( sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( cluster & 1 )
|
|
{
|
|
f12new[0] |= gl_sector[pos] & 0x0f;
|
|
}
|
|
|
|
if ( gl_sector[pos] != f12new[0] )
|
|
{
|
|
gl_sector[pos] = f12new[0];
|
|
gl_volume.modified = 1;
|
|
}
|
|
|
|
pos++;
|
|
if ( pos >= 512 )
|
|
{
|
|
ret = _f_getfatsector( sector + 1 );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
pos = 0;
|
|
}
|
|
|
|
if ( !( cluster & 1 ) )
|
|
{
|
|
f12new[1] |= gl_sector[pos] & 0xf0;
|
|
}
|
|
|
|
if ( gl_sector[pos] != f12new[1] )
|
|
{
|
|
gl_sector[pos] = f12new[1];
|
|
gl_volume.modified = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case F_FAT32_MEDIA:
|
|
{
|
|
unsigned long sector = cluster;
|
|
unsigned long oldv;
|
|
|
|
sector /= ( F_SECTOR_SIZE / 4 );
|
|
cluster -= sector * ( F_SECTOR_SIZE / 4 );
|
|
|
|
ret = _f_getfatsector( sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
oldv = _f_getlong( &gl_sector[cluster << 2] );
|
|
|
|
_tdata &= 0x0fffffff;
|
|
_tdata |= oldv & 0xf0000000; /*keep 4 top bits*/
|
|
|
|
if ( _tdata != oldv )
|
|
{
|
|
_f_setlong( &gl_sector[cluster << 2], _tdata );
|
|
gl_volume.modified = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return F_ERR_INVALIDMEDIA;
|
|
} /* switch */
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_setclustervalue */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_getclustervalue
|
|
*
|
|
* get a cluster value from FAT
|
|
*
|
|
* INPUTS
|
|
*
|
|
* cluster - which cluster value is requested
|
|
* pvalue - where to store data
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_getclustervalue ( unsigned long cluster, unsigned long * pvalue )
|
|
{
|
|
unsigned long val;
|
|
unsigned char ret;
|
|
|
|
switch ( gl_volume.mediatype )
|
|
{
|
|
case F_FAT16_MEDIA:
|
|
{
|
|
unsigned long sector = cluster;
|
|
sector /= ( F_SECTOR_SIZE / 2 );
|
|
cluster -= sector * ( F_SECTOR_SIZE / 2 );
|
|
|
|
ret = _f_getfatsector( sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
val = _f_getword( &gl_sector[cluster << 1] );
|
|
if ( val >= ( F_CLUSTER_RESERVED & 0xffff ) )
|
|
{
|
|
val |= 0x0ffff000; /*extends it*/
|
|
}
|
|
|
|
if ( pvalue )
|
|
{
|
|
*pvalue = val;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case F_FAT12_MEDIA:
|
|
{
|
|
unsigned char dataf12[2];
|
|
unsigned long sector = cluster;
|
|
unsigned short pos;
|
|
|
|
sector += sector / 2; /*1.5 bytes*/
|
|
pos = (unsigned short)( sector % F_SECTOR_SIZE );
|
|
sector /= F_SECTOR_SIZE;
|
|
|
|
ret = _f_getfatsector( sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
dataf12[0] = gl_sector[pos++];
|
|
|
|
if ( pos >= 512 )
|
|
{
|
|
ret = _f_getfatsector( sector + 1 );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
pos = 0;
|
|
}
|
|
|
|
dataf12[1] = gl_sector[pos];
|
|
|
|
val = _f_getword( dataf12 );
|
|
|
|
if ( cluster & 1 )
|
|
{
|
|
val = val >> 4;
|
|
}
|
|
else
|
|
{
|
|
val = val & 0xfff;
|
|
}
|
|
|
|
if ( val >= ( F_CLUSTER_RESERVED & 0xfff ) )
|
|
{
|
|
val |= 0x0ffff000; /*extends it*/
|
|
}
|
|
|
|
if ( pvalue )
|
|
{
|
|
*pvalue = val;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case F_FAT32_MEDIA:
|
|
{
|
|
unsigned long sector = cluster;
|
|
sector /= ( F_SECTOR_SIZE / 4 );
|
|
cluster -= sector * ( F_SECTOR_SIZE / 4 );
|
|
|
|
ret = _f_getfatsector( sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( pvalue )
|
|
{
|
|
*pvalue = _f_getlong( &gl_sector[cluster << 2] ) & 0x0fffffff; /*28bit*/
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return F_ERR_INVALIDMEDIA;
|
|
} /* switch */
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_getclustervalue */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_clustertopos
|
|
*
|
|
* convert a cluster position into physical sector position
|
|
*
|
|
* INPUTS
|
|
*
|
|
* cluster - original cluster position
|
|
* pos - position structure to fills the position
|
|
*
|
|
***************************************************************************/
|
|
void _f_clustertopos ( unsigned long cluster, F_POS * pos )
|
|
{
|
|
pos->cluster = cluster;
|
|
|
|
if ( !cluster )
|
|
{
|
|
pos->sector = gl_volume.root.sector;
|
|
pos->sectorend = pos->sector + gl_volume.root.num;
|
|
}
|
|
else
|
|
{
|
|
unsigned long sectorcou = gl_volume.bootrecord.sector_per_cluster;
|
|
pos->sector = ( pos->cluster - 2 ) * sectorcou + gl_volume._tdata.sector;
|
|
pos->sectorend = pos->sector + sectorcou;
|
|
}
|
|
|
|
if ( cluster >= F_CLUSTER_RESERVED )
|
|
{
|
|
pos->sectorend = 0;
|
|
}
|
|
|
|
pos->pos = 0;
|
|
} /* _f_clustertopos */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_getcurrsector
|
|
*
|
|
* read current sector according in file structure
|
|
*
|
|
* INPUTS
|
|
* f - internal file pointer
|
|
*
|
|
* RETURNS
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_getcurrsector ( void )
|
|
{
|
|
unsigned char ret;
|
|
unsigned long cluster;
|
|
|
|
if ( gl_file.pos.sector == gl_file.pos.sectorend )
|
|
{
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
ret = _f_getclustervalue( gl_file.pos.cluster, &cluster );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( cluster >= F_CLUSTER_RESERVED )
|
|
{
|
|
return F_ERR_EOF;
|
|
}
|
|
|
|
_f_clustertopos( cluster, &gl_file.pos );
|
|
}
|
|
|
|
return _f_readglsector( gl_file.pos.sector );
|
|
} /* _f_getcurrsector */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_alloccluster
|
|
*
|
|
* allocate cluster from FAT
|
|
*
|
|
* INPUTS
|
|
* pcluster - where to store the allocated cluster number
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_alloccluster ( unsigned long * pcluster )
|
|
{
|
|
unsigned long maxcluster = gl_volume.maxcluster;
|
|
unsigned long cou;
|
|
unsigned long cluster = gl_volume.lastalloccluster;
|
|
unsigned long value;
|
|
unsigned char ret;
|
|
|
|
for ( cou = 0 ; cou < maxcluster ; cou++ )
|
|
{
|
|
if ( cluster >= maxcluster )
|
|
{
|
|
cluster = 0;
|
|
}
|
|
|
|
ret = _f_getclustervalue( cluster, &value );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( !value )
|
|
{
|
|
gl_volume.lastalloccluster = cluster + 1; /*set next one*/
|
|
*pcluster = cluster;
|
|
|
|
return F_NO_ERROR;
|
|
}
|
|
|
|
cluster++;
|
|
}
|
|
|
|
return F_ERR_NOMOREENTRY;
|
|
} /* _f_alloccluster */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_removechain
|
|
*
|
|
* remove cluster chain from fat
|
|
*
|
|
* INPUTS
|
|
* cluster - first cluster in the cluster chain
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_removechain ( unsigned long cluster )
|
|
{
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
|
|
if ( cluster < gl_volume.lastalloccluster ) /*this could be the begining of alloc*/
|
|
{
|
|
gl_volume.lastalloccluster = cluster;
|
|
}
|
|
|
|
while ( cluster < F_CLUSTER_RESERVED && cluster >= 2 )
|
|
{
|
|
unsigned long nextcluster;
|
|
|
|
unsigned char ret = _f_getclustervalue( cluster, &nextcluster );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_setclustervalue( cluster, F_CLUSTER_FREE );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
cluster = nextcluster;
|
|
}
|
|
|
|
return _f_writefatsector();
|
|
} /* _f_removechain */
|
|
|
|
|
|
|
|
|