2 * FreeRTOS+FAT FS V1.0.0 (C) 2013 HCC Embedded
\r
4 * The FreeRTOS+FAT SL license terms are different to the FreeRTOS license
\r
7 * FreeRTOS+FAT SL uses a dual license model that allows the software to be used
\r
8 * under a pure GPL open source license (as opposed to the modified GPL licence
\r
9 * under which FreeRTOS is distributed) or a commercial license. Details of
\r
10 * both license options follow:
\r
12 * - Open source licensing -
\r
13 * FreeRTOS+FAT SL is a free download and may be used, modified, evaluated and
\r
14 * distributed without charge provided the user adheres to version two of the
\r
15 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
16 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
17 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
19 * - Commercial licensing -
\r
20 * Businesses and individuals who for commercial or other reasons cannot comply
\r
21 * with the terms of the GPL V2 license must obtain a commercial license before
\r
22 * incorporating FreeRTOS+FAT SL into proprietary software for distribution in
\r
23 * any form. Commercial licenses can be purchased from
\r
24 * http://shop.freertos.org/fat_sl and do not require any source files to be
\r
27 * FreeRTOS+FAT SL is distributed in the hope that it will be useful. You
\r
28 * cannot use FreeRTOS+FAT SL unless you agree that you use the software 'as
\r
29 * is'. FreeRTOS+FAT SL is provided WITHOUT ANY WARRANTY; without even the
\r
30 * implied warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A
\r
31 * PARTICULAR PURPOSE. Real Time Engineers Ltd. and HCC Embedded disclaims all
\r
32 * conditions and terms, be they implied, expressed, or statutory.
\r
34 * http://www.FreeRTOS.org
\r
35 * http://www.FreeRTOS.org/FreeRTOS-Plus
\r
38 #include "../../api/fat_sl.h"
\r
45 #include "../../version/ver_fat_sl.h"
\r
46 #if VER_FAT_SL_MAJOR != 3 || VER_FAT_SL_MINOR != 2
\r
47 #error Incompatible FAT_SL version number!
\r
50 /****************************************************************************
\r
54 * writing fat sector into volume, this function check if fat was modified
\r
59 * error code or zero if successful
\r
61 ***************************************************************************/
\r
62 unsigned char _f_writefatsector ( void )
\r
66 if ( gl_volume.modified )
\r
68 unsigned long fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;
\r
70 if ( gl_volume.fatsector >= gl_volume.firstfat.num )
\r
72 return F_ERR_INVALIDSECTOR;
\r
75 for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )
\r
78 ret = _f_writeglsector( fatsector );
\r
84 fatsector += gl_volume.firstfat.num;
\r
87 gl_volume.modified = 0;
\r
91 } /* _f_writefatsector */
\r
95 /****************************************************************************
\r
99 * read a fat sector from media
\r
103 * sector - which fat sector is needed, this sector number is zero based
\r
107 * error code or zero if successful
\r
109 ***************************************************************************/
\r
110 unsigned char _f_getfatsector ( unsigned long sector )
\r
114 if ( gl_volume.fatsector != sector )
\r
116 unsigned long fatsector;
\r
118 gl_volume.fatsector = sector;
\r
120 if ( gl_volume.fatsector >= gl_volume.firstfat.num )
\r
122 return F_ERR_INVALIDSECTOR;
\r
125 fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;
\r
127 for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )
\r
129 if ( !_f_readglsector( fatsector ) )
\r
134 fatsector += gl_volume.firstfat.num;
\r
141 } /* _f_getfatsector */
\r
145 /****************************************************************************
\r
147 * _f_setclustervalue
\r
149 * set a cluster value in the FAT
\r
153 * cluster - which cluster's value need to be modified
\r
154 * data - new value of the cluster
\r
158 * error code or zero if successful
\r
160 ***************************************************************************/
\r
161 unsigned char _f_setclustervalue ( unsigned long cluster, unsigned long _tdata )
\r
165 switch ( gl_volume.mediatype )
\r
167 case F_FAT16_MEDIA:
\r
169 unsigned long sector = cluster;
\r
170 unsigned short s_data = (unsigned short)( _tdata & 0xffff ); /*keep 16 bit only*/
\r
172 sector /= ( F_SECTOR_SIZE / 2 );
\r
173 cluster -= sector * ( F_SECTOR_SIZE / 2 );
\r
175 ret = _f_getfatsector( sector );
\r
181 if ( _f_getword( &gl_sector[cluster << 1] ) != s_data )
\r
183 _f_setword( &gl_sector[cluster << 1], s_data );
\r
184 gl_volume.modified = 1;
\r
189 case F_FAT12_MEDIA:
\r
191 unsigned char f12new[2];
\r
192 unsigned long sector = cluster;
\r
193 unsigned short pos;
\r
194 unsigned short s_data = (unsigned short)( _tdata & 0x0fff ); /*keep 12 bit only*/
\r
201 _f_setword( f12new, s_data ); /*create new data*/
\r
203 sector += sector / 2; /*1.5 bytes*/
\r
204 pos = (unsigned short)( sector % F_SECTOR_SIZE );
\r
205 sector /= F_SECTOR_SIZE;
\r
207 ret = _f_getfatsector( sector );
\r
215 f12new[0] |= gl_sector[pos] & 0x0f;
\r
218 if ( gl_sector[pos] != f12new[0] )
\r
220 gl_sector[pos] = f12new[0];
\r
221 gl_volume.modified = 1;
\r
227 ret = _f_getfatsector( sector + 1 );
\r
236 if ( !( cluster & 1 ) )
\r
238 f12new[1] |= gl_sector[pos] & 0xf0;
\r
241 if ( gl_sector[pos] != f12new[1] )
\r
243 gl_sector[pos] = f12new[1];
\r
244 gl_volume.modified = 1;
\r
249 case F_FAT32_MEDIA:
\r
251 unsigned long sector = cluster;
\r
252 unsigned long oldv;
\r
254 sector /= ( F_SECTOR_SIZE / 4 );
\r
255 cluster -= sector * ( F_SECTOR_SIZE / 4 );
\r
257 ret = _f_getfatsector( sector );
\r
263 oldv = _f_getlong( &gl_sector[cluster << 2] );
\r
265 _tdata &= 0x0fffffff;
\r
266 _tdata |= oldv & 0xf0000000; /*keep 4 top bits*/
\r
268 if ( _tdata != oldv )
\r
270 _f_setlong( &gl_sector[cluster << 2], _tdata );
\r
271 gl_volume.modified = 1;
\r
277 return F_ERR_INVALIDMEDIA;
\r
281 } /* _f_setclustervalue */
\r
284 /****************************************************************************
\r
286 * _f_getclustervalue
\r
288 * get a cluster value from FAT
\r
292 * cluster - which cluster value is requested
\r
293 * pvalue - where to store data
\r
297 * error code or zero if successful
\r
299 ***************************************************************************/
\r
300 unsigned char _f_getclustervalue ( unsigned long cluster, unsigned long * pvalue )
\r
305 switch ( gl_volume.mediatype )
\r
307 case F_FAT16_MEDIA:
\r
309 unsigned long sector = cluster;
\r
310 sector /= ( F_SECTOR_SIZE / 2 );
\r
311 cluster -= sector * ( F_SECTOR_SIZE / 2 );
\r
313 ret = _f_getfatsector( sector );
\r
319 val = _f_getword( &gl_sector[cluster << 1] );
\r
320 if ( val >= ( F_CLUSTER_RESERVED & 0xffff ) )
\r
322 val |= 0x0ffff000; /*extends it*/
\r
332 case F_FAT12_MEDIA:
\r
334 unsigned char dataf12[2];
\r
335 unsigned long sector = cluster;
\r
336 unsigned short pos;
\r
338 sector += sector / 2; /*1.5 bytes*/
\r
339 pos = (unsigned short)( sector % F_SECTOR_SIZE );
\r
340 sector /= F_SECTOR_SIZE;
\r
342 ret = _f_getfatsector( sector );
\r
348 dataf12[0] = gl_sector[pos++];
\r
352 ret = _f_getfatsector( sector + 1 );
\r
361 dataf12[1] = gl_sector[pos];
\r
363 val = _f_getword( dataf12 );
\r
374 if ( val >= ( F_CLUSTER_RESERVED & 0xfff ) )
\r
376 val |= 0x0ffff000; /*extends it*/
\r
386 case F_FAT32_MEDIA:
\r
388 unsigned long sector = cluster;
\r
389 sector /= ( F_SECTOR_SIZE / 4 );
\r
390 cluster -= sector * ( F_SECTOR_SIZE / 4 );
\r
392 ret = _f_getfatsector( sector );
\r
400 *pvalue = _f_getlong( &gl_sector[cluster << 2] ) & 0x0fffffff; /*28bit*/
\r
406 return F_ERR_INVALIDMEDIA;
\r
410 } /* _f_getclustervalue */
\r
417 /****************************************************************************
\r
421 * convert a cluster position into physical sector position
\r
425 * cluster - original cluster position
\r
426 * pos - position structure to fills the position
\r
428 ***************************************************************************/
\r
429 void _f_clustertopos ( unsigned long cluster, F_POS * pos )
\r
431 pos->cluster = cluster;
\r
435 pos->sector = gl_volume.root.sector;
\r
436 pos->sectorend = pos->sector + gl_volume.root.num;
\r
440 unsigned long sectorcou = gl_volume.bootrecord.sector_per_cluster;
\r
441 pos->sector = ( pos->cluster - 2 ) * sectorcou + gl_volume._tdata.sector;
\r
442 pos->sectorend = pos->sector + sectorcou;
\r
445 if ( cluster >= F_CLUSTER_RESERVED )
\r
447 pos->sectorend = 0;
\r
451 } /* _f_clustertopos */
\r
456 /****************************************************************************
\r
460 * read current sector according in file structure
\r
463 * f - internal file pointer
\r
466 * error code or zero if successful
\r
468 ***************************************************************************/
\r
469 unsigned char _f_getcurrsector ( void )
\r
472 unsigned long cluster;
\r
474 if ( gl_file.pos.sector == gl_file.pos.sectorend )
\r
476 gl_volume.fatsector = (unsigned long)-1;
\r
477 ret = _f_getclustervalue( gl_file.pos.cluster, &cluster );
\r
483 if ( cluster >= F_CLUSTER_RESERVED )
\r
488 gl_file.prevcluster = gl_file.pos.cluster;
\r
489 _f_clustertopos( cluster, &gl_file.pos );
\r
492 return _f_readglsector( gl_file.pos.sector );
\r
493 } /* _f_getcurrsector */
\r
497 /****************************************************************************
\r
501 * allocate cluster from FAT
\r
504 * pcluster - where to store the allocated cluster number
\r
508 * error code or zero if successful
\r
510 ***************************************************************************/
\r
512 unsigned char _f_alloccluster ( unsigned long * pcluster )
\r
514 unsigned long maxcluster = gl_volume.maxcluster;
\r
516 unsigned long cluster = gl_volume.lastalloccluster;
\r
517 unsigned long value;
\r
520 for ( cou = 0 ; cou < maxcluster ; cou++ )
\r
522 if ( cluster >= maxcluster )
\r
527 ret = _f_getclustervalue( cluster, &value );
\r
535 gl_volume.lastalloccluster = cluster + 1; /*set next one*/
\r
536 *pcluster = cluster;
\r
544 return F_ERR_NOMOREENTRY;
\r
545 } /* _f_alloccluster */
\r
550 /****************************************************************************
\r
554 * remove cluster chain from fat
\r
557 * cluster - first cluster in the cluster chain
\r
561 * error code or zero if successful
\r
563 ***************************************************************************/
\r
565 unsigned char _f_removechain ( unsigned long cluster )
\r
567 gl_volume.fatsector = (unsigned long)-1;
\r
569 if ( cluster < gl_volume.lastalloccluster ) /*this could be the begining of alloc*/
\r
571 gl_volume.lastalloccluster = cluster;
\r
574 while ( cluster < F_CLUSTER_RESERVED && cluster >= 2 )
\r
576 unsigned long nextcluster;
\r
578 unsigned char ret = _f_getclustervalue( cluster, &nextcluster );
\r
584 ret = _f_setclustervalue( cluster, F_CLUSTER_FREE );
\r
590 cluster = nextcluster;
\r
593 return _f_writefatsector();
\r
594 } /* _f_removechain */
\r