]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT-SL/fat_sl/common/volume.c
22609831da1aea75d33732eb2ebce4c19fae7554
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-FAT-SL / fat_sl / common / volume.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 \r
39 #include "../../api/fat_sl.h"\r
40 #include "../../psp/include/psp_string.h"\r
41 \r
42 #include "volume.h"\r
43 #include "util.h"\r
44 #include "drv.h"\r
45 #include "fat.h"\r
46 #include "dir.h"\r
47 #include "file.h"\r
48 \r
49 #include "../../version/ver_fat_sl.h"\r
50 #if VER_FAT_SL_MAJOR != 3 || VER_FAT_SL_MINOR != 2\r
51  #error Incompatible FAT_SL version number!\r
52 #endif\r
53 \r
54 #if F_FS_THREAD_AWARE == 1\r
55   #include "f_lock.h"\r
56 #endif\r
57 \r
58 F_VOLUME  gl_volume;                /* only one volume */\r
59 F_FILE    gl_file;                  /* file */\r
60 char      gl_sector[F_SECTOR_SIZE]; /* actual sector */\r
61 \r
62 #if F_FILE_CHANGED_EVENT\r
63 F_FILE_CHANGED_EVENTFUNC  f_filechangedevent;\r
64 #endif\r
65 \r
66 \r
67 /* Defines the number of sectors per cluster on a sector number basis */\r
68 typedef struct\r
69 {\r
70   unsigned long  max_sectors;\r
71   unsigned char  sector_per_cluster;\r
72 } t_FAT32_CS;\r
73 \r
74 static const t_FAT32_CS  FAT32_CS[] =\r
75 {\r
76   { 0x00020000, 1 }     /* ->64MB */\r
77   , { 0x00040000, 2 }   /* ->128MB */\r
78   , { 0x00080000, 4 }   /* ->256MB */\r
79   , { 0x01000000, 8 }   /* ->8GB */\r
80   , { 0x02000000, 16 }  /* ->16GB */\r
81   , { 0x0ffffff0, 32 }  /* -> ... */\r
82 };\r
83 \r
84 \r
85 /****************************************************************************\r
86  *\r
87  * _f_writebootrecord\r
88  *\r
89  * writing boot record onto a volume, it uses number of hidden sector variable\r
90  *\r
91  * INPUTS\r
92  * phy - media physical descriptor\r
93  *\r
94  * RETURNS\r
95  * error code or zero if successful\r
96  *\r
97  ***************************************************************************/\r
98 static unsigned char _f_writebootrecord ( F_PHY * phy )\r
99 {\r
100   unsigned char   jump_code[] =\r
101   {\r
102     0xeb, 0x3c, 0x90\r
103   };\r
104   unsigned char   oem_name[] = "MSDOS5.0";\r
105   unsigned char   executable_marker[] =\r
106   {\r
107     0x55, 0xaa\r
108   };\r
109   unsigned char * ptr = (unsigned char *)gl_sector;\r
110   unsigned char   rs;\r
111   unsigned short  mre;\r
112 \r
113   unsigned char  ret;\r
114   unsigned char  _n = 0;\r
115 \r
116   if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
117   {  /*write FS_INFO*/\r
118     unsigned char  a;\r
119 \r
120     rs = 32 + 4;\r
121     mre = 0;\r
122 \r
123     psp_memset( ptr, 0, F_SECTOR_SIZE );\r
124 \r
125     for ( a = 0 ; a < rs ; a++ )\r
126     {\r
127       ret = _f_writeglsector( a ); /*erase reserved area*/\r
128       if ( ret )\r
129       {\r
130         return ret;\r
131       }\r
132     }\r
133 \r
134     ptr = _setlong( 0x41615252, ptr ); /*signature*/\r
135     ptr = _setcharzero( 480, ptr );    /*reserved*/\r
136     ptr = _setlong( 0x61417272, ptr ); /*signature*/\r
137     ptr = _setlong( 0xffffffff, ptr ); /*no last*/\r
138     ptr = _setlong( 0xffffffff, ptr ); /*no hint*/\r
139     ptr = _setcharzero( 12, ptr );     /*reserved*/\r
140     ptr = _setlong( 0xaa550000, ptr ); /*trail*/\r
141 \r
142 \r
143     ret = _f_writeglsector( 1 ); /*write FSINFO*/\r
144     if ( ret )\r
145     {\r
146       return ret;\r
147     }\r
148 \r
149     ret = _f_writeglsector( 1 + 6 ); /*write FSINFO*/\r
150     if ( ret )\r
151     {\r
152       return ret;\r
153     }\r
154   }\r
155   else\r
156   {\r
157     rs = 1;\r
158     mre = 512;\r
159   }\r
160 \r
161   ptr = (unsigned char *)gl_sector;\r
162   ptr = _setchar( jump_code, sizeof( jump_code ), ptr );\r
163   ptr = _setchar( oem_name, sizeof( oem_name ) - 1, ptr );\r
164   ptr = _setword( F_SECTOR_SIZE, ptr );\r
165   *ptr++ = gl_volume.bootrecord.sector_per_cluster;\r
166   ptr = _setword( rs, ptr );  /* reserved sectors */\r
167   *ptr++ = 2;                 /* number of FATs */\r
168   ptr = _setword( mre, ptr ); /* max root entry */\r
169   if ( phy->number_of_sectors < 0x10000 )\r
170   {\r
171     ptr = _setword( (unsigned short)phy->number_of_sectors, ptr );\r
172   }\r
173   else\r
174   {\r
175     ptr = _setword( 0, ptr );\r
176   }\r
177 \r
178   *ptr++ = 0xf0;                /* media descriptor */\r
179   ptr = _setword( (unsigned short)gl_volume.bootrecord.sector_per_FAT, ptr );\r
180   ptr = _setword( phy->sector_per_track, ptr );\r
181   ptr = _setword( phy->number_of_heads, ptr );\r
182   ptr = _setlong( 0, ptr ); /* number of hidden sectors */\r
183   if ( phy->number_of_sectors >= 0x10000 )\r
184   {\r
185     ptr = _setlong( phy->number_of_sectors, ptr );\r
186   }\r
187   else\r
188   {\r
189     ptr = _setlong( 0, ptr );                                       /* number of sectors */\r
190   }\r
191 \r
192   if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
193   {\r
194     ptr = _setlong( gl_volume.bootrecord.sector_per_FAT32, ptr );\r
195     ptr = _setword( 0, ptr );\r
196     ptr = _setword( 0, ptr );\r
197     ptr = _setlong( 2, ptr );\r
198     ptr = _setword( 1, ptr );\r
199     ptr = _setword( 6, ptr );\r
200     ptr = _setchar( NULL, 12, ptr );\r
201     _n = 28;\r
202   }\r
203 \r
204 \r
205   ptr = _setword( 0, ptr ); /* logical drive num */\r
206   *ptr++ = 0x29;            /* extended signature */\r
207   ptr = _setlong( 0x11223344, ptr );\r
208   ptr = _setchar( (const unsigned char *)"NO NAME    ", 11, ptr ); /* volume name */\r
209 \r
210   switch ( gl_volume.mediatype )\r
211   {\r
212     case F_FAT12_MEDIA:\r
213       ptr = _setchar( (const unsigned char *)"FAT12   ", 8, ptr );\r
214       break;\r
215 \r
216     case F_FAT16_MEDIA:\r
217       ptr = _setchar( (const unsigned char *)"FAT16   ", 8, ptr );\r
218       break;\r
219 \r
220     case F_FAT32_MEDIA:\r
221       ptr = _setchar( (const unsigned char *)"FAT32   ", 8, ptr );\r
222       break;\r
223 \r
224     default:\r
225       return F_ERR_INVALIDMEDIA;\r
226   } /* switch */\r
227 \r
228   ptr = _setchar( 0, 448 - _n, ptr );\r
229   ptr = _setchar( executable_marker, sizeof( executable_marker ), ptr );\r
230 \r
231   if ( _n )\r
232   {\r
233     ret = _f_writeglsector( 6 );\r
234     if ( ret )\r
235     {\r
236       return ret;\r
237     }\r
238   }\r
239 \r
240 \r
241   return _f_writeglsector( 0 ); /*write bootrecord*/\r
242 } /* _f_writebootrecord */\r
243 \r
244 \r
245 /****************************************************************************\r
246  *\r
247  * _f_buildsectors\r
248  *\r
249  * INPUTS\r
250  * phy - media physical descriptor\r
251  *\r
252  * calculate relative sector position from boot record\r
253  *\r
254  ***************************************************************************/\r
255 static unsigned char _f_buildsectors ( F_PHY * phy )\r
256 {\r
257   gl_volume.mediatype = F_UNKNOWN_MEDIA;\r
258 \r
259 \r
260   if ( gl_volume.bootrecord.sector_per_FAT )\r
261   {\r
262     gl_volume.firstfat.sector = 1;\r
263     gl_volume.firstfat.num = gl_volume.bootrecord.sector_per_FAT;\r
264     gl_volume.root.sector = gl_volume.firstfat.sector + ( gl_volume.firstfat.num * (unsigned long)( gl_volume.bootrecord.number_of_FATs ) );\r
265     gl_volume.root.num = ( 512 * sizeof( F_DIRENTRY ) ) / F_SECTOR_SIZE;\r
266 \r
267     gl_volume._tdata.sector = gl_volume.root.sector + gl_volume.root.num;\r
268     gl_volume._tdata.num = 0;  /*??*/\r
269   }\r
270   else\r
271   {\r
272     gl_volume.firstfat.sector = ( 32 + 4 );\r
273     gl_volume.firstfat.num = gl_volume.bootrecord.sector_per_FAT32;\r
274     gl_volume._tdata.sector = gl_volume.firstfat.sector;\r
275     gl_volume._tdata.sector += gl_volume.firstfat.num * (unsigned long)( gl_volume.bootrecord.number_of_FATs );\r
276     gl_volume._tdata.num = 0;  /*??*/\r
277 \r
278     {\r
279       unsigned long  sectorcou = gl_volume.bootrecord.sector_per_cluster;\r
280       gl_volume.root.sector = ( ( gl_volume.bootrecord.rootcluster - 2 ) * sectorcou ) + gl_volume._tdata.sector;\r
281       gl_volume.root.num = gl_volume.bootrecord.sector_per_cluster;\r
282     }\r
283   }\r
284 \r
285   {\r
286     unsigned long  maxcluster;\r
287     maxcluster = phy->number_of_sectors;\r
288     maxcluster -= gl_volume._tdata.sector;\r
289     maxcluster /= gl_volume.bootrecord.sector_per_cluster;\r
290     gl_volume.maxcluster = maxcluster;\r
291   }\r
292 \r
293   if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xfff ) )\r
294   {\r
295     gl_volume.mediatype = F_FAT12_MEDIA;\r
296   }\r
297   else if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xffff ) )\r
298   {\r
299     gl_volume.mediatype = F_FAT16_MEDIA;\r
300   }\r
301   else\r
302   {\r
303     gl_volume.mediatype = F_FAT32_MEDIA;\r
304   }\r
305 \r
306   return F_NO_ERROR;\r
307 } /* _f_buildsectors */\r
308 \r
309 \r
310 \r
311 /****************************************************************************\r
312  *\r
313  * _f_prepareformat\r
314  *\r
315  * preparing boot record for formatting, it sets and calculates values\r
316  *\r
317  * INPUTS\r
318  * phy - media physical descriptor\r
319  * f_bootrecord - which bootrecord need to be prepare\r
320  * number_of_hidden_sectors - where boot record starts\r
321  * fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA\r
322  *\r
323  * RETURNS\r
324  * error code or zero if successful\r
325  *\r
326  ***************************************************************************/\r
327 static unsigned char _f_prepareformat ( F_PHY * phy, unsigned char fattype )\r
328 {\r
329   if ( !phy->number_of_sectors )\r
330   {\r
331     return F_ERR_INVALIDSECTOR;\r
332   }\r
333 \r
334   gl_volume.bootrecord.number_of_FATs = 2;\r
335   gl_volume.bootrecord.media_descriptor = 0xf0;\r
336 \r
337   if ( fattype != F_FAT32_MEDIA )\r
338   {\r
339     unsigned long  _n;\r
340     switch ( fattype )\r
341     {\r
342       case F_FAT12_MEDIA:\r
343         _n = F_CLUSTER_RESERVED & 0xfff;\r
344         break;\r
345 \r
346       case F_FAT16_MEDIA:\r
347         _n = F_CLUSTER_RESERVED & 0xffff;\r
348         break;\r
349 \r
350       default:\r
351         return F_ERR_INVFATTYPE;\r
352     }\r
353 \r
354     gl_volume.bootrecord.sector_per_cluster = 1;\r
355     while ( gl_volume.bootrecord.sector_per_cluster )\r
356     {\r
357       if ( phy->number_of_sectors / gl_volume.bootrecord.sector_per_cluster < _n )\r
358       {\r
359         break;\r
360       }\r
361 \r
362       gl_volume.bootrecord.sector_per_cluster <<= 1;\r
363     }\r
364 \r
365     if ( !gl_volume.bootrecord.sector_per_cluster )\r
366     {\r
367       return F_ERR_MEDIATOOLARGE;\r
368     }\r
369   }\r
370 \r
371   else\r
372   {\r
373     unsigned char  i;\r
374     for ( i = 0 ; i<( sizeof( FAT32_CS ) / sizeof( t_FAT32_CS ) ) - 1 && phy->number_of_sectors>FAT32_CS[i].max_sectors ; i++ )\r
375     {\r
376     }\r
377 \r
378     gl_volume.bootrecord.sector_per_cluster = FAT32_CS[i].sector_per_cluster;\r
379   }\r
380   if ( !gl_volume.bootrecord.sector_per_cluster )\r
381   {\r
382     return F_ERR_INVALIDMEDIA;                                               /*fat16 cannot be there*/\r
383   }\r
384 \r
385   {\r
386     long           secpercl = gl_volume.bootrecord.sector_per_cluster;\r
387     long           nfat = gl_volume.bootrecord.number_of_FATs;\r
388     unsigned long  roots;\r
389     unsigned long  fatsec;\r
390 \r
391     roots = ( 512 * sizeof( F_DIRENTRY ) ) / F_SECTOR_SIZE;\r
392 \r
393     switch ( fattype )\r
394     {\r
395       case F_FAT32_MEDIA:\r
396       {\r
397         unsigned long  _n = (unsigned long)( 128 * secpercl + nfat );\r
398         fatsec = ( phy->number_of_sectors - ( 32 + 4 ) + 2 * secpercl );\r
399         fatsec += ( _n - 1 );\r
400         fatsec /= _n;\r
401         gl_volume.bootrecord.sector_per_FAT32 = fatsec;\r
402         gl_volume.bootrecord.sector_per_FAT = 0;\r
403       }\r
404       break;\r
405 \r
406       case F_FAT16_MEDIA:\r
407       {\r
408         unsigned long  _n = (unsigned long)( 256 * secpercl + nfat );\r
409         fatsec = ( phy->number_of_sectors - 1 - roots + 2 * secpercl );\r
410         fatsec += ( _n - 1 );\r
411         fatsec /= _n;\r
412         gl_volume.bootrecord.sector_per_FAT = (unsigned short)( fatsec );\r
413       }\r
414       break;\r
415 \r
416       case F_FAT12_MEDIA:\r
417       {\r
418         unsigned long  _n = (unsigned long)( 1024 * secpercl + 3 * nfat );\r
419         fatsec = ( phy->number_of_sectors - 1 - roots + 2 * secpercl );\r
420         fatsec *= 3;\r
421         fatsec += ( _n - 1 );\r
422         fatsec /= _n;\r
423         gl_volume.bootrecord.sector_per_FAT = (unsigned short)( fatsec );\r
424       }\r
425       break;\r
426 \r
427       default:\r
428         return F_ERR_INVALIDMEDIA;\r
429     } /* switch */\r
430 \r
431     return F_NO_ERROR;\r
432   }\r
433 } /* _f_prepareformat */\r
434 \r
435 \r
436 \r
437 /****************************************************************************\r
438  *\r
439  * _f_postformat\r
440  *\r
441  * erase fats, erase root directory, reset variables after formatting\r
442  *\r
443  * INPUTS\r
444  * phy - media physical descriptor\r
445  * fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA\r
446  *\r
447  * RETURNS\r
448  * error code or zero if successful\r
449  *\r
450  ***************************************************************************/\r
451 static unsigned char _f_postformat ( F_PHY * phy, unsigned char fattype )\r
452 {\r
453   unsigned long  a;\r
454   unsigned char  ret;\r
455 \r
456   _f_buildsectors( phy ); /*get positions*/\r
457   if ( gl_volume.mediatype != fattype )\r
458   {\r
459     return F_ERR_MEDIATOOSMALL;\r
460   }\r
461 \r
462   gl_volume.fatsector = (unsigned long)( -1 );\r
463 \r
464   {\r
465     unsigned char * ptr = (unsigned char *)gl_sector;\r
466     unsigned char   j = 2;\r
467     unsigned long   i;\r
468 \r
469     psp_memset( ptr, 0, F_SECTOR_SIZE );\r
470 \r
471     switch ( gl_volume.mediatype )\r
472     {\r
473       case F_FAT16_MEDIA:\r
474         j = 3;\r
475         break;\r
476 \r
477       case F_FAT32_MEDIA:\r
478         j = 11;\r
479         break;\r
480     }\r
481 \r
482     *ptr = gl_volume.bootrecord.media_descriptor;\r
483     psp_memset( ptr + 1, 0xff, j );\r
484     if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
485     {\r
486       *( ptr + 8 ) = (unsigned char)( F_CLUSTER_LAST & 0xff );\r
487     }\r
488 \r
489     (void)_f_writeglsector( gl_volume.firstfat.sector );\r
490     (void)_f_writeglsector( gl_volume.firstfat.sector + gl_volume.firstfat.num );\r
491     psp_memset( ptr, 0, ( j + 1 ) );\r
492 \r
493     for ( i = 1 ; i < gl_volume.firstfat.num ; i++ )\r
494     {\r
495       (void)_f_writeglsector( gl_volume.firstfat.sector + i );\r
496       (void)_f_writeglsector( gl_volume.firstfat.sector + i + gl_volume.firstfat.num );\r
497     }\r
498   }\r
499 \r
500   for ( a = 0 ; a < gl_volume.root.num ; a++ ) /*reset root direntries*/\r
501   {\r
502     ret = _f_writeglsector( gl_volume.root.sector + a );\r
503     if ( ret )\r
504     {\r
505       return ret;\r
506     }\r
507   }\r
508 \r
509   return _f_writebootrecord( phy );\r
510 } /* _f_postformat */\r
511 \r
512 \r
513 /****************************************************************************\r
514  *\r
515  * fn_hardformat\r
516  *\r
517  * Making a complete format on media, independently from master boot record,\r
518  * according to media physical\r
519  *\r
520  * INPUTS\r
521  * fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA\r
522  *\r
523  * RETURNS\r
524  * error code or zero if successful\r
525  *\r
526  ***************************************************************************/\r
527 unsigned char fn_hardformat ( unsigned char fattype )\r
528 {\r
529   unsigned char  ret;\r
530   int            mdrv_ret;\r
531   F_PHY          phy;\r
532 \r
533   ret = _f_getvolume();\r
534   if ( ret && ( ret != F_ERR_NOTFORMATTED ) )\r
535   {\r
536     return ret;\r
537   }\r
538 \r
539   gl_volume.state = F_STATE_NEEDMOUNT;\r
540 \r
541   psp_memset( &phy, 0, sizeof( F_PHY ) );\r
542 \r
543   mdrv_ret = mdrv->getphy( mdrv, &phy );\r
544   if ( mdrv_ret )\r
545   {\r
546     return F_ERR_ONDRIVE;\r
547   }\r
548 \r
549   ret = _f_prepareformat( &phy, fattype ); /*no partition*/\r
550   if ( ret )\r
551   {\r
552     return ret;\r
553   }\r
554 \r
555   return _f_postformat( &phy, fattype );\r
556 } /* fn_hardformat */\r
557 \r
558 \r
559 \r
560 \r
561 /****************************************************************************\r
562  *\r
563  * _f_readbootrecord\r
564  *\r
565  * read boot record from a volume, it detects if there is MBR on the media\r
566  *\r
567  * RETURNS\r
568  *\r
569  * error code or zero if successful\r
570  *\r
571  ***************************************************************************/\r
572 static unsigned char _f_readbootrecord ( void )\r
573 {\r
574   unsigned char   ret;\r
575   unsigned char * ptr = (unsigned char *)gl_sector;\r
576   unsigned long   maxcluster, _n;\r
577   unsigned long   first_sector = 0;\r
578 \r
579   gl_volume.mediatype = F_UNKNOWN_MEDIA;\r
580 \r
581 \r
582   ret = _f_readglsector( 0 );\r
583   if ( ret )\r
584   {\r
585     return ret;\r
586   }\r
587 \r
588 \r
589   if ( ( ptr[0x1fe] != 0x55 ) || ( ptr[0x1ff] != 0xaa ) )\r
590   {\r
591     return F_ERR_NOTFORMATTED;                                              /*??*/\r
592   }\r
593 \r
594   if ( ( ptr[0] != 0xeb ) && ( ptr[0] != 0xe9 ) )\r
595   {\r
596     first_sector = _f_getlong( &ptr[0x08 + 0x1be] ); /*start sector for 1st partioon*/\r
597 \r
598     ret = _f_readglsector( first_sector );\r
599     if ( ret )\r
600     {\r
601       return ret;\r
602     }\r
603 \r
604     if ( ( ptr[0x1fe] != 0x55 ) || ( ptr[0x1ff] != 0xaa ) )\r
605     {\r
606       return F_ERR_NOTFORMATTED;                                                /*??*/\r
607     }\r
608 \r
609     if ( ( ptr[0] != 0xeb ) && ( ptr[0] != 0xe9 ) )\r
610     {\r
611       return F_ERR_NOTFORMATTED;                                        /*??*/\r
612     }\r
613   }\r
614 \r
615   ptr += 11;\r
616   if ( _f_getword( ptr ) != F_SECTOR_SIZE )\r
617   {\r
618     return F_ERR_NOTSUPPSECTORSIZE;\r
619   }\r
620 \r
621   ptr += 2;\r
622   gl_volume.bootrecord.sector_per_cluster = *ptr++;\r
623   gl_volume.firstfat.sector = _f_getword( ptr );\r
624   ptr += 2;\r
625   gl_volume.bootrecord.number_of_FATs = *ptr++;\r
626   gl_volume.root.num = _f_getword( ptr );\r
627   ptr += 2;\r
628   gl_volume.root.num *= sizeof( F_DIRENTRY );\r
629   gl_volume.root.num /= F_SECTOR_SIZE;\r
630   maxcluster = _f_getword( ptr );\r
631   ptr += 2;\r
632   gl_volume.bootrecord.media_descriptor = *ptr++;\r
633   gl_volume.firstfat.num = _f_getword( ptr );\r
634   ptr += 6;\r
635   _n = _f_getlong( ptr );\r
636   ptr += 4;\r
637   if ( _n < first_sector )\r
638   {\r
639     _n = first_sector;\r
640   }\r
641 \r
642   gl_volume.firstfat.sector += _n;\r
643   if ( !maxcluster )\r
644   {\r
645     maxcluster = _f_getlong( ptr );\r
646   }\r
647 \r
648   ptr += 4;\r
649 \r
650 \r
651   if ( gl_volume.firstfat.num )\r
652   {\r
653     gl_volume.root.sector = gl_volume.firstfat.sector + ( gl_volume.firstfat.num * gl_volume.bootrecord.number_of_FATs );\r
654     gl_volume._tdata.sector = gl_volume.root.sector + gl_volume.root.num;\r
655     gl_volume._tdata.num = 0;\r
656     ptr += 3;\r
657   }\r
658   else\r
659   {\r
660     gl_volume.firstfat.num = _f_getlong( ptr );\r
661     ptr += 8;\r
662     gl_volume._tdata.sector = gl_volume.firstfat.sector;\r
663     gl_volume._tdata.sector += gl_volume.firstfat.num * gl_volume.bootrecord.number_of_FATs;\r
664     gl_volume._tdata.num = 0;\r
665     gl_volume.bootrecord.rootcluster = _f_getlong( ptr );\r
666     ptr += 23;\r
667     gl_volume.root.num = gl_volume.bootrecord.sector_per_cluster;\r
668     gl_volume.root.sector = ( ( gl_volume.bootrecord.rootcluster - 2 ) * gl_volume.root.num ) + gl_volume._tdata.sector;\r
669   }\r
670 \r
671   gl_volume.bootrecord.serial_number = _f_getlong( ptr );\r
672 \r
673   maxcluster -= gl_volume._tdata.sector;\r
674   maxcluster += _n;\r
675   gl_volume.maxcluster = maxcluster / gl_volume.bootrecord.sector_per_cluster;\r
676 \r
677   if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xfff ) )\r
678   {\r
679     gl_volume.mediatype = F_FAT12_MEDIA;\r
680   }\r
681   else if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xffff ) )\r
682   {\r
683     gl_volume.mediatype = F_FAT16_MEDIA;\r
684   }\r
685   else\r
686   {\r
687     gl_volume.mediatype = F_FAT32_MEDIA;\r
688   }\r
689 \r
690   if ( gl_volume.bootrecord.media_descriptor != 0xf8 )    /*fixdrive*/\r
691   {\r
692     if ( gl_volume.bootrecord.media_descriptor != 0xf0 )  /*removable*/\r
693     {\r
694       return F_ERR_NOTFORMATTED;      /*??*/\r
695     }\r
696   }\r
697 \r
698   return F_NO_ERROR;\r
699 } /* _f_readbootrecord */\r
700 \r
701 \r
702 \r
703 \r
704 /****************************************************************************\r
705  *\r
706  * _f_getvolume\r
707  *\r
708  * getting back a volume info structure of a given drive, it try to mounts\r
709  * drive if it was not mounted before\r
710  *\r
711  * RETURNS\r
712  *\r
713  * error code or zero if successful\r
714  *\r
715  ***************************************************************************/\r
716 unsigned char _f_getvolume ( void )\r
717 {\r
718   switch ( gl_volume.state )\r
719   {\r
720     case F_STATE_NONE:\r
721       return F_ERR_ONDRIVE;\r
722 \r
723     case F_STATE_WORKING:\r
724 \r
725       if ( !_f_checkstatus() )\r
726       {\r
727         return F_NO_ERROR;\r
728       }\r
729 \r
730     /* here we don't stop case flow,  */\r
731     /* because we have to clean up this volume! */\r
732 \r
733     case F_STATE_NEEDMOUNT:\r
734     {\r
735       gl_file.modified = 0;\r
736       gl_volume.modified = 0;\r
737       gl_volume.lastalloccluster = 0;\r
738       gl_volume.actsector = (unsigned long)( -1 );\r
739       gl_volume.fatsector = (unsigned long)( -1 );\r
740 \r
741       gl_file.mode = F_FILE_CLOSE;\r
742 \r
743       gl_volume.cwd[0] = 0;     /*reset cwd*/\r
744       gl_volume.mediatype = F_UNKNOWN_MEDIA;\r
745 \r
746       if ( mdrv->getstatus != NULL )\r
747       {\r
748         if ( mdrv->getstatus( mdrv ) & F_ST_MISSING )\r
749         {\r
750           gl_volume.state = F_STATE_NEEDMOUNT;         /*card missing*/\r
751           return F_ERR_CARDREMOVED;\r
752         }\r
753       }\r
754 \r
755       if ( !_f_readbootrecord() )\r
756       {\r
757         gl_volume.state = F_STATE_WORKING;\r
758         return F_NO_ERROR;\r
759       }\r
760 \r
761       gl_volume.mediatype = F_UNKNOWN_MEDIA;\r
762       return F_ERR_NOTFORMATTED;\r
763     }\r
764   } /* switch */\r
765 \r
766   return F_ERR_ONDRIVE;\r
767 } /* _f_getvolume */\r
768 \r
769 \r
770 \r
771 /****************************************************************************\r
772  *\r
773  * fn_getfreespace\r
774  *\r
775  * get total/free/used/bad diskspace\r
776  *\r
777  * INPUTS\r
778  * pspace - pointer where to store the information\r
779  *\r
780  * RETURNS\r
781  * error code\r
782  *\r
783  ***************************************************************************/\r
784 unsigned char fn_getfreespace ( F_SPACE * pspace )\r
785 {\r
786   unsigned char  ret;\r
787   unsigned long  a;\r
788   unsigned long  clustersize;\r
789 \r
790   ret = _f_getvolume();\r
791   if ( ret )\r
792   {\r
793     return ret;\r
794   }\r
795 \r
796   psp_memset( pspace, 0, sizeof( F_SPACE ) );\r
797   pspace->total = gl_volume.maxcluster;\r
798 \r
799   gl_volume.fatsector = (unsigned long)-1;\r
800   for ( a = 2 ; a < gl_volume.maxcluster + 2 ; a++ )\r
801   {\r
802     unsigned long  value;\r
803 \r
804     ret = _f_getclustervalue( a, &value );\r
805     if ( ret )\r
806     {\r
807       return ret;\r
808     }\r
809 \r
810     if ( !value )\r
811     {\r
812       ++( pspace->free );\r
813     }\r
814     else if ( value == F_CLUSTER_BAD )\r
815     {\r
816       ++( pspace->bad );\r
817     }\r
818     else\r
819     {\r
820       ++( pspace->used );\r
821     }\r
822   }\r
823 \r
824   clustersize = (unsigned long)( gl_volume.bootrecord.sector_per_cluster * F_SECTOR_SIZE );\r
825   for ( a = 0 ; ( clustersize & 1 ) == 0 ; a++ )\r
826   {\r
827     clustersize >>= 1;\r
828   }\r
829 \r
830   pspace->total_high = ( pspace->total ) >> ( 32 - a );\r
831   pspace->total <<= a;\r
832   pspace->free_high = ( pspace->free ) >> ( 32 - a );\r
833   pspace->free <<= a;\r
834   pspace->used_high = ( pspace->used ) >> ( 32 - a );\r
835   pspace->used <<= a;\r
836   pspace->bad_high = ( pspace->bad ) >> ( 32 - a );\r
837   pspace->bad <<= a;\r
838 \r
839   return F_NO_ERROR;\r
840 } /* fn_getfreespace */\r
841 \r
842 \r
843 /****************************************************************************\r
844  *\r
845  * fn_getserial\r
846  *\r
847  * get serial number\r
848  *\r
849  * INPUTS\r
850  * serial - pointer where to store the serial number\r
851  *\r
852  * RETURNS\r
853  * error code\r
854  *\r
855  ***************************************************************************/\r
856 unsigned char fn_getserial ( unsigned long * serial )\r
857 {\r
858   unsigned char  ret;\r
859 \r
860   ret = _f_getvolume();\r
861   if ( ret )\r
862   {\r
863     return ret;\r
864   }\r
865 \r
866   *serial = gl_volume.bootrecord.serial_number;\r
867   return 0;\r
868 }\r
869 \r
870 /*\r
871 ** fn_init\r
872 **\r
873 ** Initialize FAT_SL file system\r
874 **\r
875 ** RETURN: F_NO_ERROR on success, other if error.\r
876 */\r
877 unsigned char fn_init ( void )\r
878 {\r
879   return F_NO_ERROR;\r
880 } /* fn_init */\r
881 \r
882 /****************************************************************************\r
883  *\r
884  * fn_initvolume\r
885  *\r
886  * initiate a volume, this function has to be called 1st to set physical\r
887  * driver function to a given volume\r
888  *\r
889  * RETURNS\r
890  *\r
891  * error code or zero if successful\r
892  *\r
893  ***************************************************************************/\r
894 unsigned char fn_initvolume ( F_DRIVERINIT initfunc )\r
895 {\r
896 #if F_FS_THREAD_AWARE == 1\r
897   {\r
898     if( fs_lock_semaphore == NULL )\r
899     {\r
900       fs_lock_semaphore = xSemaphoreCreateMutex();\r
901       if( fs_lock_semaphore == NULL )\r
902       {\r
903         return F_ERR_OS;\r
904       }\r
905     }\r
906   }\r
907 #endif /* F_FS_THREAD_AWARE */\r
908 \r
909   gl_volume.state = F_STATE_NONE;\r
910 \r
911   mdrv = initfunc( 0 );\r
912   if ( mdrv == NULL )\r
913   {\r
914     return F_ERR_INITFUNC;\r
915   }\r
916 \r
917   gl_volume.state = F_STATE_NEEDMOUNT;\r
918 \r
919 #if F_FILE_CHANGED_EVENT\r
920   f_filechangedevent = 0;\r
921 #endif\r
922 \r
923   return _f_getvolume();\r
924 } /* fn_initvolume */\r
925 \r
926 /****************************************************************************\r
927  *\r
928  * fn_delvolume\r
929  *\r
930  ***************************************************************************/\r
931 unsigned char fn_delvolume ( void )\r
932 {\r
933   if ( mdrv->release )\r
934   {\r
935     (void)mdrv->release( mdrv );\r
936   }\r
937 \r
938   return 0;\r
939 }\r