]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT-SL/fat_sl/common/volume.c
Add missing +TCP code.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-FAT-SL / fat_sl / common / volume.c
1 /*\r
2  * FreeRTOS+FAT SL V1.0.1 (C) 2014 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 != 5 || 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 \r
383   if ( !gl_volume.bootrecord.sector_per_cluster )\r
384   {\r
385     return F_ERR_INVALIDMEDIA;                                               /*fat16 cannot be there*/\r
386   }\r
387 \r
388   {\r
389     long           secpercl = gl_volume.bootrecord.sector_per_cluster;\r
390     long           nfat = gl_volume.bootrecord.number_of_FATs;\r
391     unsigned long  roots;\r
392     unsigned long  fatsec;\r
393 \r
394     roots = ( 512 * sizeof( F_DIRENTRY ) ) / F_SECTOR_SIZE;\r
395 \r
396     switch ( fattype )\r
397     {\r
398       case F_FAT32_MEDIA:\r
399       {\r
400         unsigned long  _n = (unsigned long)( 128 * secpercl + nfat );\r
401         fatsec = ( phy->number_of_sectors - ( 32 + 4 ) + 2 * secpercl );\r
402         fatsec += ( _n - 1 );\r
403         fatsec /= _n;\r
404         gl_volume.bootrecord.sector_per_FAT32 = fatsec;\r
405         gl_volume.bootrecord.sector_per_FAT = 0;\r
406       }\r
407       break;\r
408 \r
409       case F_FAT16_MEDIA:\r
410       {\r
411         unsigned long  _n = (unsigned long)( 256 * secpercl + nfat );\r
412         fatsec = ( phy->number_of_sectors - 1 - roots + 2 * secpercl );\r
413         fatsec += ( _n - 1 );\r
414         fatsec /= _n;\r
415         gl_volume.bootrecord.sector_per_FAT = (unsigned short)( fatsec );\r
416       }\r
417       break;\r
418 \r
419       case F_FAT12_MEDIA:\r
420       {\r
421         unsigned long  _n = (unsigned long)( 1024 * secpercl + 3 * nfat );\r
422         fatsec = ( phy->number_of_sectors - 1 - roots + 2 * secpercl );\r
423         fatsec *= 3;\r
424         fatsec += ( _n - 1 );\r
425         fatsec /= _n;\r
426         gl_volume.bootrecord.sector_per_FAT = (unsigned short)( fatsec );\r
427       }\r
428       break;\r
429 \r
430       default:\r
431         return F_ERR_INVALIDMEDIA;\r
432     } /* switch */\r
433 \r
434     return F_NO_ERROR;\r
435   }\r
436 } /* _f_prepareformat */\r
437 \r
438 \r
439 \r
440 /****************************************************************************\r
441  *\r
442  * _f_postformat\r
443  *\r
444  * erase fats, erase root directory, reset variables after formatting\r
445  *\r
446  * INPUTS\r
447  * phy - media physical descriptor\r
448  * fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA\r
449  *\r
450  * RETURNS\r
451  * error code or zero if successful\r
452  *\r
453  ***************************************************************************/\r
454 static unsigned char _f_postformat ( F_PHY * phy, unsigned char fattype )\r
455 {\r
456   unsigned long  a;\r
457   unsigned char  ret;\r
458 \r
459   _f_buildsectors( phy ); /*get positions*/\r
460   if ( gl_volume.mediatype != fattype )\r
461   {\r
462     return F_ERR_MEDIATOOSMALL;\r
463   }\r
464 \r
465   gl_volume.fatsector = (unsigned long)( -1 );\r
466 \r
467   {\r
468     unsigned char * ptr = (unsigned char *)gl_sector;\r
469     unsigned char   j = 2;\r
470     unsigned long   i;\r
471 \r
472     psp_memset( ptr, 0, F_SECTOR_SIZE );\r
473 \r
474     switch ( gl_volume.mediatype )\r
475     {\r
476       case F_FAT16_MEDIA:\r
477         j = 3;\r
478         break;\r
479 \r
480       case F_FAT32_MEDIA:\r
481         j = 11;\r
482         break;\r
483     }\r
484 \r
485     *ptr = gl_volume.bootrecord.media_descriptor;\r
486     psp_memset( ptr + 1, 0xff, j );\r
487     if ( gl_volume.mediatype == F_FAT32_MEDIA )\r
488     {\r
489       *( ptr + 8 ) = (unsigned char)( F_CLUSTER_LAST & 0xff );\r
490     }\r
491 \r
492     (void)_f_writeglsector( gl_volume.firstfat.sector );\r
493     (void)_f_writeglsector( gl_volume.firstfat.sector + gl_volume.firstfat.num );\r
494     psp_memset( ptr, 0, ( j + 1 ) );\r
495 \r
496     for ( i = 1 ; i < gl_volume.firstfat.num ; i++ )\r
497     {\r
498       (void)_f_writeglsector( gl_volume.firstfat.sector + i );\r
499       (void)_f_writeglsector( gl_volume.firstfat.sector + i + gl_volume.firstfat.num );\r
500     }\r
501   }\r
502 \r
503   for ( a = 0 ; a < gl_volume.root.num ; a++ ) /*reset root direntries*/\r
504   {\r
505     ret = _f_writeglsector( gl_volume.root.sector + a );\r
506     if ( ret )\r
507     {\r
508       return ret;\r
509     }\r
510   }\r
511 \r
512   return _f_writebootrecord( phy );\r
513 } /* _f_postformat */\r
514 \r
515 \r
516 /****************************************************************************\r
517  *\r
518  * fn_hardformat\r
519  *\r
520  * Making a complete format on media, independently from master boot record,\r
521  * according to media physical\r
522  *\r
523  * INPUTS\r
524  * fattype - one of this definitions F_FAT12_MEDIA,F_FAT16_MEDIA,F_FAT32_MEDIA\r
525  *\r
526  * RETURNS\r
527  * error code or zero if successful\r
528  *\r
529  ***************************************************************************/\r
530 unsigned char fn_hardformat ( unsigned char fattype )\r
531 {\r
532   unsigned char  ret;\r
533   int            mdrv_ret;\r
534   F_PHY          phy;\r
535 \r
536   ret = _f_getvolume();\r
537   if ( ret && ( ret != F_ERR_NOTFORMATTED ) )\r
538   {\r
539     return ret;\r
540   }\r
541 \r
542   gl_volume.state = F_STATE_NEEDMOUNT;\r
543 \r
544   psp_memset( &phy, 0, sizeof( F_PHY ) );\r
545 \r
546   mdrv_ret = mdrv->getphy( mdrv, &phy );\r
547   if ( mdrv_ret )\r
548   {\r
549     return F_ERR_ONDRIVE;\r
550   }\r
551 \r
552   ret = _f_prepareformat( &phy, fattype ); /*no partition*/\r
553   if ( ret )\r
554   {\r
555     return ret;\r
556   }\r
557 \r
558   return _f_postformat( &phy, fattype );\r
559 } /* fn_hardformat */\r
560 \r
561 \r
562 \r
563 \r
564 /****************************************************************************\r
565  *\r
566  * _f_readbootrecord\r
567  *\r
568  * read boot record from a volume, it detects if there is MBR on the media\r
569  *\r
570  * RETURNS\r
571  *\r
572  * error code or zero if successful\r
573  *\r
574  ***************************************************************************/\r
575 static unsigned char _f_readbootrecord ( void )\r
576 {\r
577   unsigned char   ret;\r
578   unsigned char * ptr = (unsigned char *)gl_sector;\r
579   unsigned long   maxcluster, _n;\r
580   unsigned long   first_sector = 0;\r
581 \r
582   gl_volume.mediatype = F_UNKNOWN_MEDIA;\r
583 \r
584 \r
585   ret = _f_readglsector( 0 );\r
586   if ( ret )\r
587   {\r
588     return ret;\r
589   }\r
590 \r
591 \r
592   if ( ( ptr[0x1fe] != 0x55 ) || ( ptr[0x1ff] != 0xaa ) )\r
593   {\r
594     return F_ERR_NOTFORMATTED;                                              /*??*/\r
595   }\r
596 \r
597   if ( ( ptr[0] != 0xeb ) && ( ptr[0] != 0xe9 ) )\r
598   {\r
599     first_sector = _f_getlong( &ptr[0x08 + 0x1be] ); /*start sector for 1st partioon*/\r
600 \r
601     ret = _f_readglsector( first_sector );\r
602     if ( ret )\r
603     {\r
604       return ret;\r
605     }\r
606 \r
607     if ( ( ptr[0x1fe] != 0x55 ) || ( ptr[0x1ff] != 0xaa ) )\r
608     {\r
609       return F_ERR_NOTFORMATTED;                                                /*??*/\r
610     }\r
611 \r
612     if ( ( ptr[0] != 0xeb ) && ( ptr[0] != 0xe9 ) )\r
613     {\r
614       return F_ERR_NOTFORMATTED;                                        /*??*/\r
615     }\r
616   }\r
617 \r
618   ptr += 11;\r
619   if ( _f_getword( ptr ) != F_SECTOR_SIZE )\r
620   {\r
621     return F_ERR_NOTSUPPSECTORSIZE;\r
622   }\r
623 \r
624   ptr += 2;\r
625   gl_volume.bootrecord.sector_per_cluster = *ptr++;\r
626   gl_volume.firstfat.sector = _f_getword( ptr );\r
627   ptr += 2;\r
628   gl_volume.bootrecord.number_of_FATs = *ptr++;\r
629   gl_volume.root.num = _f_getword( ptr );\r
630   ptr += 2;\r
631   gl_volume.root.num *= sizeof( F_DIRENTRY );\r
632   gl_volume.root.num /= F_SECTOR_SIZE;\r
633   maxcluster = _f_getword( ptr );\r
634   ptr += 2;\r
635   gl_volume.bootrecord.media_descriptor = *ptr++;\r
636   gl_volume.firstfat.num = _f_getword( ptr );\r
637   ptr += 6;\r
638   _n = _f_getlong( ptr );\r
639   ptr += 4;\r
640   if ( _n < first_sector )\r
641   {\r
642     _n = first_sector;\r
643   }\r
644 \r
645   gl_volume.firstfat.sector += _n;\r
646   if ( !maxcluster )\r
647   {\r
648     maxcluster = _f_getlong( ptr );\r
649   }\r
650 \r
651   ptr += 4;\r
652 \r
653 \r
654   if ( gl_volume.firstfat.num )\r
655   {\r
656     gl_volume.root.sector = gl_volume.firstfat.sector + ( gl_volume.firstfat.num * gl_volume.bootrecord.number_of_FATs );\r
657     gl_volume._tdata.sector = gl_volume.root.sector + gl_volume.root.num;\r
658     gl_volume._tdata.num = 0;\r
659     ptr += 3;\r
660   }\r
661   else\r
662   {\r
663     gl_volume.firstfat.num = _f_getlong( ptr );\r
664     ptr += 8;\r
665     gl_volume._tdata.sector = gl_volume.firstfat.sector;\r
666     gl_volume._tdata.sector += gl_volume.firstfat.num * gl_volume.bootrecord.number_of_FATs;\r
667     gl_volume._tdata.num = 0;\r
668     gl_volume.bootrecord.rootcluster = _f_getlong( ptr );\r
669     ptr += 23;\r
670     gl_volume.root.num = gl_volume.bootrecord.sector_per_cluster;\r
671     gl_volume.root.sector = ( ( gl_volume.bootrecord.rootcluster - 2 ) * gl_volume.root.num ) + gl_volume._tdata.sector;\r
672   }\r
673 \r
674   gl_volume.bootrecord.serial_number = _f_getlong( ptr );\r
675 \r
676   maxcluster -= gl_volume._tdata.sector;\r
677   maxcluster += _n;\r
678   gl_volume.maxcluster = maxcluster / gl_volume.bootrecord.sector_per_cluster;\r
679 \r
680   if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xfff ) )\r
681   {\r
682     gl_volume.mediatype = F_FAT12_MEDIA;\r
683   }\r
684   else if ( gl_volume.maxcluster < ( F_CLUSTER_RESERVED & 0xffff ) )\r
685   {\r
686     gl_volume.mediatype = F_FAT16_MEDIA;\r
687   }\r
688   else\r
689   {\r
690     gl_volume.mediatype = F_FAT32_MEDIA;\r
691   }\r
692 \r
693   if ( gl_volume.bootrecord.media_descriptor != 0xf8 )    /*fixdrive*/\r
694   {\r
695     if ( gl_volume.bootrecord.media_descriptor != 0xf0 )  /*removable*/\r
696     {\r
697       return F_ERR_NOTFORMATTED;      /*??*/\r
698     }\r
699   }\r
700 \r
701   return F_NO_ERROR;\r
702 } /* _f_readbootrecord */\r
703 \r
704 \r
705 \r
706 \r
707 /****************************************************************************\r
708  *\r
709  * _f_getvolume\r
710  *\r
711  * getting back a volume info structure of a given drive, it try to mounts\r
712  * drive if it was not mounted before\r
713  *\r
714  * RETURNS\r
715  *\r
716  * error code or zero if successful\r
717  *\r
718  ***************************************************************************/\r
719 unsigned char _f_getvolume ( void )\r
720 {\r
721   switch ( gl_volume.state )\r
722   {\r
723     case F_STATE_NONE:\r
724       return F_ERR_ONDRIVE;\r
725 \r
726     case F_STATE_WORKING:\r
727 \r
728       if ( !_f_checkstatus() )\r
729       {\r
730         return F_NO_ERROR;\r
731       }\r
732 \r
733     /* here we don't stop case flow,  */\r
734     /* because we have to clean up this volume! */\r
735 \r
736     case F_STATE_NEEDMOUNT:\r
737     {\r
738       gl_file.modified = 0;\r
739       gl_volume.modified = 0;\r
740       gl_volume.lastalloccluster = 0;\r
741       gl_volume.actsector = (unsigned long)( -1 );\r
742       gl_volume.fatsector = (unsigned long)( -1 );\r
743 \r
744       gl_file.mode = F_FILE_CLOSE;\r
745 \r
746       gl_volume.cwd[0] = 0;     /*reset cwd*/\r
747       gl_volume.mediatype = F_UNKNOWN_MEDIA;\r
748 \r
749       if ( mdrv->getstatus != NULL )\r
750       {\r
751         if ( mdrv->getstatus( mdrv ) & F_ST_MISSING )\r
752         {\r
753           gl_volume.state = F_STATE_NEEDMOUNT;         /*card missing*/\r
754           return F_ERR_CARDREMOVED;\r
755         }\r
756       }\r
757 \r
758       if ( !_f_readbootrecord() )\r
759       {\r
760         gl_volume.state = F_STATE_WORKING;\r
761         return F_NO_ERROR;\r
762       }\r
763 \r
764       gl_volume.mediatype = F_UNKNOWN_MEDIA;\r
765       return F_ERR_NOTFORMATTED;\r
766     }\r
767   } /* switch */\r
768 \r
769   return F_ERR_ONDRIVE;\r
770 } /* _f_getvolume */\r
771 \r
772 \r
773 \r
774 /****************************************************************************\r
775  *\r
776  * fn_getfreespace\r
777  *\r
778  * get total/free/used/bad diskspace\r
779  *\r
780  * INPUTS\r
781  * pspace - pointer where to store the information\r
782  *\r
783  * RETURNS\r
784  * error code\r
785  *\r
786  ***************************************************************************/\r
787 unsigned char fn_getfreespace ( F_SPACE * pspace )\r
788 {\r
789   unsigned char  ret;\r
790   unsigned long  a;\r
791   unsigned long  clustersize;\r
792 \r
793   ret = _f_getvolume();\r
794   if ( ret )\r
795   {\r
796     return ret;\r
797   }\r
798 \r
799   psp_memset( pspace, 0, sizeof( F_SPACE ) );\r
800   pspace->total = gl_volume.maxcluster;\r
801 \r
802   gl_volume.fatsector = (unsigned long)-1;\r
803   for ( a = 2 ; a < gl_volume.maxcluster + 2 ; a++ )\r
804   {\r
805     unsigned long  value;\r
806 \r
807     ret = _f_getclustervalue( a, &value );\r
808     if ( ret )\r
809     {\r
810       return ret;\r
811     }\r
812 \r
813     if ( !value )\r
814     {\r
815       ++( pspace->free );\r
816     }\r
817     else if ( value == F_CLUSTER_BAD )\r
818     {\r
819       ++( pspace->bad );\r
820     }\r
821     else\r
822     {\r
823       ++( pspace->used );\r
824     }\r
825   }\r
826 \r
827   clustersize = (unsigned long)( gl_volume.bootrecord.sector_per_cluster * F_SECTOR_SIZE );\r
828   for ( a = 0 ; ( clustersize & 1 ) == 0 ; a++ )\r
829   {\r
830     clustersize >>= 1;\r
831   }\r
832 \r
833   pspace->total_high = ( pspace->total ) >> ( 32 - a );\r
834   pspace->total <<= a;\r
835   pspace->free_high = ( pspace->free ) >> ( 32 - a );\r
836   pspace->free <<= a;\r
837   pspace->used_high = ( pspace->used ) >> ( 32 - a );\r
838   pspace->used <<= a;\r
839   pspace->bad_high = ( pspace->bad ) >> ( 32 - a );\r
840   pspace->bad <<= a;\r
841 \r
842   return F_NO_ERROR;\r
843 } /* fn_getfreespace */\r
844 \r
845 \r
846 /****************************************************************************\r
847  *\r
848  * fn_getserial\r
849  *\r
850  * get serial number\r
851  *\r
852  * INPUTS\r
853  * serial - pointer where to store the serial number\r
854  *\r
855  * RETURNS\r
856  * error code\r
857  *\r
858  ***************************************************************************/\r
859 unsigned char fn_getserial ( unsigned long * serial )\r
860 {\r
861   unsigned char  ret;\r
862 \r
863   ret = _f_getvolume();\r
864   if ( ret )\r
865   {\r
866     return ret;\r
867   }\r
868 \r
869   *serial = gl_volume.bootrecord.serial_number;\r
870   return 0;\r
871 }\r
872 \r
873 \r
874 /*\r
875 ** fs_init\r
876 **\r
877 ** Initialize STHIN file system\r
878 **\r
879 ** RETURN: F_NO_ERROR on success, other if error.\r
880 */\r
881 unsigned char fs_init ( void )\r
882 {\r
883   unsigned char  rc = F_NO_ERROR;\r
884 \r
885 #if RTOS_SUPPORT\r
886   rc = fsr_init();\r
887   if ( rc )\r
888   {\r
889     return rc;\r
890   }\r
891 \r
892 #endif\r
893   return rc;\r
894 } /* fs_init */\r
895 \r
896 \r
897 /*\r
898 ** fs_delete\r
899 **\r
900 ** Delete STHIN file system\r
901 **\r
902 ** RETURN: F_NO_ERROR on success, other if error.\r
903 */\r
904 unsigned char fs_delete ( void )\r
905 {\r
906   unsigned char  rc = F_NO_ERROR;\r
907 \r
908 #if RTOS_SUPPORT\r
909   rc = fsr_delete();\r
910   if ( rc )\r
911   {\r
912     return rc;\r
913   }\r
914 \r
915 #endif\r
916   return rc;\r
917 } /* fs_delete */\r
918 \r
919 \r
920 /****************************************************************************\r
921  *\r
922  * fn_initvolume\r
923  *\r
924  * initiate a volume, this function has to be called 1st to set physical\r
925  * driver function to a given volume\r
926  *\r
927  * RETURNS\r
928  *\r
929  * error code or zero if successful\r
930  *\r
931  ***************************************************************************/\r
932 unsigned char fn_initvolume ( F_DRIVERINIT initfunc )\r
933 {\r
934 #if F_FS_THREAD_AWARE == 1\r
935         {\r
936                 extern xSemaphoreHandle fs_lock_semaphore;\r
937 \r
938                 if( fs_lock_semaphore == NULL )\r
939                 {\r
940                         fs_lock_semaphore = xSemaphoreCreateMutex();\r
941                         if( fs_lock_semaphore == NULL )\r
942                         {\r
943                                 return F_ERR_OS;\r
944                         }\r
945                 }\r
946         }\r
947 #endif /* F_FS_THREAD_AWARE */\r
948 \r
949   gl_volume.state = F_STATE_NONE;\r
950 \r
951   mdrv = initfunc( 0 );\r
952   if ( mdrv == NULL )\r
953   {\r
954     return F_ERR_INITFUNC;\r
955   }\r
956 \r
957   gl_volume.state = F_STATE_NEEDMOUNT;\r
958 \r
959 #if F_FILE_CHANGED_EVENT\r
960   f_filechangedevent = 0;\r
961 #endif\r
962 \r
963   return _f_getvolume();\r
964 } /* fn_initvolume */\r
965 \r
966 \r
967 /****************************************************************************\r
968  *\r
969  * fn_delvolume\r
970  *\r
971  ***************************************************************************/\r
972 unsigned char fn_delvolume ( void )\r
973 {\r
974   if ( mdrv->release )\r
975   {\r
976     (void)mdrv->release( mdrv );\r
977   }\r
978 \r
979   return 0;\r
980 }\r