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