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
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
13 * The above copyright notice and this permission notice shall be included in all
\r
14 * copies or substantial portions of the Software.
\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
23 * https://www.FreeRTOS.org
\r
31 * @defgroup FAT Fat File-System
\r
32 * @brief Format a drive, given the number of sectors.
\r
36 #include "ff_headers.h"
\r
41 #if defined( __BORLANDC__ )
\r
42 #include "ff_windows.h"
\r
44 #include "FreeRTOS.h"
\r
45 #include "task.h" /* For FreeRTOS date/time function */
\r
49 /*=========================================================================================== */
\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
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
67 /*=========================================================================================== */
\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
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
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
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
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
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
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
116 #define RESV_COUNT 32
\r
118 #ifdef ffconfigMIN_CLUSTERS_FAT32
\r
119 #define MIN_CLUSTER_COUNT_FAT32 ffconfigMIN_CLUSTERS_FAT32
\r
121 #define MIN_CLUSTER_COUNT_FAT32 ( 65525 )
\r
124 #ifdef ffconfigMIN_CLUSTERS_FAT16
\r
125 #define MIN_CLUSTERS_FAT16 ffconfigMIN_CLUSTERS_FAT16
\r
127 #define MIN_CLUSTERS_FAT16 ( 4085 + 1 )
\r
130 #ifndef ffconfigFAT16_ROOT_SECTORS
\r
131 #define ffconfigFAT16_ROOT_SECTORS 32
\r
134 static portINLINE uint32_t ulMin32( uint32_t a, uint32_t b )
\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
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
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
175 FF_PartitionSearch( pxIOManager, &xPartitionsFound );
\r
176 if( xPartitionNumber >= xPartitionsFound.iCount )
\r
178 return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MODULE_FORMAT;
\r
181 pxMyPartition = xPartitionsFound.pxPartitions + xPartitionNumber;
\r
182 ulSectorCount = pxMyPartition->ulSectorCount;
\r
184 ulHiddenSectors = pxMyPartition->ulStartLBA;
\r
186 if( ( ( xPreferFAT16 == pdFALSE ) && ( ( ulSectorCount - RESV_COUNT ) >= 65536 ) ) ||
\r
187 ( ( ulSectorCount - RESV_COUNT ) >= ( 64 * MIN_CLUSTER_COUNT_FAT32 ) ) )
\r
189 ucFATType = FF_T_FAT32;
\r
190 iFAT32RootClusters = 2;
\r
191 ulFATReservedSectors = RESV_COUNT;
\r
192 iFAT16RootSectors = 0;
\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
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
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
209 /* Sectors within partition which can not be used */
\r
210 ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors;
\r
212 /* A fs dependent constant: */
\r
213 if( ucFATType == FF_T_FAT32 )
\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
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
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
229 /* Either search from small to large or v.v. */
\r
230 if( xSmallClusters != 0 )
\r
232 /* The caller prefers to have small clusters.
\r
233 Less waste but it can be slower. */
\r
234 ulSectorsPerCluster = 1u;
\r
238 if( ucFATType == FF_T_FAT32 )
\r
240 ulSectorsPerCluster = 64u;
\r
244 ulSectorsPerCluster = 32u;
\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
258 ulUsableDataClusters = ulMin32(
\r
259 ( uint32_t ) ( ulUsableDataSectors - xFATCount * ulSectorsPerFAT ) / ulSectorsPerCluster,
\r
260 ( uint32_t ) ( ulClustersPerFATSector * ulSectorsPerFAT ) );
\r
261 ulUsableDataSectors = ulUsableDataClusters * ulSectorsPerCluster;
\r
263 if( ( ucFATType == FF_T_FAT16 ) && ( ulUsableDataClusters >= MIN_CLUSTERS_FAT16 ) && ( ulUsableDataClusters < 65536 ) )
\r
268 if( ( ucFATType == FF_T_FAT32 ) && ( ulUsableDataClusters >= 65536 ) && ( ulUsableDataClusters < 0x0FFFFFEF ) )
\r
273 /* Was this the last test? */
\r
274 if( ( ( xSmallClusters != pdFALSE ) && ( ulSectorsPerCluster == 32 ) ) ||
\r
275 ( ( xSmallClusters == pdFALSE ) && ( ulSectorsPerCluster == 1) ) )
\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
281 /* No it wasn't, try next clustersize */
\r
282 if( xSmallClusters != pdFALSE )
\r
284 ulSectorsPerCluster <<= 1;
\r
288 ulSectorsPerCluster >>= 1;
\r
292 if( ( ucFATType == FF_T_FAT32 ) && ( ulSectorCount >= 0x100000UL ) ) /* Larger than 0.5 GB */
\r
294 uint32_t ulRemaining;
\r
296 * Putting the FAT-table into the second 4MB erase block gives
\r
297 * a higher performance and a longer life-time.
\r
299 * http://3gfp.com/wp/2014/07/formatting-sd-cards-for-speed-and-lifetime/
\r
301 ulFATReservedSectors = 8192 - ulHiddenSectors;
\r
302 ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors;
\r
304 ulRemaining = (ulNonDataSectors + 2 * ulSectorsPerFAT) % 128;
\r
305 if( ulRemaining != 0 )
\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
311 ulUsableDataSectors = ulSectorCount - ulNonDataSectors - 2 * ulSectorsPerFAT;
\r
312 ulUsableDataClusters = ulUsableDataSectors / ulSectorsPerCluster;
\r
314 ulClusterBeginLBA = ulHiddenSectors + ulFATReservedSectors + 2 * ulSectorsPerFAT;
\r
316 pucSectorBuffer = ( uint8_t * ) ffconfigMALLOC( 512 );
\r
317 if( pucSectorBuffer == NULL )
\r
319 return FF_ERR_NOT_ENOUGH_MEMORY | FF_MODULE_FORMAT;
\r
322 /* ======================================================================================= */
\r
324 memset( pucSectorBuffer, '\0', 512 );
\r
326 memcpy( pucSectorBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 ); /* Includes OFS_BPB_OEMName_64 */
\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
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
334 /* For FAT12 and FAT16 volumes, this field contains the count of 32- */
\r
335 /* byte directory entries in the root directory */
\r
337 FF_putChar( pucSectorBuffer, OFS_BPB_Media_8, 0xF8 ); /* 0x015 / 0xF0 (rem media) also in FAT[0] low byte */
\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
343 int32_t fatBeginLBA;
\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
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
354 FF_putLong (pucSectorBuffer, OFS_BPB_TotSec32_32, ulSectorCount ); /* 0x020 / >= 0x10000 */
\r
356 if( ucFATType == FF_T_FAT32 )
\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
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
377 FF_putShort( pucSectorBuffer, OFS_BPB_FATSz16_16, ulSectorsPerFAT ); /* 0x16 */
\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
383 pucSectorBuffer[510] = 0x55;
\r
384 pucSectorBuffer[511] = 0xAA;
\r
386 FF_BlockWrite( pxIOManager, ulHiddenSectors, 1, pucSectorBuffer, 0u );
\r
387 if (ucFATType == FF_T_FAT32)
\r
389 FF_BlockWrite( pxIOManager, ulHiddenSectors + ulBackupBootSector, 1, pucSectorBuffer, pdFALSE );
\r
392 if( ucFATType == FF_T_FAT32 )
\r
394 memset( pucSectorBuffer, '\0', 512 );
\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
405 FF_BlockWrite( pxIOManager, ulHiddenSectors + ulFSInfo, 1, pucSectorBuffer, pdFALSE );
\r
406 FF_BlockWrite( pxIOManager, ulHiddenSectors + ulFSInfo + ulBackupBootSector, 1, pucSectorBuffer, pdFALSE );
\r
409 fatBeginLBA = ulHiddenSectors + ulFATReservedSectors;
\r
410 memset( pucSectorBuffer, '\0', 512 );
\r
411 switch( ucFATType )
\r
414 FF_putShort( pucSectorBuffer, 0, 0xFFF8 ); /* First FAT entry. */
\r
415 FF_putShort( pucSectorBuffer, 2, 0xFFFF ); /* RESERVED alloc. */
\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
426 FF_BlockWrite( pxIOManager, ( uint32_t ) fatBeginLBA, 1, pucSectorBuffer, pdFALSE );
\r
427 FF_BlockWrite( pxIOManager, ( uint32_t ) fatBeginLBA + ulSectorsPerFAT, 1, pucSectorBuffer, pdFALSE );
\r
429 FF_PRINTF( "FF_Format: Clearing entire FAT (2 x %lu sectors):\n", ulSectorsPerFAT );
\r
433 memset( pucSectorBuffer, '\0', 512 );
\r
434 for( addr = fatBeginLBA+1;
\r
435 addr < ( fatBeginLBA + ( int32_t ) ulSectorsPerFAT );
\r
438 FF_BlockWrite( pxIOManager, ( uint32_t ) addr, 1, pucSectorBuffer, pdFALSE );
\r
439 FF_BlockWrite( pxIOManager, ( uint32_t ) addr + ulSectorsPerFAT, 1, pucSectorBuffer, pdFALSE );
\r
442 FF_PRINTF( "FF_Format: Clearing done\n" );
\r
443 dirBegin = fatBeginLBA + ( 2 * ulSectorsPerFAT );
\r
444 #if( ffconfigTIME_SUPPORT != 0 )
\r
446 FF_SystemTime_t str_t;
\r
449 FF_GetSystemTime( &str_t );
\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
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
461 #endif /* ffconfigTIME_SUPPORT */
\r
463 memcpy (pucSectorBuffer, "MY_DISK ", 11);
\r
464 pucSectorBuffer[11] = FF_FAT_ATTR_VOLID;
\r
468 int32_t lLastAddress;
\r
470 if( iFAT16RootSectors != 0 )
\r
472 lLastAddress = dirBegin + iFAT16RootSectors;
\r
476 lLastAddress = dirBegin + ulSectorsPerCluster;
\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
482 FF_BlockWrite( pxIOManager, ( uint32_t ) lAddress, 1, pucSectorBuffer, 0u );
\r
483 if( lAddress == dirBegin )
\r
485 memset( pucSectorBuffer, '\0', 512 );
\r
491 ffconfigFREE( pucSectorBuffer );
\r
493 return FF_ERR_NONE;
\r
496 FF_Error_t FF_Partition( FF_Disk_t *pxDisk, FF_PartitionParameters_t *pParams )
\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
512 /* Clear caching without flushing first. */
\r
513 FF_IOMAN_InitBufferDescriptors( pxIOManager );
\r
515 /* Avoid sanity checks by FF_BlockRead/Write. */
\r
516 pxIOManager->xPartition.ulTotalSectors = 0;
\r
518 /* Get the sum of sizes and number of actual partitions. */
\r
519 for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ )
\r
521 if( pParams->xSizes[ xPartitionNumber ] > 0 )
\r
524 ulSummedSizes += pParams->xSizes[ xPartitionNumber ];
\r
528 if( xPartitionCount == 0 )
\r
530 xPartitionCount = 1;
\r
531 if( pParams->eSizeType == eSizeIsSectors)
\r
533 pParams->xSizes[ 0 ] = pParams->ulSectorCount;
\r
537 pParams->xSizes[ 0 ] = 100;
\r
540 ulSummedSizes = pParams->xSizes[ 0 ];
\r
543 /* Correct PrimaryCount if necessary. */
\r
544 if( pParams->xPrimaryCount > ( ( xPartitionCount > 4 ) ? 3 : xPartitionCount ) )
\r
546 pParams->xPrimaryCount = ( xPartitionCount > 4 ) ? 3 : xPartitionCount;
\r
549 /* Now see if extended is necessary. */
\r
550 xNeedExtended = ( xPartitionCount > pParams->xPrimaryCount );
\r
552 if( xNeedExtended != pdFALSE )
\r
554 if( pParams->ulHiddenSectors < 4096 )
\r
556 pParams->ulHiddenSectors = 4096;
\r
559 ulReservedSpace = ulInterSpace * ( xPartitionCount - pParams->xPrimaryCount );
\r
563 /* There must be at least 1 hidden sector. */
\r
564 if( pParams->ulHiddenSectors < 1 )
\r
566 pParams->ulHiddenSectors = 1;
\r
568 ulReservedSpace = 0;
\r
571 ulAvailable = pParams->ulSectorCount - pParams->ulHiddenSectors - ulReservedSpace;
\r
573 /* Check validity of Sizes */
\r
574 switch( pParams->eSizeType )
\r
576 case eSizeIsQuota: /* Assign a quotum (sum of Sizes is free, all disk space will be allocated) */
\r
578 case eSizeIsPercent: /* Assign a percentage of the available space (sum of Sizes must be <= 100) */
\r
579 if( ulSummedSizes > 100 )
\r
581 return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE;
\r
583 ulSummedSizes = 100;
\r
585 case eSizeIsSectors: /* Assign fixed number of sectors (512 byte each) */
\r
586 if( ulSummedSizes > ulAvailable )
\r
588 return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE;
\r
594 uint32_t ulRemaining = ulAvailable;
\r
595 uint32_t ulLBA = pParams->ulHiddenSectors;
\r
597 /* Divide the available sectors among the partitions: */
\r
598 memset( pxPartitions, '\0', sizeof( pxPartitions ) );
\r
600 for( xPartitionNumber = 0; xPartitionNumber < xPartitionCount; xPartitionNumber++ )
\r
602 if( pParams->xSizes[ xPartitionNumber ] > 0 )
\r
605 switch( pParams->eSizeType )
\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
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
617 if( ulSize > ulRemaining )
\r
619 ulSize = ulRemaining;
\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
632 if( xNeedExtended != pdFALSE )
\r
634 /* Create at least 1 extended/logical partition */
\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
643 for( index = -1; index < xPartitionCount; index++ )
\r
645 uint32_t ulNextLBA;
\r
647 memset (writeParts, '\0', sizeof( writeParts ) );
\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
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
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
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
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
685 ulNextLBA = writeParts[ 1 ].ulStartLBA + extendedLBA;
\r
687 pxSectorBuffer = FF_GetBuffer(pxIOManager, ( uint32_t ) ulLBA, ( uint8_t ) FF_MODE_WRITE );
\r
689 if( pxSectorBuffer == NULL )
\r
691 return FF_ERR_DEVICE_DRIVER_FAILED;
\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
698 ulPartitionOffset = OFS_PTABLE_PART_0;
\r
699 for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++, ulPartitionOffset += 16 )
\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
710 pucBuffer[510] = 0x55;
\r
711 pucBuffer[511] = 0xAA;
\r
713 FF_ReleaseBuffer(pxIOManager, pxSectorBuffer );
\r
714 FF_FlushCache( pxIOManager );
\r
720 pxSectorBuffer = FF_GetBuffer( pxIOManager, 0, ( uint8_t ) FF_MODE_WRITE );
\r
722 if( pxSectorBuffer == NULL )
\r
724 return FF_ERR_DEVICE_DRIVER_FAILED;
\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
733 for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ )
\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
745 pucBuffer[ 510 ] = 0x55;
\r
746 pucBuffer[ 511 ] = 0xAA;
\r
748 FF_ReleaseBuffer( pxIOManager, pxSectorBuffer );
\r
749 FF_FlushCache( pxIOManager );
\r
752 return FF_ERR_NONE;
\r