| /* | |
| * 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; | |
| } |