]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT-SL/fat_sl/common/fat.c
Add FAT SL code and demo project.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-FAT-SL / fat_sl / common / fat.c
1 /*\r
2  * FreeRTOS+FAT FS V1.0.0 (C) 2013 HCC Embedded\r
3  *\r
4  * The FreeRTOS+FAT SL license terms are different to the FreeRTOS license \r
5  * terms.\r
6  * \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
11  * \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
18  * \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
25  * changed.\r
26  *\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
33  *\r
34  * http://www.FreeRTOS.org\r
35  * http://www.FreeRTOS.org/FreeRTOS-Plus\r
36  *\r
37  */\r
38 #include "../../api/fat_sl.h"\r
39 \r
40 #include "fat.h"\r
41 #include "util.h"\r
42 #include "volume.h"\r
43 #include "drv.h"\r
44 \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
48 #endif\r
49 \r
50 /****************************************************************************\r
51  *\r
52  * _f_writefatsector\r
53  *\r
54  * writing fat sector into volume, this function check if fat was modified\r
55  * and writes data\r
56  *\r
57  * RETURNS\r
58  *\r
59  * error code or zero if successful\r
60  *\r
61  ***************************************************************************/\r
62 unsigned char _f_writefatsector ( void )\r
63 {\r
64   unsigned char  a;\r
65 \r
66   if ( gl_volume.modified )\r
67   {\r
68     unsigned long  fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;\r
69 \r
70     if ( gl_volume.fatsector >= gl_volume.firstfat.num )\r
71     {\r
72       return F_ERR_INVALIDSECTOR;\r
73     }\r
74 \r
75     for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )\r
76     {\r
77       unsigned char  ret;\r
78       ret = _f_writeglsector( fatsector );\r
79       if ( ret )\r
80       {\r
81         return ret;\r
82       }\r
83 \r
84       fatsector += gl_volume.firstfat.num;\r
85     }\r
86 \r
87     gl_volume.modified = 0;\r
88   }\r
89 \r
90   return F_NO_ERROR;\r
91 } /* _f_writefatsector */\r
92 \r
93 \r
94 \r
95 /****************************************************************************\r
96  *\r
97  * _f_getfatsector\r
98  *\r
99  * read a fat sector from media\r
100  *\r
101  * INPUTS\r
102  *\r
103  * sector - which fat sector is needed, this sector number is zero based\r
104  *\r
105  * RETURNS\r
106  *\r
107  * error code or zero if successful\r
108  *\r
109  ***************************************************************************/\r
110 unsigned char _f_getfatsector ( unsigned long sector )\r
111 {\r
112   unsigned char  a;\r
113 \r
114   if ( gl_volume.fatsector != sector )\r
115   {\r
116     unsigned long  fatsector;\r
117 \r
118     gl_volume.fatsector = sector;\r
119 \r
120     if ( gl_volume.fatsector >= gl_volume.firstfat.num )\r
121     {\r
122       return F_ERR_INVALIDSECTOR;\r
123     }\r
124 \r
125     fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;\r
126 \r
127     for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )\r
128     {\r
129       if ( !_f_readglsector( fatsector ) )\r
130       {\r
131         return F_NO_ERROR;\r
132       }\r
133 \r
134       fatsector += gl_volume.firstfat.num;\r
135     }\r
136 \r
137     return F_ERR_READ;\r
138   }\r
139 \r
140   return F_NO_ERROR;\r
141 } /* _f_getfatsector */\r
142 \r
143 \r
144 \r
145 /****************************************************************************\r
146  *\r
147  * _f_setclustervalue\r
148  *\r
149  * set a cluster value in the FAT\r
150  *\r
151  * INPUTS\r
152  *\r
153  * cluster - which cluster's value need to be modified\r
154  * data - new value of the cluster\r
155  *\r
156  * RETURNS\r
157  *\r
158  * error code or zero if successful\r
159  *\r
160  ***************************************************************************/\r
161 unsigned char _f_setclustervalue ( unsigned long cluster, unsigned long _tdata )\r
162 {\r
163   unsigned char  ret;\r
164 \r
165   switch ( gl_volume.mediatype )\r
166   {\r
167     case F_FAT16_MEDIA:\r
168     {\r
169       unsigned long   sector = cluster;\r
170       unsigned short  s_data = (unsigned short)( _tdata & 0xffff ); /*keep 16 bit only*/\r
171 \r
172       sector /= ( F_SECTOR_SIZE / 2 );\r
173       cluster -= sector * ( F_SECTOR_SIZE / 2 );\r
174 \r
175       ret = _f_getfatsector( sector );\r
176       if ( ret )\r
177       {\r
178         return ret;\r
179       }\r
180 \r
181       if ( _f_getword( &gl_sector[cluster << 1] ) != s_data )\r
182       {\r
183         _f_setword( &gl_sector[cluster << 1], s_data );\r
184         gl_volume.modified = 1;\r
185       }\r
186     }\r
187     break;\r
188 \r
189     case F_FAT12_MEDIA:\r
190     {\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
195 \r
196       if ( cluster & 1 )\r
197       {\r
198         s_data <<= 4;\r
199       }\r
200 \r
201       _f_setword( f12new, s_data ); /*create new data*/\r
202 \r
203       sector += sector / 2;       /*1.5 bytes*/\r
204       pos = (unsigned short)( sector % F_SECTOR_SIZE );\r
205       sector /= F_SECTOR_SIZE;\r
206 \r
207       ret = _f_getfatsector( sector );\r
208       if ( ret )\r
209       {\r
210         return ret;\r
211       }\r
212 \r
213       if ( cluster & 1 )\r
214       {\r
215         f12new[0] |= gl_sector[pos] & 0x0f;\r
216       }\r
217 \r
218       if ( gl_sector[pos] != f12new[0] )\r
219       {\r
220         gl_sector[pos] = f12new[0];\r
221         gl_volume.modified = 1;\r
222       }\r
223 \r
224       pos++;\r
225       if ( pos >= 512 )\r
226       {\r
227         ret = _f_getfatsector( sector + 1 );\r
228         if ( ret )\r
229         {\r
230           return ret;\r
231         }\r
232 \r
233         pos = 0;\r
234       }\r
235 \r
236       if ( !( cluster & 1 ) )\r
237       {\r
238         f12new[1] |= gl_sector[pos] & 0xf0;\r
239       }\r
240 \r
241       if ( gl_sector[pos] != f12new[1] )\r
242       {\r
243         gl_sector[pos] = f12new[1];\r
244         gl_volume.modified = 1;\r
245       }\r
246     }\r
247     break;\r
248 \r
249     case F_FAT32_MEDIA:\r
250     {\r
251       unsigned long  sector = cluster;\r
252       unsigned long  oldv;\r
253 \r
254       sector /= ( F_SECTOR_SIZE / 4 );\r
255       cluster -= sector * ( F_SECTOR_SIZE / 4 );\r
256 \r
257       ret = _f_getfatsector( sector );\r
258       if ( ret )\r
259       {\r
260         return ret;\r
261       }\r
262 \r
263       oldv = _f_getlong( &gl_sector[cluster << 2] );\r
264 \r
265       _tdata &= 0x0fffffff;\r
266       _tdata |= oldv & 0xf0000000; /*keep 4 top bits*/\r
267 \r
268       if ( _tdata != oldv )\r
269       {\r
270         _f_setlong( &gl_sector[cluster << 2], _tdata );\r
271         gl_volume.modified = 1;\r
272       }\r
273     }\r
274     break;\r
275 \r
276     default:\r
277       return F_ERR_INVALIDMEDIA;\r
278   } /* switch */\r
279 \r
280   return F_NO_ERROR;\r
281 } /* _f_setclustervalue */\r
282 \r
283 \r
284 /****************************************************************************\r
285  *\r
286  * _f_getclustervalue\r
287  *\r
288  * get a cluster value from FAT\r
289  *\r
290  * INPUTS\r
291  *\r
292  * cluster - which cluster value is requested\r
293  * pvalue - where to store data\r
294  *\r
295  * RETURNS\r
296  *\r
297  * error code or zero if successful\r
298  *\r
299  ***************************************************************************/\r
300 unsigned char _f_getclustervalue ( unsigned long cluster, unsigned long * pvalue )\r
301 {\r
302   unsigned long  val;\r
303   unsigned char  ret;\r
304 \r
305   switch ( gl_volume.mediatype )\r
306   {\r
307     case F_FAT16_MEDIA:\r
308     {\r
309       unsigned long  sector = cluster;\r
310       sector /= ( F_SECTOR_SIZE / 2 );\r
311       cluster -= sector * ( F_SECTOR_SIZE / 2 );\r
312 \r
313       ret = _f_getfatsector( sector );\r
314       if ( ret )\r
315       {\r
316         return ret;\r
317       }\r
318 \r
319       val = _f_getword( &gl_sector[cluster << 1] );\r
320       if ( val >= ( F_CLUSTER_RESERVED & 0xffff ) )\r
321       {\r
322         val |= 0x0ffff000;                                       /*extends it*/\r
323       }\r
324 \r
325       if ( pvalue )\r
326       {\r
327         *pvalue = val;\r
328       }\r
329     }\r
330     break;\r
331 \r
332     case F_FAT12_MEDIA:\r
333     {\r
334       unsigned char   dataf12[2];\r
335       unsigned long   sector = cluster;\r
336       unsigned short  pos;\r
337 \r
338       sector += sector / 2;       /*1.5 bytes*/\r
339       pos = (unsigned short)( sector % F_SECTOR_SIZE );\r
340       sector /= F_SECTOR_SIZE;\r
341 \r
342       ret = _f_getfatsector( sector );\r
343       if ( ret )\r
344       {\r
345         return ret;\r
346       }\r
347 \r
348       dataf12[0] = gl_sector[pos++];\r
349 \r
350       if ( pos >= 512 )\r
351       {\r
352         ret = _f_getfatsector( sector + 1 );\r
353         if ( ret )\r
354         {\r
355           return ret;\r
356         }\r
357 \r
358         pos = 0;\r
359       }\r
360 \r
361       dataf12[1] = gl_sector[pos];\r
362 \r
363       val = _f_getword( dataf12 );\r
364 \r
365       if ( cluster & 1 )\r
366       {\r
367         val = val >> 4;\r
368       }\r
369       else\r
370       {\r
371         val = val & 0xfff;\r
372       }\r
373 \r
374       if ( val >= ( F_CLUSTER_RESERVED & 0xfff ) )\r
375       {\r
376         val |= 0x0ffff000;                                      /*extends it*/\r
377       }\r
378 \r
379       if ( pvalue )\r
380       {\r
381         *pvalue = val;\r
382       }\r
383     }\r
384     break;\r
385 \r
386     case F_FAT32_MEDIA:\r
387     {\r
388       unsigned long  sector = cluster;\r
389       sector /= ( F_SECTOR_SIZE / 4 );\r
390       cluster -= sector * ( F_SECTOR_SIZE / 4 );\r
391 \r
392       ret = _f_getfatsector( sector );\r
393       if ( ret )\r
394       {\r
395         return ret;\r
396       }\r
397 \r
398       if ( pvalue )\r
399       {\r
400         *pvalue = _f_getlong( &gl_sector[cluster << 2] ) & 0x0fffffff;       /*28bit*/\r
401       }\r
402     }\r
403     break;\r
404 \r
405     default:\r
406       return F_ERR_INVALIDMEDIA;\r
407   } /* switch */\r
408 \r
409   return F_NO_ERROR;\r
410 } /* _f_getclustervalue */\r
411 \r
412 \r
413 \r
414 \r
415 \r
416 \r
417 /****************************************************************************\r
418  *\r
419  * _f_clustertopos\r
420  *\r
421  * convert a cluster position into physical sector position\r
422  *\r
423  * INPUTS\r
424  *\r
425  * cluster - original cluster position\r
426  * pos - position structure to fills the position\r
427  *\r
428  ***************************************************************************/\r
429 void _f_clustertopos ( unsigned long cluster, F_POS * pos )\r
430 {\r
431   pos->cluster = cluster;\r
432 \r
433   if ( !cluster )\r
434   {\r
435     pos->sector = gl_volume.root.sector;\r
436     pos->sectorend = pos->sector + gl_volume.root.num;\r
437   }\r
438   else\r
439   {\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
443   }\r
444 \r
445   if ( cluster >= F_CLUSTER_RESERVED )\r
446   {\r
447     pos->sectorend = 0;\r
448   }\r
449 \r
450   pos->pos = 0;\r
451 } /* _f_clustertopos */\r
452 \r
453 \r
454 \r
455 \r
456 /****************************************************************************\r
457  *\r
458  * _f_getcurrsector\r
459  *\r
460  * read current sector according in file structure\r
461  *\r
462  * INPUTS\r
463  * f - internal file pointer\r
464  *\r
465  * RETURNS\r
466  * error code or zero if successful\r
467  *\r
468  ***************************************************************************/\r
469 unsigned char _f_getcurrsector ( void )\r
470 {\r
471   unsigned char  ret;\r
472   unsigned long  cluster;\r
473 \r
474   if ( gl_file.pos.sector == gl_file.pos.sectorend )\r
475   {\r
476     gl_volume.fatsector = (unsigned long)-1;\r
477     ret = _f_getclustervalue( gl_file.pos.cluster, &cluster );\r
478     if ( ret )\r
479     {\r
480       return ret;\r
481     }\r
482 \r
483     if ( cluster >= F_CLUSTER_RESERVED )\r
484     {\r
485       return F_ERR_EOF;\r
486     }\r
487 \r
488     gl_file.prevcluster = gl_file.pos.cluster;\r
489     _f_clustertopos( cluster, &gl_file.pos );\r
490   }\r
491 \r
492   return _f_readglsector( gl_file.pos.sector );\r
493 } /* _f_getcurrsector */\r
494 \r
495 \r
496 \r
497 /****************************************************************************\r
498  *\r
499  * _f_alloccluster\r
500  *\r
501  * allocate cluster from FAT\r
502  *\r
503  * INPUTS\r
504  * pcluster - where to store the allocated cluster number\r
505  *\r
506  * RETURNS\r
507  *\r
508  * error code or zero if successful\r
509  *\r
510  ***************************************************************************/\r
511 \r
512 unsigned char _f_alloccluster ( unsigned long * pcluster )\r
513 {\r
514   unsigned long  maxcluster = gl_volume.maxcluster;\r
515   unsigned long  cou;\r
516   unsigned long  cluster = gl_volume.lastalloccluster;\r
517   unsigned long  value;\r
518   unsigned char  ret;\r
519 \r
520   for ( cou = 0 ; cou < maxcluster ; cou++ )\r
521   {\r
522     if ( cluster >= maxcluster )\r
523     {\r
524       cluster = 0;\r
525     }\r
526 \r
527     ret = _f_getclustervalue( cluster, &value );\r
528     if ( ret )\r
529     {\r
530       return ret;\r
531     }\r
532 \r
533     if ( !value )\r
534     {\r
535       gl_volume.lastalloccluster = cluster + 1;   /*set next one*/\r
536       *pcluster = cluster;\r
537 \r
538       return F_NO_ERROR;\r
539     }\r
540 \r
541     cluster++;\r
542   }\r
543 \r
544   return F_ERR_NOMOREENTRY;\r
545 } /* _f_alloccluster */\r
546 \r
547 \r
548 \r
549 \r
550 /****************************************************************************\r
551  *\r
552  * _f_removechain\r
553  *\r
554  * remove cluster chain from fat\r
555  *\r
556  * INPUTS\r
557  * cluster - first cluster in the cluster chain\r
558  *\r
559  * RETURNS\r
560  *\r
561  * error code or zero if successful\r
562  *\r
563  ***************************************************************************/\r
564 \r
565 unsigned char _f_removechain ( unsigned long cluster )\r
566 {\r
567   gl_volume.fatsector = (unsigned long)-1;\r
568 \r
569   if ( cluster < gl_volume.lastalloccluster ) /*this could be the begining of alloc*/\r
570   {\r
571     gl_volume.lastalloccluster = cluster;\r
572   }\r
573 \r
574   while ( cluster < F_CLUSTER_RESERVED && cluster >= 2 )\r
575   {\r
576     unsigned long  nextcluster;\r
577 \r
578     unsigned char  ret = _f_getclustervalue( cluster, &nextcluster );\r
579     if ( ret )\r
580     {\r
581       return ret;\r
582     }\r
583 \r
584     ret = _f_setclustervalue( cluster, F_CLUSTER_FREE );\r
585     if ( ret )\r
586     {\r
587       return ret;\r
588     }\r
589 \r
590     cluster = nextcluster;\r
591   }\r
592 \r
593   return _f_writefatsector();\r
594 } /* _f_removechain */\r
595 \r
596 \r
597 \r
598 \r