]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_format.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / ff_format.c
1 /*\r
2  * FreeRTOS+FAT build 191128 - Note:  FreeRTOS+FAT is still in the lab!\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  * Authors include James Walmsley, Hein Tibosch and Richard Barry\r
5  *\r
6  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
7  * this software and associated documentation files (the "Software"), to deal in\r
8  * the Software without restriction, including without limitation the rights to\r
9  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
10  * the Software, and to permit persons to whom the Software is furnished to do so,\r
11  * subject to the following conditions:\r
12  *\r
13  * The above copyright notice and this permission notice shall be included in all\r
14  * copies or substantial portions of the Software.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * https://www.FreeRTOS.org\r
24  *\r
25  */\r
26 \r
27 /**\r
28  *      @file           ff_format.c\r
29  *      @ingroup        FORMAT\r
30  *\r
31  *      @defgroup       FAT Fat File-System\r
32  *      @brief          Format a drive, given the number of sectors.\r
33  *\r
34  **/\r
35 \r
36 #include "ff_headers.h"\r
37 \r
38 #include <time.h>\r
39 #include <string.h>\r
40 \r
41 #if defined( __BORLANDC__ )\r
42         #include "ff_windows.h"\r
43 #else\r
44         #include "FreeRTOS.h"\r
45         #include "task.h"       /* For FreeRTOS date/time function */\r
46 #endif\r
47 \r
48 \r
49 /*=========================================================================================== */\r
50 \r
51 #define OFS_PART_ACTIVE_8             0x000 /* 0x01BE 0x80 if active */\r
52 #define OFS_PART_START_HEAD_8         0x001 /* 0x01BF */\r
53 #define OFS_PART_START_SEC_TRACK_16   0x002 /* 0x01C0 */\r
54 #define OFS_PART_ID_NUMBER_8          0x004 /* 0x01C2 */\r
55 #define OFS_PART_ENDING_HEAD_8        0x005 /* 0x01C3 */\r
56 #define OFS_PART_ENDING_SEC_TRACK_16  0x006 /* 0x01C4   = SectorCount - 1 - ulHiddenSectors */\r
57 #define OFS_PART_STARTING_LBA_32      0x008 /* 0x01C6   = ulHiddenSectors (This is important) */\r
58 #define OFS_PART_LENGTH_32            0x00C /* 0x01CA   = SectorCount - 1 - ulHiddenSectors */\r
59 \r
60 #define OFS_PTABLE_MACH_CODE          0x000 /* 0x0000 */\r
61 #define OFS_PTABLE_PART_0             0x1BE /* 446 */\r
62 #define OFS_PTABLE_PART_1             0x1CE /* 462 */\r
63 #define OFS_PTABLE_PART_2             0x1DE /* 478 */\r
64 #define OFS_PTABLE_PART_3             0x1FE /* 494 */\r
65 #define OFS_PTABLE_PART_LEN           16\r
66 \r
67 /*=========================================================================================== */\r
68 \r
69 #define OFS_BPB_jmpBoot_24           0x000 /* uchar jmpBoot[3] "0xEB 0x00 0x90" */\r
70 #define OFS_BPB_OEMName_64           0x003 /* uchar BS_OEMName[8] "MSWIN4.1" */\r
71 \r
72 #define OFS_BPB_BytsPerSec_16        0x00B /* Only 512, 1024, 2048 or 4096 */\r
73 #define OFS_BPB_SecPerClus_8         0x00D /* Only 1, 2, 4, 8, 16, 32, 64, 128 */\r
74 #define OFS_BPB_ResvdSecCnt_16       0x00E /* ulFATReservedSectors, e.g. 1 (FAT12/16) or 32 (FAT32) */\r
75 \r
76 #define OFS_BPB_NumFATs_8            0x010 /* 2 recommended */\r
77 #define OFS_BPB_RootEntCnt_16        0x011 /* ((iFAT16RootSectors * 512) / 32) 512 (FAT12/16) or 0 (FAT32) */\r
78 #define OFS_BPB_TotSec16_16          0x013 /* xxx (FAT12/16) or 0 (FAT32) */\r
79 #define OFS_BPB_Media_8              0x015 /* 0xF0 (rem media) also in FAT[0] low byte */\r
80 \r
81 #define OFS_BPB_FATSz16_16           0x016\r
82 #define OFS_BPB_SecPerTrk_16         0x018 /* n.a. CF has no tracks */\r
83 #define OFS_BPB_NumHeads_16          0x01A /* n.a. 1 ? */\r
84 #define OFS_BPB_HiddSec_32           0x01C /* n.a.      0 for nonparitioned volume */\r
85 #define OFS_BPB_TotSec32_32          0x020 /* >= 0x10000 */\r
86 \r
87 #define OFS_BPB_16_DrvNum_8          0x024 /* n.a. */\r
88 #define OFS_BPB_16_Reserved1_8       0x025 /* n.a. */\r
89 #define OFS_BPB_16_BootSig_8         0x026 /* n.a. */\r
90 #define OFS_BPB_16_BS_VolID_32       0x027 /* "unique" number */\r
91 #define OFS_BPB_16_BS_VolLab_88      0x02B /* "NO NAME    " */\r
92 #define OFS_BPB_16_FilSysType_64     0x036 /* "FAT12   " */\r
93 \r
94 #define OFS_BPB_32_FATSz32_32        0x024 /* Only when BPB_FATSz16 = 0 */\r
95 #define OFS_BPB_32_ExtFlags_16       0x028 /* FAT32 only */\r
96 #define OFS_BPB_32_FSVer_16          0x02A /* 0:0 */\r
97 #define OFS_BPB_32_RootClus_32       0x02C /* See 'iFAT32RootClusters' Normally 2 */\r
98 #define OFS_BPB_32_FSInfo_16         0x030 /* Normally 1 */\r
99 #define OFS_BPB_32_BkBootSec_16      0x032 /* Normally 6 */\r
100 #define OFS_BPB_32_Reserved_96       0x034 /* Zeros */\r
101 #define OFS_BPB_32_DrvNum_8          0x040 /* n.a. */\r
102 #define OFS_BPB_32_Reserved1_8       0x041 /* n.a. */\r
103 #define OFS_BPB_32_BootSig_8         0x042 /* n.a. */\r
104 #define OFS_BPB_32_VolID_32          0x043 /* "unique" number */\r
105 #define OFS_BPB_32_VolLab_88         0x047 /* "NO NAME    " */\r
106 #define OFS_BPB_32_FilSysType_64     0x052 /* "FAT12   " */\r
107 \r
108 #define OFS_FSI_32_LeadSig                      0x000 /* With contents 0x41615252 */\r
109 #define OFS_FSI_32_Reserved1            0x004 /* 480 times 0 */\r
110 #define OFS_FSI_32_StrucSig                     0x1E4 /* With contents 0x61417272 */\r
111 #define OFS_FSI_32_Free_Count           0x1E8 /* last known free cluster count on the volume, ~0 for unknown */\r
112 #define OFS_FSI_32_Nxt_Free                     0x1EC /* cluster number at which the driver should start looking for free clusters */\r
113 #define OFS_FSI_32_Reserved2            0x1F0 /* zero's */\r
114 #define OFS_FSI_32_TrailSig                     0x1FC /* 0xAA550000 (little endian) */\r
115 \r
116 #define RESV_COUNT                                      32\r
117 \r
118 #ifdef ffconfigMIN_CLUSTERS_FAT32\r
119         #define MIN_CLUSTER_COUNT_FAT32         ffconfigMIN_CLUSTERS_FAT32\r
120 #else\r
121         #define MIN_CLUSTER_COUNT_FAT32         ( 65525 )\r
122 #endif\r
123 \r
124 #ifdef ffconfigMIN_CLUSTERS_FAT16\r
125         #define MIN_CLUSTERS_FAT16                      ffconfigMIN_CLUSTERS_FAT16\r
126 #else\r
127         #define MIN_CLUSTERS_FAT16                      ( 4085 + 1 )\r
128 #endif\r
129 \r
130 #ifndef ffconfigFAT16_ROOT_SECTORS\r
131         #define ffconfigFAT16_ROOT_SECTORS    32\r
132 #endif\r
133 \r
134 static portINLINE uint32_t ulMin32( uint32_t a, uint32_t b )\r
135 {\r
136 uint32_t ulReturn;\r
137 \r
138         if( a <= b )\r
139         {\r
140                 ulReturn = a;\r
141         }\r
142         else\r
143         {\r
144                 ulReturn = b;\r
145         }\r
146         return ulReturn;\r
147 }\r
148 \r
149 /*_RB_ Candidate for splitting into multiple functions? */\r
150 FF_Error_t FF_Format( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber, BaseType_t xPreferFAT16, BaseType_t xSmallClusters )\r
151 {\r
152 uint32_t ulHiddenSectors;              /* Space from MBR and partition table */\r
153 const uint32_t ulFSInfo = 1;           /* Sector number of FSINFO structure within the reserved area */\r
154 const uint32_t ulBackupBootSector = 6; /* Sector number of "copy of the boot record" within the reserved area */\r
155 const BaseType_t xFATCount = 2;        /* Number of FAT's */\r
156 uint32_t ulFATReservedSectors = 0;     /* Space between the partition table and FAT table. */\r
157 int32_t iFAT16RootSectors = 0;         /* Number of sectors reserved for root directory (FAT16 only) */\r
158 int32_t iFAT32RootClusters = 0;        /* Initial amount of clusters claimed for root directory (FAT32 only) */\r
159 uint8_t ucFATType = 0;                 /* Either 'FF_T_FAT16' or 'FF_T_FAT32' */\r
160 uint32_t ulVolumeID = 0;               /* A pseudo Volume ID */\r
161 \r
162 uint32_t ulSectorsPerFAT = 0;          /* Number of sectors used by a single FAT table */\r
163 uint32_t ulClustersPerFATSector = 0;   /* # of clusters which can be described within a sector (256 or 128) */\r
164 uint32_t ulSectorsPerCluster = 0;      /* Size of a cluster (# of sectors) */\r
165 uint32_t ulUsableDataSectors = 0;      /* Usable data sectors (= SectorCount - (ulHiddenSectors + ulFATReservedSectors)) */\r
166 uint32_t ulUsableDataClusters = 0;     /* equals "ulUsableDataSectors / ulSectorsPerCluster" */\r
167 uint32_t ulNonDataSectors = 0;         /* ulFATReservedSectors + ulHiddenSectors + iFAT16RootSectors */\r
168 uint32_t ulClusterBeginLBA = 0;        /* Sector address of the first data cluster */\r
169 uint32_t ulSectorCount;\r
170 uint8_t *pucSectorBuffer = 0;\r
171 FF_SPartFound_t xPartitionsFound;\r
172 FF_Part_t *pxMyPartition = 0;\r
173 FF_IOManager_t *pxIOManager = pxDisk->pxIOManager;\r
174 \r
175         FF_PartitionSearch( pxIOManager, &xPartitionsFound );\r
176         if( xPartitionNumber >= xPartitionsFound.iCount )\r
177         {\r
178                 return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MODULE_FORMAT;\r
179         }\r
180 \r
181         pxMyPartition = xPartitionsFound.pxPartitions + xPartitionNumber;\r
182         ulSectorCount = pxMyPartition->ulSectorCount;\r
183 \r
184         ulHiddenSectors = pxMyPartition->ulStartLBA;\r
185 \r
186         if( ( ( xPreferFAT16 == pdFALSE ) && ( ( ulSectorCount - RESV_COUNT ) >= 65536 ) ) ||\r
187                 ( ( ulSectorCount - RESV_COUNT ) >= ( 64 * MIN_CLUSTER_COUNT_FAT32 ) ) )\r
188         {\r
189                 ucFATType = FF_T_FAT32;\r
190                 iFAT32RootClusters = 2;\r
191                 ulFATReservedSectors = RESV_COUNT;\r
192                 iFAT16RootSectors = 0;\r
193         }\r
194         else\r
195         {\r
196                 ucFATType = FF_T_FAT16;\r
197                 iFAT32RootClusters = 0;\r
198                 ulFATReservedSectors = 1u;\r
199                 iFAT16RootSectors = ffconfigFAT16_ROOT_SECTORS; /* 32 sectors to get 512 dir entries */\r
200         }\r
201 \r
202         /* Set start sector and length to allow FF_BlockRead/Write */\r
203         pxIOManager->xPartition.ulTotalSectors = pxMyPartition->ulSectorCount;\r
204         pxIOManager->xPartition.ulBeginLBA = pxMyPartition->ulStartLBA;\r
205 \r
206         /* TODO: Find some solution here to get a unique disk ID */\r
207         ulVolumeID = ( rand() << 16 ) | rand(); /*_RB_ rand() has proven problematic in some environments. */\r
208 \r
209         /* Sectors within partition which can not be used */\r
210         ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors;\r
211 \r
212         /* A fs dependent constant: */\r
213         if( ucFATType == FF_T_FAT32 )\r
214         {\r
215                 /* In FAT32, 4 bytes are needed to store the address (LBA) of a cluster.\r
216                 Each FAT sector of 512 bytes can contain 512 / 4 = 128 entries. */\r
217                 ulClustersPerFATSector = 128u;\r
218         }\r
219         else\r
220         {\r
221                 /* In FAT16, 2 bytes are needed to store the address (LBA) of a cluster.\r
222                 Each FAT sector of 512 bytes can contain 512 / 2 = 256 entries. */\r
223                 ulClustersPerFATSector = 256u;\r
224         }\r
225 \r
226         FF_PRINTF( "FF_Format: Secs %lu Rsvd %lu Hidden %lu Root %lu Data %lu\n",\r
227                 ulSectorCount, ulFATReservedSectors, ulHiddenSectors, iFAT16RootSectors, ulSectorCount - ulNonDataSectors );\r
228 \r
229         /* Either search from small to large or v.v. */\r
230         if( xSmallClusters != 0 )\r
231         {\r
232                 /* The caller prefers to have small clusters.\r
233                 Less waste but it can be slower. */\r
234                 ulSectorsPerCluster = 1u;\r
235         }\r
236         else\r
237         {\r
238                 if( ucFATType == FF_T_FAT32 )\r
239                 {\r
240                         ulSectorsPerCluster = 64u;\r
241                 }\r
242                 else\r
243                 {\r
244                         ulSectorsPerCluster = 32u;\r
245                 }\r
246         }\r
247 \r
248         for( ;; )\r
249         {\r
250                 int32_t groupSize;\r
251                 /* Usable sectors */\r
252                 ulUsableDataSectors = ulSectorCount - ulNonDataSectors;\r
253                 /* Each group consists of 'xFATCount' sectors + 'ulClustersPerFATSector' clusters */\r
254                 groupSize = xFATCount + ulClustersPerFATSector * ulSectorsPerCluster;\r
255                 /* This amount of groups will fit: */\r
256                 ulSectorsPerFAT = ( ulUsableDataSectors + groupSize - ulSectorsPerCluster - xFATCount ) / groupSize;\r
257 \r
258                 ulUsableDataClusters = ulMin32(\r
259                         ( uint32_t ) ( ulUsableDataSectors - xFATCount * ulSectorsPerFAT ) / ulSectorsPerCluster,\r
260                         ( uint32_t ) ( ulClustersPerFATSector * ulSectorsPerFAT ) );\r
261                 ulUsableDataSectors = ulUsableDataClusters * ulSectorsPerCluster;\r
262 \r
263                 if( ( ucFATType == FF_T_FAT16 ) && ( ulUsableDataClusters >= MIN_CLUSTERS_FAT16 ) && ( ulUsableDataClusters < 65536 ) )\r
264                 {\r
265                         break;\r
266                 }\r
267 \r
268                 if( ( ucFATType == FF_T_FAT32 ) && ( ulUsableDataClusters >= 65536 ) && ( ulUsableDataClusters < 0x0FFFFFEF ) )\r
269                 {\r
270                         break;\r
271                 }\r
272 \r
273                 /* Was this the last test? */\r
274                 if( ( ( xSmallClusters != pdFALSE ) && ( ulSectorsPerCluster == 32 ) ) ||\r
275                         ( ( xSmallClusters == pdFALSE ) && ( ulSectorsPerCluster == 1) ) )\r
276                 {\r
277                         FF_PRINTF( "FF_Format: Can not make a FAT%d (tried %d) with %lu sectors\n",\r
278                                 ucFATType == FF_T_FAT32 ? 32 : 16, xPreferFAT16 ? 16 : 32, ulSectorCount );\r
279                         return FF_ERR_IOMAN_BAD_MEMSIZE | FF_MODULE_FORMAT;\r
280                 }\r
281                 /* No it wasn't, try next clustersize */\r
282                 if( xSmallClusters != pdFALSE )\r
283                 {\r
284                         ulSectorsPerCluster <<= 1;\r
285                 }\r
286                 else\r
287                 {\r
288                         ulSectorsPerCluster >>= 1;\r
289                 }\r
290         }\r
291 \r
292         if( ( ucFATType == FF_T_FAT32 ) && ( ulSectorCount >= 0x100000UL ) )    /* Larger than 0.5 GB */\r
293         {\r
294         uint32_t ulRemaining;\r
295                 /*\r
296                  * Putting the FAT-table into the second 4MB erase block gives\r
297                  * a higher performance and a longer life-time.\r
298                  * See e.g. here:\r
299                  * http://3gfp.com/wp/2014/07/formatting-sd-cards-for-speed-and-lifetime/\r
300                  */\r
301                 ulFATReservedSectors = 8192 - ulHiddenSectors;\r
302                 ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors;\r
303 \r
304                 ulRemaining = (ulNonDataSectors + 2 * ulSectorsPerFAT) % 128;\r
305                 if( ulRemaining != 0 )\r
306                 {\r
307                         /* In order to get ClusterBeginLBA well aligned (on a 128 sector boundary) */\r
308                         ulFATReservedSectors += ( 128 - ulRemaining );\r
309                         ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors;\r
310                 }\r
311                 ulUsableDataSectors = ulSectorCount - ulNonDataSectors - 2 * ulSectorsPerFAT;\r
312                 ulUsableDataClusters = ulUsableDataSectors / ulSectorsPerCluster;\r
313         }\r
314         ulClusterBeginLBA       = ulHiddenSectors + ulFATReservedSectors + 2 * ulSectorsPerFAT;\r
315 \r
316         pucSectorBuffer = ( uint8_t * ) ffconfigMALLOC( 512 );\r
317         if( pucSectorBuffer == NULL )\r
318         {\r
319                 return FF_ERR_NOT_ENOUGH_MEMORY | FF_MODULE_FORMAT;\r
320         }\r
321 \r
322 /*  ======================================================================================= */\r
323 \r
324         memset( pucSectorBuffer, '\0', 512 );\r
325 \r
326         memcpy( pucSectorBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 );   /* Includes OFS_BPB_OEMName_64 */\r
327 \r
328         FF_putShort( pucSectorBuffer, OFS_BPB_BytsPerSec_16, 512 );   /* 0x00B / Only 512, 1024, 2048 or 4096 */\r
329         FF_putShort( pucSectorBuffer, OFS_BPB_ResvdSecCnt_16, ( uint32_t ) ulFATReservedSectors ); /*  0x00E / 1 (FAT12/16) or 32 (FAT32) */\r
330 \r
331         FF_putChar( pucSectorBuffer, OFS_BPB_NumFATs_8, 2);          /* 0x010 / 2 recommended */\r
332         FF_putShort( pucSectorBuffer, OFS_BPB_RootEntCnt_16, ( uint32_t ) ( iFAT16RootSectors * 512 ) / 32 ); /* 0x011 / 512 (FAT12/16) or 0 (FAT32) */\r
333 \r
334         /* For FAT12 and FAT16 volumes, this field contains the count of 32- */\r
335         /* byte directory entries in the root directory */\r
336 \r
337         FF_putChar( pucSectorBuffer, OFS_BPB_Media_8, 0xF8 );         /* 0x015 / 0xF0 (rem media) also in FAT[0] low byte */\r
338 \r
339         FF_putShort( pucSectorBuffer, OFS_BPB_SecPerTrk_16, 0x3F );        /* 0x18 n.a. CF has no tracks */\r
340         FF_putShort( pucSectorBuffer, OFS_BPB_NumHeads_16, 255 );         /* 0x01A / n.a. 1 ? */\r
341         FF_putLong (pucSectorBuffer, OFS_BPB_HiddSec_32, ( uint32_t ) ulHiddenSectors ); /* 0x01C / n.a.        0 for nonparitioned volume */\r
342         {\r
343                 int32_t fatBeginLBA;\r
344                 int32_t dirBegin;\r
345 \r
346                 FF_putChar( pucSectorBuffer, OFS_BPB_SecPerClus_8, ( uint32_t ) ulSectorsPerCluster ); /*  0x00D / Only 1, 2, 4, 8, 16, 32, 64, 128 */\r
347                 FF_PRINTF("FF_Format: SecCluster %lu DatSec %lu DataClus %lu ulClusterBeginLBA %lu\n",\r
348                         ulSectorsPerCluster, ulUsableDataSectors, ulUsableDataClusters, ulClusterBeginLBA );\r
349 \r
350                 /* This field is the new 32-bit total count of sectors on the volume. */\r
351                 /* This count includes the count of all sectors in all four regions of the volume */\r
352                 FF_putShort( pucSectorBuffer, OFS_BPB_TotSec16_16, 0 );        /* 0x013 / xxx (FAT12/16) or 0 (FAT32) */\r
353 \r
354                 FF_putLong (pucSectorBuffer, OFS_BPB_TotSec32_32, ulSectorCount ); /* 0x020 / >= 0x10000 */\r
355 \r
356                 if( ucFATType == FF_T_FAT32 )\r
357                 {\r
358                         FF_putLong( pucSectorBuffer,  OFS_BPB_32_FATSz32_32, ulSectorsPerFAT );      /* 0x24 / Only when BPB_FATSz16 = 0 */\r
359                         FF_putShort( pucSectorBuffer, OFS_BPB_32_ExtFlags_16, 0 );                               /* 0x28 / FAT32 only */\r
360                         FF_putShort( pucSectorBuffer, OFS_BPB_32_FSVer_16, 0 );                                  /* 0x2A / 0:0 */\r
361                         FF_putLong( pucSectorBuffer,  OFS_BPB_32_RootClus_32, ( uint32_t ) iFAT32RootClusters ); /* 0x2C / Normally 2 */\r
362                         FF_putShort( pucSectorBuffer, OFS_BPB_32_FSInfo_16, ulFSInfo );                          /* 0x30 / Normally 1 */\r
363                         FF_putShort( pucSectorBuffer, OFS_BPB_32_BkBootSec_16, ulBackupBootSector );             /* 0x32 / Normally 6 */\r
364                         FF_putChar( pucSectorBuffer,  OFS_BPB_32_DrvNum_8, 0 );                                  /* 0x40 / n.a. */\r
365                         FF_putChar( pucSectorBuffer,  OFS_BPB_32_BootSig_8, 0x29 );                              /* 0x42 / n.a. */\r
366                         FF_putLong( pucSectorBuffer,  OFS_BPB_32_VolID_32, ( uint32_t ) ulVolumeID );            /* 0x43 / "unique" number */\r
367                         memcpy( pucSectorBuffer + OFS_BPB_32_VolLab_88, "MY NAME    ", 11 );    /* 0x47 / "NO NAME    " */\r
368                         memcpy( pucSectorBuffer + OFS_BPB_32_FilSysType_64, "FAT32   ", 8 );    /* 0x52 / "FAT12   " */\r
369                 }\r
370                 else\r
371                 {\r
372                         FF_putChar( pucSectorBuffer, OFS_BPB_16_DrvNum_8, 0u );         /* 0x024 / n.a. */\r
373                         FF_putChar( pucSectorBuffer, OFS_BPB_16_Reserved1_8, 0 );      /* 0x025 / n.a. */\r
374                         FF_putChar( pucSectorBuffer, OFS_BPB_16_BootSig_8, 0x29 );     /* 0x026 / n.a. */\r
375                         FF_putLong (pucSectorBuffer, OFS_BPB_16_BS_VolID_32, ( uint32_t ) ulVolumeID ); /* 0x027 / "unique" number */\r
376 \r
377                         FF_putShort( pucSectorBuffer, OFS_BPB_FATSz16_16, ulSectorsPerFAT );            /* 0x16 */\r
378 \r
379                         memcpy( pucSectorBuffer + OFS_BPB_16_BS_VolLab_88, "MY NAME    ", 11 );            /* 0x02B / "NO NAME    " */\r
380                         memcpy( pucSectorBuffer + OFS_BPB_16_FilSysType_64, "FAT16   ", 8 );           /* 0x036 / "FAT12   " */\r
381                 }\r
382 \r
383                 pucSectorBuffer[510] = 0x55;\r
384                 pucSectorBuffer[511] = 0xAA;\r
385 \r
386                 FF_BlockWrite( pxIOManager, ulHiddenSectors, 1, pucSectorBuffer, 0u );\r
387                 if (ucFATType == FF_T_FAT32)\r
388                 {\r
389                         FF_BlockWrite( pxIOManager, ulHiddenSectors + ulBackupBootSector, 1, pucSectorBuffer, pdFALSE );\r
390                 }\r
391 \r
392                 if( ucFATType == FF_T_FAT32 )\r
393                 {\r
394                         memset( pucSectorBuffer, '\0', 512 );\r
395 \r
396                         FF_putLong( pucSectorBuffer, OFS_FSI_32_LeadSig, 0x41615252 );  /* to validate that this is in fact an FSInfo sector. */\r
397                         /* OFS_FSI_32_Reserved1         0x004 / 480 times 0 */\r
398                         FF_putLong( pucSectorBuffer, OFS_FSI_32_StrucSig, 0x61417272 ); /* Another signature that is more localized in the */\r
399                                                                                                                                          /* sector to the location of the fields that are used. */\r
400                         FF_putLong( pucSectorBuffer, OFS_FSI_32_Free_Count, ulUsableDataClusters );      /* last known free cluster count on the volume, ~0 for unknown */\r
401                         FF_putLong( pucSectorBuffer, OFS_FSI_32_Nxt_Free, 2 );          /* cluster number at which the driver should start looking for free clusters */\r
402                         /* OFS_FSI_32_Reserved2         0x1F0 / zero's */\r
403                         FF_putLong( pucSectorBuffer, OFS_FSI_32_TrailSig, 0xAA550000 ); /* Will correct for endianness */\r
404 \r
405                         FF_BlockWrite( pxIOManager, ulHiddenSectors + ulFSInfo, 1, pucSectorBuffer, pdFALSE );\r
406                         FF_BlockWrite( pxIOManager, ulHiddenSectors + ulFSInfo + ulBackupBootSector, 1, pucSectorBuffer, pdFALSE );\r
407                 }\r
408 \r
409                 fatBeginLBA = ulHiddenSectors + ulFATReservedSectors;\r
410                 memset( pucSectorBuffer, '\0', 512 );\r
411                 switch( ucFATType )\r
412                 {\r
413                         case FF_T_FAT16:\r
414                                 FF_putShort( pucSectorBuffer, 0, 0xFFF8 ); /* First FAT entry. */\r
415                                 FF_putShort( pucSectorBuffer, 2, 0xFFFF ); /* RESERVED alloc. */\r
416                                 break;\r
417                         case FF_T_FAT32:\r
418                                 FF_putLong( pucSectorBuffer, 0, 0x0FFFFFF8 ); /* FAT32 FAT sig. */\r
419                                 FF_putLong( pucSectorBuffer, 4, 0xFFFFFFFF ); /* RESERVED alloc. */\r
420                                 FF_putLong( pucSectorBuffer, 8, 0x0FFFFFFF ); /* Root dir allocation. */\r
421                                 break;\r
422                         default:\r
423                                 break;\r
424                 }\r
425 \r
426                 FF_BlockWrite( pxIOManager, ( uint32_t ) fatBeginLBA, 1, pucSectorBuffer, pdFALSE );\r
427                 FF_BlockWrite( pxIOManager, ( uint32_t ) fatBeginLBA + ulSectorsPerFAT, 1, pucSectorBuffer, pdFALSE );\r
428 \r
429                 FF_PRINTF( "FF_Format: Clearing entire FAT (2 x %lu sectors):\n", ulSectorsPerFAT );\r
430                 {\r
431                 int32_t addr;\r
432 \r
433                         memset( pucSectorBuffer, '\0', 512 );\r
434                         for( addr = fatBeginLBA+1;\r
435                                  addr < ( fatBeginLBA + ( int32_t ) ulSectorsPerFAT );\r
436                                  addr++ )\r
437                         {\r
438                                 FF_BlockWrite( pxIOManager, ( uint32_t ) addr, 1, pucSectorBuffer, pdFALSE );\r
439                                 FF_BlockWrite( pxIOManager, ( uint32_t ) addr + ulSectorsPerFAT, 1, pucSectorBuffer, pdFALSE );\r
440                         }\r
441                 }\r
442                 FF_PRINTF( "FF_Format: Clearing done\n" );\r
443                 dirBegin = fatBeginLBA + ( 2 * ulSectorsPerFAT );\r
444 #if( ffconfigTIME_SUPPORT != 0 )\r
445                 {\r
446                         FF_SystemTime_t str_t;\r
447                         int16_t myShort;\r
448 \r
449                         FF_GetSystemTime( &str_t );\r
450 \r
451                         myShort = ( ( str_t.Hour << 11 ) & 0xF800 ) |\r
452                                                                 ( ( str_t.Minute  <<  5 ) & 0x07E0 ) |\r
453                                                                 ( ( str_t.Second   /  2 ) & 0x001F );\r
454                         FF_putShort( pucSectorBuffer, 22, ( uint32_t ) myShort );\r
455 \r
456                         myShort = ( ( ( str_t.Year- 1980 )  <<  9 ) & 0xFE00 ) |\r
457                                            ( ( str_t.Month << 5 ) & 0x01E0 ) |\r
458                                            ( str_t.Day & 0x001F );\r
459                         FF_putShort( pucSectorBuffer, 24, ( uint32_t ) myShort);\r
460                 }\r
461 #endif  /* ffconfigTIME_SUPPORT */\r
462 \r
463                 memcpy (pucSectorBuffer, "MY_DISK    ", 11);\r
464                 pucSectorBuffer[11] = FF_FAT_ATTR_VOLID;\r
465 \r
466                 {\r
467                 int32_t lAddress;\r
468                 int32_t lLastAddress;\r
469 \r
470                         if( iFAT16RootSectors != 0 )\r
471                         {\r
472                                 lLastAddress = dirBegin + iFAT16RootSectors;\r
473                         }\r
474                         else\r
475                         {\r
476                                 lLastAddress = dirBegin + ulSectorsPerCluster;\r
477                         }\r
478 \r
479                         FF_PRINTF("FF_Format: Clearing root directory at %08lX: %lu sectors\n", dirBegin, lLastAddress - dirBegin );\r
480                         for( lAddress = dirBegin; lAddress < lLastAddress; lAddress++ )\r
481                         {\r
482                                 FF_BlockWrite( pxIOManager, ( uint32_t ) lAddress, 1, pucSectorBuffer, 0u );\r
483                                 if( lAddress == dirBegin )\r
484                                 {\r
485                                         memset( pucSectorBuffer, '\0', 512 );\r
486                                 }\r
487                         }\r
488                 }\r
489         }\r
490 \r
491         ffconfigFREE( pucSectorBuffer );\r
492 \r
493         return FF_ERR_NONE;\r
494 }\r
495 \r
496 FF_Error_t FF_Partition( FF_Disk_t *pxDisk, FF_PartitionParameters_t *pParams )\r
497 {\r
498         const uint32_t ulInterSpace = pParams->ulInterSpace ? pParams->ulInterSpace : 2048;  /* Hidden space between 2 extended partitions */\r
499         BaseType_t xPartitionNumber;\r
500         FF_Part_t pxPartitions[ ffconfigMAX_PARTITIONS ];\r
501         uint32_t ulPartitionOffset; /* Pointer within partition table */\r
502         FF_Buffer_t *pxSectorBuffer;\r
503         uint8_t *pucBuffer;\r
504         uint32_t ulSummedSizes = 0;     /* Summed sizes as a percentage or as number of sectors. */\r
505         BaseType_t xPartitionCount = 0;\r
506         BaseType_t xNeedExtended;\r
507         uint32_t ulReservedSpace;\r
508         uint32_t ulAvailable;\r
509         FF_IOManager_t *pxIOManager = pxDisk->pxIOManager;\r
510 \r
511 \r
512         /* Clear caching without flushing first. */\r
513         FF_IOMAN_InitBufferDescriptors( pxIOManager );\r
514 \r
515         /* Avoid sanity checks by FF_BlockRead/Write. */\r
516         pxIOManager->xPartition.ulTotalSectors = 0;\r
517 \r
518         /* Get the sum of sizes and number of actual partitions. */\r
519         for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ )\r
520         {\r
521                 if( pParams->xSizes[ xPartitionNumber ] > 0 )\r
522                 {\r
523                         xPartitionCount++;\r
524                         ulSummedSizes += pParams->xSizes[ xPartitionNumber ];\r
525                 }\r
526         }\r
527 \r
528         if( xPartitionCount == 0 )\r
529         {\r
530                 xPartitionCount = 1;\r
531                 if( pParams->eSizeType == eSizeIsSectors)\r
532                 {\r
533                         pParams->xSizes[ 0 ] = pParams->ulSectorCount;\r
534                 }\r
535                 else\r
536                 {\r
537                         pParams->xSizes[ 0 ] = 100;\r
538                 }\r
539 \r
540                 ulSummedSizes = pParams->xSizes[ 0 ];\r
541         }\r
542 \r
543         /* Correct PrimaryCount if necessary. */\r
544         if( pParams->xPrimaryCount > ( ( xPartitionCount > 4 ) ? 3 : xPartitionCount ) )\r
545         {\r
546                 pParams->xPrimaryCount = ( xPartitionCount > 4 ) ? 3 : xPartitionCount;\r
547         }\r
548 \r
549         /* Now see if extended is necessary. */\r
550         xNeedExtended = ( xPartitionCount > pParams->xPrimaryCount );\r
551 \r
552         if( xNeedExtended != pdFALSE )\r
553         {\r
554                 if( pParams->ulHiddenSectors < 4096 )\r
555                 {\r
556                         pParams->ulHiddenSectors = 4096;\r
557                 }\r
558 \r
559                 ulReservedSpace = ulInterSpace * ( xPartitionCount - pParams->xPrimaryCount );\r
560         }\r
561         else\r
562         {\r
563                 /* There must be at least 1 hidden sector. */\r
564                 if( pParams->ulHiddenSectors < 1 )\r
565                 {\r
566                         pParams->ulHiddenSectors = 1;\r
567                 }\r
568                 ulReservedSpace = 0;\r
569         }\r
570 \r
571         ulAvailable = pParams->ulSectorCount - pParams->ulHiddenSectors - ulReservedSpace;\r
572 \r
573         /* Check validity of Sizes */\r
574         switch( pParams->eSizeType )\r
575         {\r
576                 case eSizeIsQuota:       /* Assign a quotum (sum of Sizes is free, all disk space will be allocated) */\r
577                         break;\r
578                 case eSizeIsPercent:  /* Assign a percentage of the available space (sum of Sizes must be <= 100) */\r
579                         if( ulSummedSizes > 100 )\r
580                         {\r
581                                 return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE;\r
582                         }\r
583                         ulSummedSizes = 100;\r
584                         break;\r
585                 case eSizeIsSectors:     /* Assign fixed number of sectors (512 byte each) */\r
586                         if( ulSummedSizes > ulAvailable )\r
587                         {\r
588                                 return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE;\r
589                         }\r
590                         break;\r
591         }\r
592 \r
593         {\r
594         uint32_t ulRemaining = ulAvailable;\r
595         uint32_t ulLBA = pParams->ulHiddenSectors;\r
596 \r
597                 /* Divide the available sectors among the partitions: */\r
598                 memset( pxPartitions, '\0', sizeof( pxPartitions ) );\r
599 \r
600                 for( xPartitionNumber = 0; xPartitionNumber < xPartitionCount; xPartitionNumber++ )\r
601                 {\r
602                         if( pParams->xSizes[ xPartitionNumber ] > 0 )\r
603                         {\r
604                                 uint32_t ulSize;\r
605                                 switch( pParams->eSizeType )\r
606                                 {\r
607                                         case eSizeIsQuota:       /* Assign a quotum (sum of Sizes is free, all disk space will be allocated) */\r
608                                         case eSizeIsPercent:  /* Assign a percentage of the available space (sum of Sizes must be <= 100) */\r
609                                                 ulSize = ( uint32_t ) ( ( ( uint64_t ) pParams->xSizes[ xPartitionNumber ] * ulAvailable) / ulSummedSizes );\r
610                                                 break;\r
611                                         case eSizeIsSectors:     /* Assign fixed number of sectors (512 byte each) */\r
612                                         default:                  /* Just for the compiler(s) */\r
613                                                 ulSize = pParams->xSizes[ xPartitionNumber ];\r
614                                                 break;\r
615                                 }\r
616 \r
617                                 if( ulSize > ulRemaining )\r
618                                 {\r
619                                         ulSize = ulRemaining;\r
620                                 }\r
621 \r
622                                 ulRemaining -= ulSize;\r
623                                 pxPartitions[ xPartitionNumber ].ulSectorCount = ulSize;\r
624                                 pxPartitions[ xPartitionNumber ].ucActive = 0x80;\r
625                                 pxPartitions[ xPartitionNumber ].ulStartLBA = ulLBA; /* ulStartLBA might still change for logical partitions */\r
626                                 pxPartitions[ xPartitionNumber ].ucPartitionID = 0x0B;\r
627                                 ulLBA += ulSize;\r
628                         }\r
629                 }\r
630         }\r
631 \r
632         if( xNeedExtended != pdFALSE )\r
633         {\r
634                 /* Create at least 1 extended/logical partition */\r
635                 int index;\r
636                 /* Start of the big extended partition */\r
637                 unsigned extendedLBA = pParams->ulHiddenSectors;\r
638                 /* Where to write the table */\r
639                 uint32_t ulLBA = 0;\r
640                 /* Contents of the table */\r
641                 FF_Part_t writeParts[4];\r
642 \r
643                 for( index = -1; index < xPartitionCount; index++ )\r
644                 {\r
645                 uint32_t ulNextLBA;\r
646 \r
647                         memset (writeParts, '\0', sizeof( writeParts ) );\r
648                         if( index < 0 )\r
649                         {\r
650                         /* we're at secor 0: */\r
651                         /* write primary partitions, if any */\r
652                         /* create big extended partition */\r
653                         uint32_t ulStartLBA = pParams->ulHiddenSectors;\r
654                                 for( xPartitionNumber = 0; xPartitionNumber < pParams->xPrimaryCount; xPartitionNumber++ )\r
655                                 {\r
656                                         writeParts[ xPartitionNumber ].ulStartLBA = ulStartLBA;\r
657                                         writeParts[ xPartitionNumber ].ulSectorCount = pxPartitions[ xPartitionNumber ].ulSectorCount;\r
658                                         writeParts[ xPartitionNumber ].ucActive = 0x80;\r
659                                         writeParts[ xPartitionNumber ].ucPartitionID = 0x0B;\r
660                                         ulStartLBA += writeParts[ xPartitionNumber ].ulSectorCount;\r
661                                         index++;\r
662                                 }\r
663                                 extendedLBA = ulStartLBA;\r
664                                 writeParts[ xPartitionNumber ].ulStartLBA = ulStartLBA;\r
665                                 writeParts[ xPartitionNumber ].ulSectorCount = pParams->ulSectorCount - ulStartLBA;\r
666                                 writeParts[ xPartitionNumber ].ucActive = 0x80;\r
667                                 writeParts[ xPartitionNumber ].ucPartitionID = 0x05;\r
668                                 ulNextLBA = ulStartLBA;\r
669                         }\r
670                         else\r
671                         {\r
672                                 /* Create a logical partition with "ulSectorCount" sectors: */\r
673                                 writeParts[ 0 ].ulStartLBA = ulInterSpace;\r
674                                 writeParts[ 0 ].ulSectorCount = pxPartitions[index].ulSectorCount;\r
675                                 writeParts[ 0 ].ucActive = 0x80;\r
676                                 writeParts[ 0 ].ucPartitionID = 0x0B;\r
677                                 if( index < xPartitionCount - 1 )\r
678                                 {\r
679                                         /* Next extended partition */\r
680                                         writeParts[ 1 ].ulStartLBA = ulInterSpace + ulLBA - extendedLBA + writeParts[ 0 ].ulSectorCount;\r
681                                         writeParts[ 1 ].ulSectorCount = pxPartitions[index+1].ulSectorCount + ulInterSpace;\r
682                                         writeParts[ 1 ].ucActive = 0x80;\r
683                                         writeParts[ 1 ].ucPartitionID = 0x05;\r
684                                 }\r
685                                 ulNextLBA = writeParts[ 1 ].ulStartLBA + extendedLBA;\r
686                         }\r
687                         pxSectorBuffer = FF_GetBuffer(pxIOManager, ( uint32_t ) ulLBA, ( uint8_t ) FF_MODE_WRITE );\r
688                         {\r
689                                 if( pxSectorBuffer == NULL )\r
690                                 {\r
691                                         return FF_ERR_DEVICE_DRIVER_FAILED;\r
692                                 }\r
693                         }\r
694                         pucBuffer = pxSectorBuffer->pucBuffer;\r
695                         memset ( pucBuffer, 0, 512 );\r
696                         memcpy ( pucBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 );   /* Includes OFS_BPB_OEMName_64 */\r
697 \r
698                         ulPartitionOffset = OFS_PTABLE_PART_0;\r
699                         for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++, ulPartitionOffset += 16 )\r
700                         {\r
701                                 FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ACTIVE_8,            writeParts[ xPartitionNumber ].ucActive );             /* 0x01BE 0x80 if active */\r
702                                 FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_START_HEAD_8,        1 );                                                                                   /* 0x001 / 0x01BF */\r
703                                 FF_putShort(pucBuffer, ulPartitionOffset + OFS_PART_START_SEC_TRACK_16,  1 );                                                                                   /* 0x002 / 0x01C0 */\r
704                                 FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ID_NUMBER_8,         writeParts[ xPartitionNumber ].ucPartitionID );/* 0x004 / 0x01C2 */\r
705                                 FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_HEAD_8,       0xFE );                                                                                /* 0x005 / 0x01C3 */\r
706                                 FF_putShort(pucBuffer, ulPartitionOffset + OFS_PART_ENDING_SEC_TRACK_16, writeParts[ xPartitionNumber ].ulSectorCount );/* 0x006 / 0x01C4 */\r
707                                 FF_putLong (pucBuffer, ulPartitionOffset + OFS_PART_STARTING_LBA_32,     writeParts[ xPartitionNumber ].ulStartLBA );   /* 0x008 / 0x01C6 This is important */\r
708                                 FF_putLong (pucBuffer, ulPartitionOffset + OFS_PART_LENGTH_32,           writeParts[ xPartitionNumber ].ulSectorCount );/* 0x00C / 0x01CA Equal to total sectors */\r
709                         }\r
710                         pucBuffer[510] = 0x55;\r
711                         pucBuffer[511] = 0xAA;\r
712 \r
713                         FF_ReleaseBuffer(pxIOManager, pxSectorBuffer );\r
714                         FF_FlushCache( pxIOManager );\r
715                         ulLBA = ulNextLBA;\r
716                 }\r
717         }\r
718         else\r
719         {\r
720                 pxSectorBuffer = FF_GetBuffer( pxIOManager, 0, ( uint8_t ) FF_MODE_WRITE );\r
721                 {\r
722                         if( pxSectorBuffer == NULL )\r
723                         {\r
724                                 return FF_ERR_DEVICE_DRIVER_FAILED;\r
725                         }\r
726                 }\r
727 \r
728                 pucBuffer = pxSectorBuffer->pucBuffer;\r
729                 memset (pucBuffer, 0, 512 );\r
730                 memcpy (pucBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 );   /* Includes OFS_BPB_OEMName_64 */\r
731                 ulPartitionOffset = OFS_PTABLE_PART_0;\r
732 \r
733                 for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ )\r
734                 {\r
735                         FF_putChar(  pucBuffer, ulPartitionOffset + OFS_PART_ACTIVE_8,            pxPartitions[ xPartitionNumber ].ucActive );          /* 0x01BE 0x80 if active */\r
736                         FF_putChar(  pucBuffer, ulPartitionOffset + OFS_PART_START_HEAD_8,        1 );                                                                                  /* 0x001 / 0x01BF */\r
737                         FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_START_SEC_TRACK_16,  1 );                                                                                          /* 0x002 / 0x01C0 */\r
738                         FF_putChar(  pucBuffer, ulPartitionOffset + OFS_PART_ID_NUMBER_8,         pxPartitions[ xPartitionNumber ].ucPartitionID );     /* 0x004 / 0x01C2 */\r
739                         FF_putChar(  pucBuffer, ulPartitionOffset + OFS_PART_ENDING_HEAD_8,       0xFE );                                                                               /* 0x005 / 0x01C3 */\r
740                         FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_SEC_TRACK_16, pxPartitions[ xPartitionNumber ].ulSectorCount );     /* 0x006 / 0x01C4 */\r
741                         FF_putLong(  pucBuffer, ulPartitionOffset + OFS_PART_STARTING_LBA_32,     pxPartitions[ xPartitionNumber ].ulStartLBA );        /* 0x008 / 0x01C6 This is important */\r
742                         FF_putLong(  pucBuffer, ulPartitionOffset + OFS_PART_LENGTH_32,           pxPartitions[ xPartitionNumber ].ulSectorCount );     /* 0x00C / 0x01CA Equal to total sectors */\r
743                         ulPartitionOffset += 16;\r
744                 }\r
745                 pucBuffer[ 510 ] = 0x55;\r
746                 pucBuffer[ 511 ] = 0xAA;\r
747 \r
748                 FF_ReleaseBuffer( pxIOManager, pxSectorBuffer );\r
749                 FF_FlushCache( pxIOManager );\r
750         }\r
751 \r
752         return FF_ERR_NONE;\r
753 }\r