/* * FreeRTOS+FAT FS V1.0.0 (C) 2013 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 != 3 || 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; } gl_file.prevcluster = gl_file.pos.cluster; _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 */