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.
981 lines
25 KiB
C
981 lines
25 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 "../../psp/include/psp_string.h"
|
|
|
|
#include "volume.h"
|
|
#include "util.h"
|
|
#include "drv.h"
|
|
#include "fat.h"
|
|
#include "dir.h"
|
|
#include "file.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
|
|
|
|
#if F_FS_THREAD_AWARE == 1
|
|
#include "f_lock.h"
|
|
#endif
|
|
|
|
F_VOLUME gl_volume; /* only one volume */
|
|
F_FILE gl_file; /* file */
|
|
char gl_sector[F_SECTOR_SIZE]; /* actual sector */
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
F_FILE_CHANGED_EVENTFUNC f_filechangedevent;
|
|
#endif
|
|
|
|
|
|
/* Defines the number of sectors per cluster on a sector number basis */
|
|
typedef struct
|
|
{
|
|
unsigned long max_sectors;
|
|
unsigned char sector_per_cluster;
|
|
} t_FAT32_CS;
|
|
|
|
static const t_FAT32_CS FAT32_CS[] =
|
|
{
|
|
{ 0x00020000, 1 } /* ->64MB */
|
|
, { 0x00040000, 2 } /* ->128MB */
|
|
, { 0x00080000, 4 } /* ->256MB */
|
|
, { 0x01000000, 8 } /* ->8GB */
|
|
, { 0x02000000, 16 } /* ->16GB */
|
|
, { 0x0ffffff0, 32 } /* -> ... */
|
|
};
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_writebootrecord
|
|
*
|
|
* writing boot record onto a volume, it uses number of hidden sector variable
|
|
*
|
|
* INPUTS
|
|
* phy - media physical descriptor
|
|
*
|
|
* RETURNS
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
static unsigned char _f_writebootrecord ( F_PHY * phy )
|
|
{
|
|
unsigned char jump_code[] =
|
|
{
|
|
0xeb, 0x3c, 0x90
|
|
};
|
|
unsigned char oem_name[] = "MSDOS5.0";
|
|
unsigned char executable_marker[] =
|
|
{
|
|
0x55, 0xaa
|
|
};
|
|
unsigned char * ptr = (unsigned char *)gl_sector;
|
|
unsigned char rs;
|
|
unsigned short mre;
|
|
|
|
unsigned char ret;
|
|
unsigned char _n = 0;
|
|
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{ /*write FS_INFO*/
|
|
unsigned char a;
|
|
|
|
rs = 32 + 4;
|
|
mre = 0;
|
|
|
|
psp_memset( ptr, 0, F_SECTOR_SIZE );
|
|
|
|
for ( a = 0 ; a < rs ; a++ )
|
|
{
|
|
ret = _f_writeglsector( a ); /*erase reserved area*/
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ptr = _setlong( 0x41615252, ptr ); /*signature*/
|
|
ptr = _setcharzero( 480, ptr ); /*reserved*/
|
|
ptr = _setlong( 0x61417272, ptr ); /*signature*/
|
|
ptr = _setlong( 0xffffffff, ptr ); /*no last*/
|
|
ptr = _setlong( 0xffffffff, ptr ); /*no hint*/
|
|
ptr = _setcharzero( 12, ptr ); /*reserved*/
|
|
ptr = _setlong( 0xaa550000, ptr ); /*trail*/
|
|
|
|
|
|
ret = _f_writeglsector( 1 ); /*write FSINFO*/
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_writeglsector( 1 + 6 ); /*write FSINFO*/
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rs = 1;
|
|
mre = 512;
|
|
}
|
|
|
|
ptr = (unsigned char *)gl_sector;
|
|
ptr = _setchar( jump_code, sizeof( jump_code ), ptr );
|
|
ptr = _setchar( oem_name, sizeof( oem_name ) - 1, ptr );
|
|
ptr = _setword( F_SECTOR_SIZE, ptr );
|
|
*ptr++ = gl_volume.bootrecord.sector_per_cluster;
|
|
ptr = _setword( rs, ptr ); /* reserved sectors */
|
|
*ptr++ = 2; /* number of FATs */
|
|
ptr = _setword( mre, ptr ); /* max root entry */
|
|
if ( phy->number_of_sectors < 0x10000 )
|
|
{
|
|
ptr = _setword( (unsigned short)phy->number_of_sectors, ptr );
|
|
}
|
|
else
|
|
{
|
|
ptr = _setword( 0, ptr );
|
|
}
|
|
|
|
*ptr++ = 0xf0; /* media descriptor */
|
|
ptr = _setword( (unsigned short)gl_volume.bootrecord.sector_per_FAT, ptr );
|
|
ptr = _setword( phy->sector_per_track, ptr );
|
|
ptr = _setword( phy->number_of_heads, ptr );
|
|
ptr = _setlong( 0, ptr ); /* number of hidden sectors */
|
|
if ( phy->number_of_sectors >= 0x10000 )
|
|
{
|
|
ptr = _setlong( phy->number_of_sectors, ptr );
|
|
}
|
|
else
|
|
{
|
|
ptr = _setlong( 0, ptr ); /* number of sectors */
|
|
}
|
|
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
ptr = _setlong( gl_volume.bootrecord.sector_per_FAT32, ptr );
|
|
ptr = _setword( 0, ptr );
|
|
ptr = _setword( 0, ptr );
|
|
ptr = _setlong( 2, ptr );
|
|
ptr = _setword( 1, ptr );
|
|
ptr = _setword( 6, ptr );
|
|
ptr = _setchar( NULL, 12, ptr );
|
|
_n = 28;
|
|
}
|
|
|
|
|
|
ptr = _setword( 0, ptr ); /* logical drive num */
|
|
*ptr++ = 0x29; /* extended signature */
|
|
ptr = _setlong( 0x11223344, ptr );
|
|
ptr = _setchar( (const unsigned char *)"NO NAME ", 11, ptr ); /* volume name */
|
|
|
|
switch ( gl_volume.mediatype )
|
|
{
|
|
case F_FAT12_MEDIA:
|
|
ptr = _setchar( (const unsigned char *)"FAT12 ", 8, ptr );
|
|
break;
|
|
|
|
case F_FAT16_MEDIA:
|
|
ptr = _setchar( (const unsigned char *)"FAT16 ", 8, ptr );
|
|
break;
|
|
|
|
case F_FAT32_MEDIA:
|
|
ptr = _setchar( (const unsigned char *)"FAT32 ", 8, ptr );
|
|
break;
|
|
|
|
default:
|
|
return F_ERR_INVALIDMEDIA;
|
|
} /* switch */
|
|
|
|
ptr = _setchar( 0, 448 - _n, ptr );
|
|
ptr = _setchar( executable_marker, sizeof( executable_marker ), ptr );
|
|
|
|
if ( _n )
|
|
{
|
|
ret = _f_writeglsector( 6 );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
return _f_writeglsector( 0 ); /*write bootrecord*/
|
|
} /* _f_writebootrecord */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_buildsectors
|
|
*
|
|
* INPUTS
|
|
* phy - media physical descriptor
|
|
*
|
|
* calculate relative sector position from boot record
|
|
*
|
|
***************************************************************************/
|
|
static unsigned char _f_buildsectors ( F_PHY * phy )
|
|
{
|
|
gl_volume.mediatype = F_UNKNOWN_MEDIA;
|
|
|
|
|
|
if ( gl_volume.bootrecord.sector_per_FAT )
|
|
{
|
|
gl_volume.firstfat.sector = 1;
|
|
gl_volume.firstfat.num = gl_volume.bootrecord.sector_per_FAT;
|
|
gl_volume.root.sector = gl_volume.firstfat.sector + ( gl_volume.firstfat.num * (unsigned long)( gl_volume.bootrecord.number_of_FATs ) );
|
|
gl_volume.root.num = ( 512 * sizeof( F_DIRENTRY ) ) / F_SECTOR_SIZE;
|
|
|
|
gl_volume._tdata.sector = gl_volume.root.sector + gl_volume.root.num;
|
|
gl_volume._tdata.num = 0; /*??*/
|
|
}
|
|
else
|
|
{
|
|
gl_volume.firstfat.sector = ( 32 + 4 );
|
|
gl_volume.firstfat.num = gl_volume.bootrecord.sector_per_FAT32;
|
|
gl_volume._tdata.sector = gl_volume.firstfat.sector;
|
|
gl_volume._tdata.sector += gl_volume.firstfat.num * (unsigned long)( gl_volume.bootrecord.number_of_FATs );
|
|
gl_volume._tdata.num = 0; /*??*/
|
|
|
|
{
|
|
unsigned long sectorcou = gl_volume.bootrecord.sector_per_cluster;
|
|
gl_volume.root.sector = ( ( gl_volume.bootrecord.rootcluster - 2 ) * sectorcou ) + gl_volume._tdata.sector;
|
|
gl_volume.root.num = gl_volume.bootrecord.sector_per_cluster;
|
|
}
|
|
}
|
|
|
|
{
|
|
unsigned long maxcluster;
|
|
maxcluster = phy->number_of_sectors;
|
|
maxcluster -= gl_volume._tdata.sector;
|
|
maxcluster /= gl_volume.bootrecord.sector_per_cluster;
|
|
gl_volume.maxcluster = maxcluster;
|
|
}
|
|
|
|
if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xfff ) )
|
|
{
|
|
gl_volume.mediatype = F_FAT12_MEDIA;
|
|
}
|
|
else if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xffff ) )
|
|
{
|
|
gl_volume.mediatype = F_FAT16_MEDIA;
|
|
}
|
|
else
|
|
{
|
|
gl_volume.mediatype = F_FAT32_MEDIA;
|
|
}
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_buildsectors */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_prepareformat
|
|
*
|
|
* preparing boot record for formatting, it sets and calculates values
|
|
*
|
|
* INPUTS
|
|
* phy - media physical descriptor
|
|
* f_bootrecord - which bootrecord need to be prepare
|
|
* number_of_hidden_sectors - where boot record starts
|
|
* fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA
|
|
*
|
|
* RETURNS
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
static unsigned char _f_prepareformat ( F_PHY * phy, unsigned char fattype )
|
|
{
|
|
if ( !phy->number_of_sectors )
|
|
{
|
|
return F_ERR_INVALIDSECTOR;
|
|
}
|
|
|
|
gl_volume.bootrecord.number_of_FATs = 2;
|
|
gl_volume.bootrecord.media_descriptor = 0xf0;
|
|
|
|
if ( fattype != F_FAT32_MEDIA )
|
|
{
|
|
unsigned long _n;
|
|
switch ( fattype )
|
|
{
|
|
case F_FAT12_MEDIA:
|
|
_n = F_CLUSTER_RESERVED & 0xfff;
|
|
break;
|
|
|
|
case F_FAT16_MEDIA:
|
|
_n = F_CLUSTER_RESERVED & 0xffff;
|
|
break;
|
|
|
|
default:
|
|
return F_ERR_INVFATTYPE;
|
|
}
|
|
|
|
gl_volume.bootrecord.sector_per_cluster = 1;
|
|
while ( gl_volume.bootrecord.sector_per_cluster )
|
|
{
|
|
if ( phy->number_of_sectors / gl_volume.bootrecord.sector_per_cluster < _n )
|
|
{
|
|
break;
|
|
}
|
|
|
|
gl_volume.bootrecord.sector_per_cluster <<= 1;
|
|
}
|
|
|
|
if ( !gl_volume.bootrecord.sector_per_cluster )
|
|
{
|
|
return F_ERR_MEDIATOOLARGE;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
unsigned char i;
|
|
for ( i = 0 ; i<( sizeof( FAT32_CS ) / sizeof( t_FAT32_CS ) ) - 1 && phy->number_of_sectors>FAT32_CS[i].max_sectors ; i++ )
|
|
{
|
|
}
|
|
|
|
gl_volume.bootrecord.sector_per_cluster = FAT32_CS[i].sector_per_cluster;
|
|
}
|
|
|
|
if ( !gl_volume.bootrecord.sector_per_cluster )
|
|
{
|
|
return F_ERR_INVALIDMEDIA; /*fat16 cannot be there*/
|
|
}
|
|
|
|
{
|
|
long secpercl = gl_volume.bootrecord.sector_per_cluster;
|
|
long nfat = gl_volume.bootrecord.number_of_FATs;
|
|
unsigned long roots;
|
|
unsigned long fatsec;
|
|
|
|
roots = ( 512 * sizeof( F_DIRENTRY ) ) / F_SECTOR_SIZE;
|
|
|
|
switch ( fattype )
|
|
{
|
|
case F_FAT32_MEDIA:
|
|
{
|
|
unsigned long _n = (unsigned long)( 128 * secpercl + nfat );
|
|
fatsec = ( phy->number_of_sectors - ( 32 + 4 ) + 2 * secpercl );
|
|
fatsec += ( _n - 1 );
|
|
fatsec /= _n;
|
|
gl_volume.bootrecord.sector_per_FAT32 = fatsec;
|
|
gl_volume.bootrecord.sector_per_FAT = 0;
|
|
}
|
|
break;
|
|
|
|
case F_FAT16_MEDIA:
|
|
{
|
|
unsigned long _n = (unsigned long)( 256 * secpercl + nfat );
|
|
fatsec = ( phy->number_of_sectors - 1 - roots + 2 * secpercl );
|
|
fatsec += ( _n - 1 );
|
|
fatsec /= _n;
|
|
gl_volume.bootrecord.sector_per_FAT = (unsigned short)( fatsec );
|
|
}
|
|
break;
|
|
|
|
case F_FAT12_MEDIA:
|
|
{
|
|
unsigned long _n = (unsigned long)( 1024 * secpercl + 3 * nfat );
|
|
fatsec = ( phy->number_of_sectors - 1 - roots + 2 * secpercl );
|
|
fatsec *= 3;
|
|
fatsec += ( _n - 1 );
|
|
fatsec /= _n;
|
|
gl_volume.bootrecord.sector_per_FAT = (unsigned short)( fatsec );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return F_ERR_INVALIDMEDIA;
|
|
} /* switch */
|
|
|
|
return F_NO_ERROR;
|
|
}
|
|
} /* _f_prepareformat */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_postformat
|
|
*
|
|
* erase fats, erase root directory, reset variables after formatting
|
|
*
|
|
* INPUTS
|
|
* phy - media physical descriptor
|
|
* fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA
|
|
*
|
|
* RETURNS
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
static unsigned char _f_postformat ( F_PHY * phy, unsigned char fattype )
|
|
{
|
|
unsigned long a;
|
|
unsigned char ret;
|
|
|
|
_f_buildsectors( phy ); /*get positions*/
|
|
if ( gl_volume.mediatype != fattype )
|
|
{
|
|
return F_ERR_MEDIATOOSMALL;
|
|
}
|
|
|
|
gl_volume.fatsector = (unsigned long)( -1 );
|
|
|
|
{
|
|
unsigned char * ptr = (unsigned char *)gl_sector;
|
|
unsigned char j = 2;
|
|
unsigned long i;
|
|
|
|
psp_memset( ptr, 0, F_SECTOR_SIZE );
|
|
|
|
switch ( gl_volume.mediatype )
|
|
{
|
|
case F_FAT16_MEDIA:
|
|
j = 3;
|
|
break;
|
|
|
|
case F_FAT32_MEDIA:
|
|
j = 11;
|
|
break;
|
|
}
|
|
|
|
*ptr = gl_volume.bootrecord.media_descriptor;
|
|
psp_memset( ptr + 1, 0xff, j );
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
*( ptr + 8 ) = (unsigned char)( F_CLUSTER_LAST & 0xff );
|
|
}
|
|
|
|
(void)_f_writeglsector( gl_volume.firstfat.sector );
|
|
(void)_f_writeglsector( gl_volume.firstfat.sector + gl_volume.firstfat.num );
|
|
psp_memset( ptr, 0, ( j + 1 ) );
|
|
|
|
for ( i = 1 ; i < gl_volume.firstfat.num ; i++ )
|
|
{
|
|
(void)_f_writeglsector( gl_volume.firstfat.sector + i );
|
|
(void)_f_writeglsector( gl_volume.firstfat.sector + i + gl_volume.firstfat.num );
|
|
}
|
|
}
|
|
|
|
for ( a = 0 ; a < gl_volume.root.num ; a++ ) /*reset root direntries*/
|
|
{
|
|
ret = _f_writeglsector( gl_volume.root.sector + a );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return _f_writebootrecord( phy );
|
|
} /* _f_postformat */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_hardformat
|
|
*
|
|
* Making a complete format on media, independently from master boot record,
|
|
* according to media physical
|
|
*
|
|
* INPUTS
|
|
* fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA
|
|
*
|
|
* RETURNS
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_hardformat ( unsigned char fattype )
|
|
{
|
|
unsigned char ret;
|
|
int mdrv_ret;
|
|
F_PHY phy;
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret && ( ret != F_ERR_NOTFORMATTED ) )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_volume.state = F_STATE_NEEDMOUNT;
|
|
|
|
psp_memset( &phy, 0, sizeof( F_PHY ) );
|
|
|
|
mdrv_ret = mdrv->getphy( mdrv, &phy );
|
|
if ( mdrv_ret )
|
|
{
|
|
return F_ERR_ONDRIVE;
|
|
}
|
|
|
|
ret = _f_prepareformat( &phy, fattype ); /*no partition*/
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
return _f_postformat( &phy, fattype );
|
|
} /* fn_hardformat */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_readbootrecord
|
|
*
|
|
* read boot record from a volume, it detects if there is MBR on the media
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
static unsigned char _f_readbootrecord ( void )
|
|
{
|
|
unsigned char ret;
|
|
unsigned char * ptr = (unsigned char *)gl_sector;
|
|
unsigned long maxcluster, _n;
|
|
unsigned long first_sector = 0;
|
|
|
|
gl_volume.mediatype = F_UNKNOWN_MEDIA;
|
|
|
|
|
|
ret = _f_readglsector( 0 );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
|
|
if ( ( ptr[0x1fe] != 0x55 ) || ( ptr[0x1ff] != 0xaa ) )
|
|
{
|
|
return F_ERR_NOTFORMATTED; /*??*/
|
|
}
|
|
|
|
if ( ( ptr[0] != 0xeb ) && ( ptr[0] != 0xe9 ) )
|
|
{
|
|
first_sector = _f_getlong( &ptr[0x08 + 0x1be] ); /*start sector for 1st partioon*/
|
|
|
|
ret = _f_readglsector( first_sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( ( ptr[0x1fe] != 0x55 ) || ( ptr[0x1ff] != 0xaa ) )
|
|
{
|
|
return F_ERR_NOTFORMATTED; /*??*/
|
|
}
|
|
|
|
if ( ( ptr[0] != 0xeb ) && ( ptr[0] != 0xe9 ) )
|
|
{
|
|
return F_ERR_NOTFORMATTED; /*??*/
|
|
}
|
|
}
|
|
|
|
ptr += 11;
|
|
if ( _f_getword( ptr ) != F_SECTOR_SIZE )
|
|
{
|
|
return F_ERR_NOTSUPPSECTORSIZE;
|
|
}
|
|
|
|
ptr += 2;
|
|
gl_volume.bootrecord.sector_per_cluster = *ptr++;
|
|
gl_volume.firstfat.sector = _f_getword( ptr );
|
|
ptr += 2;
|
|
gl_volume.bootrecord.number_of_FATs = *ptr++;
|
|
gl_volume.root.num = _f_getword( ptr );
|
|
ptr += 2;
|
|
gl_volume.root.num *= sizeof( F_DIRENTRY );
|
|
gl_volume.root.num /= F_SECTOR_SIZE;
|
|
maxcluster = _f_getword( ptr );
|
|
ptr += 2;
|
|
gl_volume.bootrecord.media_descriptor = *ptr++;
|
|
gl_volume.firstfat.num = _f_getword( ptr );
|
|
ptr += 6;
|
|
_n = _f_getlong( ptr );
|
|
ptr += 4;
|
|
if ( _n < first_sector )
|
|
{
|
|
_n = first_sector;
|
|
}
|
|
|
|
gl_volume.firstfat.sector += _n;
|
|
if ( !maxcluster )
|
|
{
|
|
maxcluster = _f_getlong( ptr );
|
|
}
|
|
|
|
ptr += 4;
|
|
|
|
|
|
if ( gl_volume.firstfat.num )
|
|
{
|
|
gl_volume.root.sector = gl_volume.firstfat.sector + ( gl_volume.firstfat.num * gl_volume.bootrecord.number_of_FATs );
|
|
gl_volume._tdata.sector = gl_volume.root.sector + gl_volume.root.num;
|
|
gl_volume._tdata.num = 0;
|
|
ptr += 3;
|
|
}
|
|
else
|
|
{
|
|
gl_volume.firstfat.num = _f_getlong( ptr );
|
|
ptr += 8;
|
|
gl_volume._tdata.sector = gl_volume.firstfat.sector;
|
|
gl_volume._tdata.sector += gl_volume.firstfat.num * gl_volume.bootrecord.number_of_FATs;
|
|
gl_volume._tdata.num = 0;
|
|
gl_volume.bootrecord.rootcluster = _f_getlong( ptr );
|
|
ptr += 23;
|
|
gl_volume.root.num = gl_volume.bootrecord.sector_per_cluster;
|
|
gl_volume.root.sector = ( ( gl_volume.bootrecord.rootcluster - 2 ) * gl_volume.root.num ) + gl_volume._tdata.sector;
|
|
}
|
|
|
|
gl_volume.bootrecord.serial_number = _f_getlong( ptr );
|
|
|
|
maxcluster -= gl_volume._tdata.sector;
|
|
maxcluster += _n;
|
|
gl_volume.maxcluster = maxcluster / gl_volume.bootrecord.sector_per_cluster;
|
|
|
|
if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xfff ) )
|
|
{
|
|
gl_volume.mediatype = F_FAT12_MEDIA;
|
|
}
|
|
else if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xffff ) )
|
|
{
|
|
gl_volume.mediatype = F_FAT16_MEDIA;
|
|
}
|
|
else
|
|
{
|
|
gl_volume.mediatype = F_FAT32_MEDIA;
|
|
}
|
|
|
|
if ( gl_volume.bootrecord.media_descriptor != 0xf8 ) /*fixdrive*/
|
|
{
|
|
if ( gl_volume.bootrecord.media_descriptor != 0xf0 ) /*removable*/
|
|
{
|
|
return F_ERR_NOTFORMATTED; /*??*/
|
|
}
|
|
}
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_readbootrecord */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_getvolume
|
|
*
|
|
* getting back a volume info structure of a given drive, it try to mounts
|
|
* drive if it was not mounted before
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_getvolume ( void )
|
|
{
|
|
switch ( gl_volume.state )
|
|
{
|
|
case F_STATE_NONE:
|
|
return F_ERR_ONDRIVE;
|
|
|
|
case F_STATE_WORKING:
|
|
|
|
if ( !_f_checkstatus() )
|
|
{
|
|
return F_NO_ERROR;
|
|
}
|
|
|
|
/* here we don't stop case flow, */
|
|
/* because we have to clean up this volume! */
|
|
|
|
case F_STATE_NEEDMOUNT:
|
|
{
|
|
gl_file.modified = 0;
|
|
gl_volume.modified = 0;
|
|
gl_volume.lastalloccluster = 0;
|
|
gl_volume.actsector = (unsigned long)( -1 );
|
|
gl_volume.fatsector = (unsigned long)( -1 );
|
|
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
|
|
gl_volume.cwd[0] = 0; /*reset cwd*/
|
|
gl_volume.mediatype = F_UNKNOWN_MEDIA;
|
|
|
|
if ( mdrv->getstatus != NULL )
|
|
{
|
|
if ( mdrv->getstatus( mdrv ) & F_ST_MISSING )
|
|
{
|
|
gl_volume.state = F_STATE_NEEDMOUNT; /*card missing*/
|
|
return F_ERR_CARDREMOVED;
|
|
}
|
|
}
|
|
|
|
if ( !_f_readbootrecord() )
|
|
{
|
|
gl_volume.state = F_STATE_WORKING;
|
|
return F_NO_ERROR;
|
|
}
|
|
|
|
gl_volume.mediatype = F_UNKNOWN_MEDIA;
|
|
return F_ERR_NOTFORMATTED;
|
|
}
|
|
} /* switch */
|
|
|
|
return F_ERR_ONDRIVE;
|
|
} /* _f_getvolume */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_getfreespace
|
|
*
|
|
* get total/free/used/bad diskspace
|
|
*
|
|
* INPUTS
|
|
* pspace - pointer where to store the information
|
|
*
|
|
* RETURNS
|
|
* error code
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_getfreespace ( F_SPACE * pspace )
|
|
{
|
|
unsigned char ret;
|
|
unsigned long a;
|
|
unsigned long clustersize;
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
psp_memset( pspace, 0, sizeof( F_SPACE ) );
|
|
pspace->total = gl_volume.maxcluster;
|
|
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
for ( a = 2 ; a < gl_volume.maxcluster + 2 ; a++ )
|
|
{
|
|
unsigned long value;
|
|
|
|
ret = _f_getclustervalue( a, &value );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( !value )
|
|
{
|
|
++( pspace->free );
|
|
}
|
|
else if ( value == F_CLUSTER_BAD )
|
|
{
|
|
++( pspace->bad );
|
|
}
|
|
else
|
|
{
|
|
++( pspace->used );
|
|
}
|
|
}
|
|
|
|
clustersize = (unsigned long)( gl_volume.bootrecord.sector_per_cluster * F_SECTOR_SIZE );
|
|
for ( a = 0 ; ( clustersize & 1 ) == 0 ; a++ )
|
|
{
|
|
clustersize >>= 1;
|
|
}
|
|
|
|
pspace->total_high = ( pspace->total ) >> ( 32 - a );
|
|
pspace->total <<= a;
|
|
pspace->free_high = ( pspace->free ) >> ( 32 - a );
|
|
pspace->free <<= a;
|
|
pspace->used_high = ( pspace->used ) >> ( 32 - a );
|
|
pspace->used <<= a;
|
|
pspace->bad_high = ( pspace->bad ) >> ( 32 - a );
|
|
pspace->bad <<= a;
|
|
|
|
return F_NO_ERROR;
|
|
} /* fn_getfreespace */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_getserial
|
|
*
|
|
* get serial number
|
|
*
|
|
* INPUTS
|
|
* serial - pointer where to store the serial number
|
|
*
|
|
* RETURNS
|
|
* error code
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_getserial ( unsigned long * serial )
|
|
{
|
|
unsigned char ret;
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
*serial = gl_volume.bootrecord.serial_number;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** fs_init
|
|
**
|
|
** Initialize STHIN file system
|
|
**
|
|
** RETURN: F_NO_ERROR on success, other if error.
|
|
*/
|
|
unsigned char fs_init ( void )
|
|
{
|
|
unsigned char rc = F_NO_ERROR;
|
|
|
|
#if RTOS_SUPPORT
|
|
rc = fsr_init();
|
|
if ( rc )
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
#endif
|
|
return rc;
|
|
} /* fs_init */
|
|
|
|
|
|
/*
|
|
** fs_delete
|
|
**
|
|
** Delete STHIN file system
|
|
**
|
|
** RETURN: F_NO_ERROR on success, other if error.
|
|
*/
|
|
unsigned char fs_delete ( void )
|
|
{
|
|
unsigned char rc = F_NO_ERROR;
|
|
|
|
#if RTOS_SUPPORT
|
|
rc = fsr_delete();
|
|
if ( rc )
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
#endif
|
|
return rc;
|
|
} /* fs_delete */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_initvolume
|
|
*
|
|
* initiate a volume, this function has to be called 1st to set physical
|
|
* driver function to a given volume
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_initvolume ( F_DRIVERINIT initfunc )
|
|
{
|
|
#if F_FS_THREAD_AWARE == 1
|
|
{
|
|
extern xSemaphoreHandle fs_lock_semaphore;
|
|
|
|
if( fs_lock_semaphore == NULL )
|
|
{
|
|
fs_lock_semaphore = xSemaphoreCreateMutex();
|
|
if( fs_lock_semaphore == NULL )
|
|
{
|
|
return F_ERR_OS;
|
|
}
|
|
}
|
|
}
|
|
#endif /* F_FS_THREAD_AWARE */
|
|
|
|
gl_volume.state = F_STATE_NONE;
|
|
|
|
mdrv = initfunc( 0 );
|
|
if ( mdrv == NULL )
|
|
{
|
|
return F_ERR_INITFUNC;
|
|
}
|
|
|
|
gl_volume.state = F_STATE_NEEDMOUNT;
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
f_filechangedevent = 0;
|
|
#endif
|
|
|
|
return _f_getvolume();
|
|
} /* fn_initvolume */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_delvolume
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_delvolume ( void )
|
|
{
|
|
if ( mdrv->release )
|
|
{
|
|
(void)mdrv->release( mdrv );
|
|
}
|
|
|
|
return 0;
|
|
}
|