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 IOMAN I/O Manager
\r
32 * @brief Handles IO buffers for FreeRTOS+FAT safely.
\r
34 * Provides a simple static interface to the rest of FreeRTOS+FAT to manage
\r
35 * buffers. It also defines the public interfaces for Creating and
\r
36 * Destroying a FreeRTOS+FAT IO object.
\r
42 #include "ff_headers.h"
\r
44 #define FAT16_SECTOR_COUNT_4085 4085
\r
45 #define FAT32_SECTOR_COUNT_65525 65525 /* 65536 clusters */
\r
47 /* Some values and offsets describing the special sector FS INFO: */
\r
48 #define FS_INFO_SIGNATURE1_0x41615252 0x41615252UL
\r
49 #define FS_INFO_SIGNATURE2_0x61417272 0x61417272UL
\r
50 #define FS_INFO_OFFSET_SIGNATURE1_000 0
\r
51 #define FS_INFO_OFFSET_SIGNATURE2_484 484
\r
52 #define FS_INFO_OFFSET_FREE_COUNT_488 488
\r
53 #define FS_INFO_OFFSET_FREE_CLUSTER_492 492
\r
55 /* Inspect the PBR (Partition Boot Record) to determine the type of FAT */
\r
56 static FF_Error_t prvDetermineFatType( FF_IOManager_t *pxIOManager );
\r
58 /* Check if a given ID introduces an extended partition. */
\r
59 static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID );
\r
61 /* Return pdTRUE if the media byte in an MBR is valid. */
\r
62 static BaseType_t prvIsValidMedia( uint8_t media );
\r
64 /* Read the MBR to see what extended partitions have been defined.
\r
65 Definitions of extended partitions may be chained.
\r
66 Walk down the chain to find all extended partitions. */
\r
67 static FF_Error_t FF_ParseExtended( FF_IOManager_t *pxIOManager, uint32_t ulFirstSector, uint32_t ulFirstSize,
\r
68 FF_SPartFound_t *pPartsFound );
\r
70 static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t *pxIOManager, uint32_t ulPartitionNumber );
\r
72 static BaseType_t prvHasActiveHandles( FF_IOManager_t *pxIOManager );
\r
77 * @brief Creates an FF_IOManager_t object, to initialise FreeRTOS+FAT
\r
79 * @param pucCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc).
\r
80 * @param ulCacheSize The size of the provided buffer, or size of the cache to be created.
\r
81 * (Must be at least 2 * ulSectorSize). Always a multiple of ulSectorSize.
\r
82 * @param usSectorSize The block size of devices to be attached. If in doubt use 512.
\r
83 * @param pError Pointer to a signed byte for error checking. Can be NULL if not required.
\r
84 * To be checked when a NULL pointer is returned.
\r
86 * @Return Returns a pointer to an FF_IOManager_t type object. NULL on xError, check the contents of
\r
89 FF_IOManager_t *FF_CreateIOManger( FF_CreationParameters_t *pxParameters, FF_Error_t *pError )
\r
91 FF_IOManager_t *pxIOManager = NULL;
\r
93 uint32_t ulCacheSize = pxParameters->ulMemorySize;
\r
94 uint32_t usSectorSize = pxParameters->ulSectorSize;
\r
98 ulCacheSize = N x ulSectorSize. */
\r
99 if( ( ( usSectorSize % 512 ) != 0 ) || ( usSectorSize == 0 ) )
\r
101 /* ulSectorSize Size not a multiple of 512 or it is zero*/
\r
102 xError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN;
\r
104 else if( ( ( ulCacheSize % ( uint32_t ) usSectorSize ) != 0 ) || ( ulCacheSize == 0 ) ||
\r
105 ( ulCacheSize == ( uint32_t ) usSectorSize ) )
\r
107 /* The size of the caching memory (ulCacheSize) must now be atleast 2 * ulSectorSize (or a deadlock will occur). */
\r
108 xError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN;
\r
112 pxIOManager = ( FF_IOManager_t * ) ffconfigMALLOC( sizeof( FF_IOManager_t ) );
\r
114 /* Ensure malloc() succeeded. */
\r
115 if( pxIOManager != NULL )
\r
117 /* Use memset() to clear every single bit. */
\r
118 memset( pxIOManager, '\0', sizeof( FF_IOManager_t ) );
\r
119 if( FF_CreateEvents( pxIOManager ) != pdFALSE )
\r
121 xError = FF_ERR_NONE;
\r
125 /* xEventGroupCreate() probably failed. */
\r
126 xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
\r
131 /* ffconfigMALLOC() failed. */
\r
132 xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
\r
136 if( FF_isERR( xError ) == pdFALSE )
\r
138 /* pxIOManager is created, FF_CreateEvents() succeeded. */
\r
139 if( pxParameters->pucCacheMemory != NULL )
\r
141 /* The caller has provided a piece of memory, use it. */
\r
142 pxIOManager->pucCacheMem = pxParameters->pucCacheMemory;
\r
146 /* No cache buffer provided, call malloc(). */
\r
147 pxIOManager->pucCacheMem = ( uint8_t * ) ffconfigMALLOC( ulCacheSize );
\r
148 if( pxIOManager->pucCacheMem != NULL )
\r
150 /* Indicate that malloc() was used for pucCacheMem. */
\r
151 pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFFERS;
\r
155 xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
\r
159 if( pxIOManager->pucCacheMem != NULL )
\r
161 memset( pxIOManager->pucCacheMem, '\0', ulCacheSize );
\r
165 if( FF_isERR( xError ) == pdFALSE )
\r
167 pxIOManager->usSectorSize = usSectorSize;
\r
168 pxIOManager->usCacheSize = ( uint16_t ) ( ulCacheSize / ( uint32_t ) usSectorSize );
\r
170 /* Malloc() memory for buffer objects. FreeRTOS+FAT never refers to a
\r
171 buffer directly but uses buffer objects instead. Allows for thread
\r
173 pxIOManager->pxBuffers = ( FF_Buffer_t * ) ffconfigMALLOC( sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize );
\r
175 if( pxIOManager->pxBuffers != NULL )
\r
177 /* From now on a call to FF_IOMAN_InitBufferDescriptors will clear
\r
179 pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFDESCR;
\r
181 FF_IOMAN_InitBufferDescriptors( pxIOManager );
\r
183 /* Finally store the semaphore for Buffer Description modifications. */
\r
184 pxIOManager->pvSemaphore = pxParameters->pvSemaphore;
\r
186 if( pxParameters->xBlockDeviceIsReentrant != pdFALSE )
\r
188 pxIOManager->ucFlags |= FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT;
\r
191 pxIOManager->xBlkDevice.fnpReadBlocks = pxParameters->fnReadBlocks;
\r
192 pxIOManager->xBlkDevice.fnpWriteBlocks = pxParameters->fnWriteBlocks;
\r
193 pxIOManager->xBlkDevice.pxDisk = pxParameters->pxDisk;
\r
197 xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
\r
201 if( FF_isERR( xError ) )
\r
203 if( pxIOManager != NULL )
\r
205 FF_DeleteIOManager( pxIOManager );
\r
206 pxIOManager = NULL;
\r
210 if( pError != NULL )
\r
215 return pxIOManager;
\r
216 } /* FF_CreateIOManger() */
\r
217 /*-----------------------------------------------------------*/
\r
221 * @brief Destroys an FF_IOManager_t object, and frees all assigned memory.
\r
223 * @param pxIOManager Pointer to an FF_IOManager_t object, as returned from FF_CreateIOManger.
\r
225 * @Return FF_ERR_NONE on sucess, or a documented error code on failure. (FF_ERR_NULL_POINTER)
\r
228 FF_Error_t FF_DeleteIOManager( FF_IOManager_t *pxIOManager )
\r
232 /* Ensure no NULL pointer was provided. */
\r
233 if( pxIOManager == NULL )
\r
235 xError = FF_ERR_NULL_POINTER | FF_DESTROYIOMAN;
\r
239 xError = FF_ERR_NONE;
\r
241 /* Ensure pxBuffers pointer was allocated. */
\r
242 if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFDESCR ) != 0 )
\r
244 ffconfigFREE( pxIOManager->pxBuffers );
\r
247 /* Ensure pucCacheMem pointer was allocated. */
\r
248 if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFFERS ) != 0 )
\r
250 ffconfigFREE( pxIOManager->pucCacheMem );
\r
253 /* Delete the event group object within the IO manager before deleting
\r
255 FF_DeleteEvents( pxIOManager );
\r
257 /* Finally free the FF_IOManager_t object. */
\r
258 ffconfigFREE( pxIOManager );
\r
262 } /* FF_DeleteIOManager() */
\r
263 /*-----------------------------------------------------------*/
\r
267 * @brief Initialises Buffer Descriptions as part of the FF_IOManager_t object initialisation.
\r
269 * @param pxIOManager IOMAN Object.
\r
272 void FF_IOMAN_InitBufferDescriptors( FF_IOManager_t *pxIOManager )
\r
274 uint8_t *pucBuffer = pxIOManager->pucCacheMem;
\r
275 FF_Buffer_t *pxBuffer = pxIOManager->pxBuffers;
\r
276 FF_Buffer_t *pxLastBuffer = pxBuffer + pxIOManager->usCacheSize;
\r
278 /* Clear the contents of the buffer descriptors. */
\r
279 memset( ( void * ) pxBuffer, '\0', sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize );
\r
281 while( pxBuffer < pxLastBuffer )
\r
283 pxBuffer->pucBuffer = pucBuffer;
\r
285 pucBuffer += pxIOManager->usSectorSize;
\r
287 } /* FF_IOMAN_InitBufferDescriptors() */
\r
288 /*-----------------------------------------------------------*/
\r
292 * @brief Flushes all Write cache buffers with no active Handles.
\r
294 * @param pxIOManager IOMAN Object.
\r
296 * @Return FF_ERR_NONE on Success.
\r
298 FF_Error_t FF_FlushCache( FF_IOManager_t *pxIOManager )
\r
300 BaseType_t xIndex, xIndex2;
\r
303 if( pxIOManager == NULL )
\r
305 xError = FF_ERR_NULL_POINTER | FF_FLUSHCACHE;
\r
309 xError = FF_ERR_NONE;
\r
311 FF_PendSemaphore( pxIOManager->pvSemaphore );
\r
313 for( xIndex = 0; xIndex < pxIOManager->usCacheSize; xIndex++ )
\r
315 /* If a buffers has no users and if it has been modified... */
\r
316 if( ( pxIOManager->pxBuffers[ xIndex ].usNumHandles == 0 ) && ( pxIOManager->pxBuffers[ xIndex ].bModified == pdTRUE ) )
\r
318 /* The buffer may be flushed to disk. */
\r
319 FF_BlockWrite( pxIOManager, pxIOManager->pxBuffers[ xIndex ].ulSector, 1, pxIOManager->pxBuffers[ xIndex ].pucBuffer, pdTRUE );
\r
321 /* Buffer has now been flushed, mark it as a read buffer and unmodified. */
\r
322 pxIOManager->pxBuffers[ xIndex ].ucMode = FF_MODE_READ;
\r
323 pxIOManager->pxBuffers[ xIndex ].bModified = pdFALSE;
\r
325 /* Search for other buffers that used this sector, and mark them as modified
\r
326 So that further requests will result in the new sector being fetched. */
\r
327 for( xIndex2 = 0; xIndex2 < pxIOManager->usCacheSize; xIndex2++ )
\r
329 if( ( xIndex != xIndex2 ) &&
\r
330 ( pxIOManager->pxBuffers[ xIndex2 ].ulSector == pxIOManager->pxBuffers[ xIndex ].ulSector ) &&
\r
331 ( pxIOManager->pxBuffers[ xIndex2 ].ucMode == FF_MODE_READ ) )
\r
333 pxIOManager->pxBuffers[ xIndex2 ].bModified = pdTRUE;
\r
339 if( ( pxIOManager->xBlkDevice.pxDisk != NULL ) &&
\r
340 ( pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook != NULL ) )
\r
342 /* Let the low-level driver also flush data.
\r
343 See comments in ff_ioman.h. */
\r
344 pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook( pxIOManager->xBlkDevice.pxDisk );
\r
347 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
351 } /* FF_FlushCache() */
\r
352 /*-----------------------------------------------------------*/
\r
355 A new version of FF_GetBuffer() with a simple mechanism for timeout
\r
357 #define FF_GETBUFFER_SLEEP_TIME_MS 10
\r
358 #define FF_GETBUFFER_WAIT_TIME_MS ( 20000 / FF_GETBUFFER_SLEEP_TIME_MS )
\r
360 FF_Buffer_t *FF_GetBuffer( FF_IOManager_t *pxIOManager, uint32_t ulSector, uint8_t ucMode )
\r
362 FF_Buffer_t *pxBuffer;
\r
363 /* Least Recently Used Buffer */
\r
364 FF_Buffer_t *pxRLUBuffer;
\r
365 FF_Buffer_t *pxMatchingBuffer = NULL;
\r
367 BaseType_t xLoopCount = FF_GETBUFFER_WAIT_TIME_MS;
\r
368 const FF_Buffer_t *pxLastBuffer = &( pxIOManager->pxBuffers[ pxIOManager->usCacheSize ] );
\r
370 /* 'pxIOManager->usCacheSize' is bigger than zero and it is a multiple of ulSectorSize. */
\r
372 while( pxMatchingBuffer == NULL )
\r
375 if( xLoopCount == 0 )
\r
380 FF_PendSemaphore( pxIOManager->pvSemaphore );
\r
382 for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ )
\r
384 if( ( pxBuffer->ulSector == ulSector ) && ( pxBuffer->bValid ) )
\r
386 pxMatchingBuffer = pxBuffer;
\r
387 /* Don't look further if you found a perfect match. */
\r
392 if( pxMatchingBuffer != NULL )
\r
394 /* A Match was found process! */
\r
395 if( ( ucMode == FF_MODE_READ ) && ( pxMatchingBuffer->ucMode == FF_MODE_READ ) )
\r
397 pxMatchingBuffer->usNumHandles += 1;
\r
398 pxMatchingBuffer->usPersistance += 1;
\r
402 if( pxMatchingBuffer->usNumHandles == 0 )
\r
404 pxMatchingBuffer->ucMode = ( ucMode & FF_MODE_RD_WR );
\r
405 if( ( ucMode & FF_MODE_WRITE ) != 0 )
\r
407 /* This buffer has no attached handles. */
\r
408 pxMatchingBuffer->bModified = pdTRUE;
\r
411 pxMatchingBuffer->usNumHandles = 1;
\r
412 pxMatchingBuffer->usPersistance += 1;
\r
416 pxMatchingBuffer = NULL; /* Sector is already in use, keep yielding until its available! */
\r
420 /* There is no valid buffer now for the desired sector.
\r
421 Find a free buffer and use it for that sector. */
\r
422 pxRLUBuffer = NULL;
\r
424 for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ )
\r
426 if( pxBuffer->usNumHandles != 0 )
\r
428 continue; /* Occupied */
\r
431 pxBuffer->ulLRU += 1;
\r
433 if( ( pxRLUBuffer == NULL ) ||
\r
434 ( pxBuffer->ulLRU > pxRLUBuffer->ulLRU ) ||
\r
435 ( ( pxBuffer->ulLRU == pxRLUBuffer->ulLRU ) && ( pxBuffer->usPersistance > pxRLUBuffer->usPersistance ) ) )
\r
437 pxRLUBuffer = pxBuffer;
\r
441 /* A free buffer with the highest value of 'ulLRU' was found: */
\r
442 if( pxRLUBuffer != NULL )
\r
444 /* Process the suitable candidate. */
\r
445 if( pxRLUBuffer->bModified == pdTRUE )
\r
447 /* Along with the pdTRUE parameter to indicate semaphore has been claimed already. */
\r
448 lRetVal = FF_BlockWrite( pxIOManager, pxRLUBuffer->ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE );
\r
451 /* NULL will be returned because 'pxMatchingBuffer' is still NULL. */
\r
456 if( ucMode == FF_MODE_WR_ONLY )
\r
458 memset( pxRLUBuffer->pucBuffer, '\0', pxIOManager->usSectorSize );
\r
462 lRetVal = FF_BlockRead( pxIOManager, ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE );
\r
465 /* 'pxMatchingBuffer' is NULL. */
\r
470 pxRLUBuffer->ucMode = ( ucMode & FF_MODE_RD_WR );
\r
471 pxRLUBuffer->usPersistance = 1;
\r
472 pxRLUBuffer->ulLRU = 0;
\r
473 pxRLUBuffer->usNumHandles = 1;
\r
474 pxRLUBuffer->ulSector = ulSector;
\r
476 pxRLUBuffer->bModified = ( ucMode & FF_MODE_WRITE ) != 0;
\r
478 pxRLUBuffer->bValid = pdTRUE;
\r
479 pxMatchingBuffer = pxRLUBuffer;
\r
481 } /* if( pxRLUBuffer != NULL ) */
\r
482 } /* else ( pxMatchingBuffer == NULL ) */
\r
484 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
486 /* Better to go asleep to give low-priority task a chance to release buffer(s). */
\r
487 FF_BufferWait( pxIOManager, FF_GETBUFFER_SLEEP_TIME_MS );
\r
488 } /* while( pxMatchingBuffer == NULL ) */
\r
490 if( xLoopCount > 0 )
\r
492 /* If xLoopCount is 0 here, the semaphore was not taken. */
\r
493 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
495 if( pxMatchingBuffer == NULL )
\r
497 FF_PRINTF( "FF_GetBuffer[0x%X]: failed mode 0x%X\n", ( unsigned )ulSector, ( unsigned )ucMode );
\r
499 return pxMatchingBuffer; /* Return the Matched Buffer! */
\r
500 } /* FF_GetBuffer() */
\r
501 /*-----------------------------------------------------------*/
\r
505 * @brief Releases a buffer resource.
\r
507 * @param pxIOManager Pointer to an FF_IOManager_t object.
\r
508 * @param pxBuffer Pointer to an FF_Buffer_t object.
\r
511 FF_Error_t FF_ReleaseBuffer( FF_IOManager_t *pxIOManager, FF_Buffer_t *pxBuffer )
\r
513 FF_Error_t xError = FF_ERR_NONE;
\r
515 /* Protect description changes with a semaphore. */
\r
516 FF_PendSemaphore( pxIOManager->pvSemaphore );
\r
518 #if( ffconfigCACHE_WRITE_THROUGH != 0 )
\r
519 if( pxBuffer->bModified == pdTRUE )
\r
521 xError = FF_BlockWrite( pxIOManager, pxBuffer->ulSector, 1, pxBuffer->pucBuffer, pdTRUE );
\r
522 if( FF_isERR( xError ) == pdFALSE )
\r
524 /* Ensure if an error occurs its still possible to write the block again. */
\r
525 pxBuffer->bModified = pdFALSE;
\r
529 configASSERT( pxBuffer->usNumHandles != 0 );
\r
531 if( pxBuffer->usNumHandles != 0 )
\r
533 pxBuffer->usNumHandles--;
\r
537 /*printf ("FF_ReleaseBuffer: buffer not claimed\n"); */
\r
541 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
543 /* Notify tasks which may be waiting in FF_GetBuffer() */
\r
544 FF_BufferProceed( pxIOManager );
\r
547 } /* FF_ReleaseBuffer() */
\r
548 /*-----------------------------------------------------------*/
\r
550 /* New Interface for FreeRTOS+FAT to read blocks. */
\r
551 int32_t FF_BlockRead( FF_IOManager_t *pxIOManager, uint32_t ulSectorLBA, uint32_t ulNumSectors, void *pxBuffer,
\r
552 BaseType_t xSemLocked )
\r
554 int32_t slRetVal = 0;
\r
556 if( pxIOManager->xPartition.ulTotalSectors != 0ul )
\r
558 /* At some point while formatting a partition, ulTotalSectors might be unknown.
\r
559 In that case this test will be skipped. */
\r
560 if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) )
\r
562 slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD;
\r
566 if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpReadBlocks != NULL ) )
\r
570 /* Make sure we don't execute a NULL. */
\r
571 if( ( xSemLocked == pdFALSE ) &&
\r
572 ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
\r
574 FF_PendSemaphore( pxIOManager->pvSemaphore );
\r
577 slRetVal = pxIOManager->xBlkDevice.fnpReadBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk );
\r
579 if( ( xSemLocked == pdFALSE ) &&
\r
580 ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
\r
582 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
585 if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY )
\r
590 FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS );
\r
595 } /* FF_BlockRead() */
\r
596 /*-----------------------------------------------------------*/
\r
598 int32_t FF_BlockWrite( FF_IOManager_t *pxIOManager, uint32_t ulSectorLBA, uint32_t ulNumSectors, void *pxBuffer,
\r
599 BaseType_t xSemLocked )
\r
601 int32_t slRetVal = 0;
\r
603 if( pxIOManager->xPartition.ulTotalSectors != 0 )
\r
605 /* At some point while formatting a partition, ulTotalSectors might be unknown.
\r
606 In that case this test will be skipped. */
\r
607 if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) )
\r
609 slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE;
\r
613 if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpWriteBlocks != NULL ) )
\r
616 { /* Make sure we don't execute a NULL. */
\r
618 if( ( xSemLocked == pdFALSE ) &&
\r
619 ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
\r
621 FF_PendSemaphore( pxIOManager->pvSemaphore );
\r
624 slRetVal = pxIOManager->xBlkDevice.fnpWriteBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk );
\r
626 if( ( xSemLocked == pdFALSE ) &&
\r
627 ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
\r
629 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
632 if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY )
\r
637 FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS );
\r
642 } /* FF_BlockWrite() */
\r
643 /*-----------------------------------------------------------*/
\r
646 * This global variable is a kind of expert option:
\r
647 * It may be set to one of these values: FF_T_FAT[12,16,32]
\r
648 * just to force the driver to assume a certain FAT type.
\r
650 uint8_t ucAssumeFATType;
\r
652 /* The history of FAT types:
\r
653 * The Microsoft documents says that the actual type: FAT-12, FAT-16 and FAT-32
\r
654 * of a partition can be found by looking at the total number of data clusters:
\r
656 * if( clusters < 4085 )
\r
658 * else if( clusters < 65525 )
\r
663 * In practice however, this does not always seem to be a correct assumption.
\r
665 * The first 12 or 16 bits in the FAT table may also help to determine the
\r
666 * correct FAT-type:
\r
668 * FAT-12: ( firstWord & 0x3FF ) == 0x3F8 )
\r
669 * FAT-16: ( firstWord == 0xFFF8 )
\r
672 static FF_Error_t prvDetermineFatType( FF_IOManager_t *pxIOManager )
\r
674 FF_Partition_t *pxPartition;
\r
675 FF_Buffer_t *pxBuffer;
\r
676 uint32_t ulFirstWord = 0ul;
\r
677 FF_Error_t xError = FF_ERR_NONE;
\r
679 pxPartition = &( pxIOManager->xPartition );
\r
680 if( ucAssumeFATType != 0 )
\r
682 switch( ucAssumeFATType )
\r
687 pxPartition->ucType = ucAssumeFATType;
\r
690 /* An invalid value will be ignored, and the FAT type is determined dynamically. */
\r
691 ucAssumeFATType = 0;
\r
694 xError = FF_ERR_NONE;
\r
697 /* Test again, the value may have become zero now: */
\r
698 if( ucAssumeFATType == 0 )
\r
700 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA, FF_MODE_READ );
\r
701 if( pxBuffer == NULL )
\r
703 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE;
\r
707 ulFirstWord = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, 0x0000 );
\r
708 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
712 if( ( ucAssumeFATType == 0 ) && ( FF_isERR( xError ) == pdFALSE ) )
\r
714 #if( ffconfigFAT12_SUPPORT != 0 )
\r
715 if( pxPartition->ulNumClusters < FAT16_SECTOR_COUNT_4085 )
\r
718 pxPartition->ucType = FF_T_FAT12;
\r
719 #if( ffconfigFAT_CHECK != 0 )
\r
720 if( ( ulFirstWord & 0x3FF ) != 0x3F8 )
\r
722 xError = FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE;
\r
725 #endif /* ffconfigFAT_CHECK */
\r
727 xError = FF_ERR_NONE;
\r
731 #endif /* ffconfigFAT12_SUPPORT */
\r
733 if( pxPartition->ulNumClusters < FAT32_SECTOR_COUNT_65525 )
\r
736 pxPartition->ucType = FF_T_FAT16;
\r
737 #if( ffconfigFAT_CHECK != 0 )
\r
739 if( ulFirstWord == 0xFFF8 )
\r
741 xError = FF_ERR_NONE;
\r
744 if( ( ulFirstWord & 0x3FF ) != 0x3F8 )
\r
746 FF_PRINTF( "Part at %lu is probably a FAT12\n", pxIOManager->xPartition.ulFATBeginLBA );
\r
750 FF_PRINTF( "Partition at %lu has strange FAT data %08lX\n",
\r
751 pxIOManager->xPartition.ulFATBeginLBA, ulFirstWord );
\r
753 xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_DETERMINEFATTYPE;
\r
756 #endif /* ffconfigFAT_CHECK */
\r
761 pxPartition->ucType = FF_T_FAT32;
\r
762 #if( ffconfigFAT_CHECK != 0 )
\r
763 if( ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF8 ) &&
\r
764 ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF0 ) )
\r
767 I had an SD-card which worked well in Linux/W32
\r
768 but FreeRTOS+FAT returned me this error
\r
769 So for me I left out this check (just issue a warning for now)
\r
771 FF_PRINTF( "prvDetermineFatType: firstWord %08lX\n", ulFirstWord );
\r
772 xError = FF_ERR_NONE; /* FF_ERR_IOMAN_NOT_FAT_FORMATTED; */
\r
775 #endif /* ffconfigFAT_CHECK */
\r
776 xError = FF_ERR_NONE;
\r
781 } /* prvDetermineFatType() */
\r
782 /*-----------------------------------------------------------*/
\r
784 /* Check if ucPartitionID introduces an extended partition. */
\r
785 static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID )
\r
787 BaseType_t xResult;
\r
789 if( ( ucPartitionID == FF_DOS_EXT_PART ) ||
\r
790 ( ucPartitionID == FF_WIN98_EXT_PART ) ||
\r
791 ( ucPartitionID == FF_LINUX_EXT_PART ) )
\r
801 } /* prvIsExtendedPartition() */
\r
802 /*-----------------------------------------------------------*/
\r
804 /* Check if the media byte in an MBR is valid */
\r
805 static BaseType_t prvIsValidMedia( uint8_t media )
\r
807 BaseType_t xResult;
\r
809 * 0xF8 is the standard value for
\93fixed
\94 (non-removable) media. For
\r
810 * removable media, 0xF0 is frequently used. The legal values for this
\r
811 * field are 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, and
\r
812 * 0xFF. The only other important point is that whatever value is put
\r
813 * in here must also be put in the low byte of the FAT[0] entry. This
\r
814 * dates back to the old MS-DOS 1.x media determination noted
\r
815 * earlier and is no longer usually used for anything.
\r
817 if( ( 0xf8 <= media ) || ( media == 0xf0 ) )
\r
827 } /* prvIsValidMedia() */
\r
828 /*-----------------------------------------------------------*/
\r
830 void FF_ReadParts( uint8_t *pucBuffer, FF_Part_t *pxParts )
\r
832 BaseType_t xPartNr;
\r
833 UBaseType_t uxOffset = FF_FAT_PTBL;
\r
835 /* pxParts is expected to be declared as an array of 4 elements:
\r
836 FF_Part_t pxParts[4];
\r
837 FF_ReadParts( pxBuffer->pucBuffer, pxParts );
\r
839 for( xPartNr = 0; xPartNr < 4; xPartNr++, uxOffset += 16, pxParts++ )
\r
841 pxParts->ucActive = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ACTIVE );
\r
842 pxParts->ucPartitionID = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ID );
\r
843 pxParts->ulSectorCount = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_SECT_COUNT );
\r
844 pxParts->ulStartLBA = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_LBA );
\r
847 /*-----------------------------------------------------------*/
\r
849 /* This function will traverse through a chain of extended partitions. */
\r
851 /* It is protected against rubbish data by a counter. */
\r
852 static FF_Error_t FF_ParseExtended( FF_IOManager_t *pxIOManager, uint32_t ulFirstSector, uint32_t ulFirstSize,
\r
853 FF_SPartFound_t *pPartsFound )
\r
855 uint32_t ulThisSector, ulThisSize;
\r
856 uint32_t ulSectorSize = pxIOManager->usSectorSize / 512;
\r
857 uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors;
\r
858 FF_Buffer_t *pxBuffer = NULL;
\r
859 BaseType_t xTryCount = 100;
\r
860 BaseType_t xPartNr;
\r
861 BaseType_t xExtendedPartNr;
\r
862 FF_Error_t xError = FF_ERR_NONE;
\r
863 FF_Part_t pxPartitions[ 4 ];
\r
865 ulThisSector = ulFirstSector;
\r
866 ulThisSize = ulFirstSize;
\r
868 /* Disable sector checking in FF_BlockRead, because the
\r
869 exact disk (partition) parameters are not yet known.
\r
870 Let user driver return an error is appropriate. */
\r
871 pxIOManager->xPartition.ulTotalSectors = 0;
\r
873 while( xTryCount-- )
\r
875 if( ( pxBuffer == NULL ) || ( pxBuffer->ulSector != ulThisSector ) )
\r
877 /* Moving to a different sector. Release the
\r
878 previous one and allocate a new buffer. */
\r
879 if( pxBuffer != NULL )
\r
881 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
883 if( FF_isERR( xError ) )
\r
888 FF_PRINTF( "FF_ParseExtended: Read sector %u\n", ( unsigned) ulThisSector );
\r
889 pxBuffer = FF_GetBuffer( pxIOManager, ulThisSector, FF_MODE_READ );
\r
890 if( pxBuffer == NULL )
\r
892 xError = FF_PARSEEXTENDED | FF_ERR_DEVICE_DRIVER_FAILED; /* | FUNCTION...; */
\r
898 uint8_t a = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 0 );
\r
899 uint8_t b = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 1 );
\r
901 if( ( a != 0x55 ) || ( b != 0xAA ) )
\r
903 FF_PRINTF( "FF_ParseExtended: No signature %02X,%02X\n", a, b );
\r
908 /* Check for data partition(s),
\r
909 and remember if there is an extended partition */
\r
911 FF_ReadParts( pxBuffer->pucBuffer, pxPartitions );
\r
913 /* Assume there is no next ext partition. */
\r
914 xExtendedPartNr = -1;
\r
916 for( xPartNr = 0; xPartNr < 4; xPartNr++ )
\r
918 uint32_t ulOffset, ulSize, ulNext;
\r
919 if( pxPartitions[ xPartNr ].ulSectorCount == 0 )
\r
921 /* Partition is empty */
\r
925 if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) )
\r
927 if( xExtendedPartNr < 0 )
\r
929 xExtendedPartNr = xPartNr;
\r
932 continue; /* We'll examine this ext partition later */
\r
935 /* Some sanity checks */
\r
936 ulOffset = pxPartitions[ xPartNr ].ulStartLBA * ulSectorSize;
\r
937 ulSize = pxPartitions[ xPartNr ].ulSectorCount * ulSectorSize;
\r
938 ulNext = ulThisSector + ulOffset;
\r
940 /* Is it oversized? */
\r
941 ( ulOffset + ulSize > ulThisSize ) ||
\r
942 /* or going backward? */
\r
943 ( ulNext < ulFirstSector ) ||
\r
944 /* Or outsize the logical partition? */
\r
945 ( ulNext > ulFirstSector + ulFirstSize )
\r
948 FF_PRINTF( "Part %d looks insane: ulThisSector %u ulOffset %u ulNext %u\n",
\r
949 ( int ) xPartNr, ( unsigned )ulThisSector, ( unsigned )ulOffset, ( unsigned )ulNext );
\r
954 /* Store this partition for the caller */
\r
955 FF_Part_t *p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ];
\r
957 /* Copy the whole structure */
\r
958 memcpy( p, pxPartitions + xPartNr, sizeof( *p ) );
\r
960 /* and make LBA absolute to sector-0. */
\r
961 p->ulStartLBA += ulThisSector;
\r
962 p->bIsExtended = pdTRUE;
\r
965 if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS )
\r
971 } /* for( xPartNr = 0; xPartNr < 4; xPartNr++ ) */
\r
973 if( xExtendedPartNr < 0 )
\r
975 FF_PRINTF( "No more extended partitions\n" );
\r
976 break; /* nothing left to do */
\r
979 /* Examine the ulNext extended partition */
\r
980 ulThisSector = ulFirstSector + pxPartitions[ xExtendedPartNr ].ulStartLBA * ulSectorSize;
\r
981 ulThisSize = pxPartitions[ xExtendedPartNr ].ulSectorCount * ulSectorSize;
\r
984 if( pxBuffer != NULL )
\r
986 FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
987 if( FF_isERR( xError ) == pdFALSE )
\r
989 xError = xTempError;
\r
993 pxIOManager->xPartition.ulTotalSectors = prevTotalSectors;
\r
996 } /* FF_ParseExtended() */
\r
997 /*-----------------------------------------------------------*/
\r
1001 * @brief Searches a disk for all primary and extended/logical partitions
\r
1002 * @brief Previously called FF_PartitionCount
\r
1004 * @param pxIOManager FF_IOManager_t object.
\r
1005 * @param pPartsFound Contains an array of ffconfigMAX_PARTITIONS partitions
\r
1007 * @Return >=0 Number of partitions found
\r
1008 * @Return <0 error
\r
1010 FF_Error_t FF_PartitionSearch( FF_IOManager_t *pxIOManager, FF_SPartFound_t *pPartsFound )
\r
1012 BaseType_t xPartNr;
\r
1013 FF_Buffer_t *pxBuffer;
\r
1014 uint8_t *ucDataBuffer;
\r
1015 BaseType_t isPBR = pdFALSE;
\r
1016 FF_Error_t xError = FF_ERR_NONE;
\r
1017 uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors;
\r
1018 FF_Part_t pxPartitions[ 4 ];
\r
1020 memset( pPartsFound, '\0', sizeof( *pPartsFound ) );
\r
1024 pxBuffer = FF_GetBuffer( pxIOManager, 0, FF_MODE_READ );
\r
1025 if( pxBuffer == NULL )
\r
1027 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_PARTITIONSEARCH;
\r
1031 /* Disable sector checking in FF_BlockRead
\r
1032 Let user driver return an error is appropriate. */
\r
1033 pxIOManager->xPartition.ulTotalSectors = 0;
\r
1034 ucDataBuffer = pxBuffer->pucBuffer;
\r
1036 /* Check MBR (Master Boot Record) or
\r
1037 PBR (Partition Boot Record) signature. */
\r
1038 if( ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ) != 0x55 ) &&
\r
1039 ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ) != 0xAA ) )
\r
1041 /* No MBR, but is it a PBR ?
\r
1042 Partition Boot Record */
\r
1043 if( ( FF_getChar( ucDataBuffer, 0 ) == 0xEB ) && /* PBR Byte 0 */
\r
1044 ( FF_getChar( ucDataBuffer, 2 ) == 0x90 ) )
\r
1047 No MBR but PBR exist then there is only one partition
\r
1048 Handle this later. */
\r
1053 FF_PRINTF( "FF_PartitionSearch: [%02X,%02X] No signature (%02X %02X), no PBR neither\n",
\r
1054 FF_getChar( ucDataBuffer, 0 ),
\r
1055 FF_getChar( ucDataBuffer, 2 ),
\r
1056 FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ),
\r
1057 FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE + 1 ) );
\r
1059 /* No MBR and no PBR then no partition found. */
\r
1060 xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH;
\r
1064 /* Copy the 4 partition records into 'pxPartitions': */
\r
1065 FF_ReadParts( ucDataBuffer, pxPartitions );
\r
1067 for( xPartNr = 0; ( xPartNr < 4 ) && ( isPBR == pdFALSE ); xPartNr++ )
\r
1069 /* FF_PRINTF ("FF_Part[%d]: id %02X act %02X Start %6lu Len %6lu (sectors)\n", */
\r
1070 /* xPartNr, pxPartitions[ xPartNr ].ucPartitionID, */
\r
1071 /* pxPartitions[ xPartNr ].ucActive, */
\r
1072 /* pxPartitions[ xPartNr ].ulStartLBA, */
\r
1073 /* pxPartitions[ xPartNr ].ulSectorCount); */
\r
1074 if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) != pdFALSE )
\r
1076 continue; /* Do this later */
\r
1079 /* The first sector must be a MBR, then check the partition entry in the MBR */
\r
1080 if( ( pxPartitions[ xPartNr ].ucActive != 0x80 ) &&
\r
1081 ( pxPartitions[ xPartNr ].ucActive != 0x00 ) )
\r
1083 if( ( xPartNr == 0 ) &&
\r
1084 ( FF_getShort( ucDataBuffer, FF_FAT_RESERVED_SECTORS ) != 0 ) &&
\r
1085 ( FF_getChar( ucDataBuffer, FF_FAT_NUMBER_OF_FATS ) != 0 ) )
\r
1091 xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH;
\r
1095 else if( pxPartitions[ xPartNr ].ulSectorCount )
\r
1097 FF_Part_t *p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ];
\r
1098 *p = pxPartitions[ xPartNr ];
\r
1099 p->bIsExtended = 0;
\r
1100 if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS )
\r
1106 if( FF_isERR( xError ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) )
\r
1110 for( xPartNr = 0; xPartNr < 4; xPartNr++ )
\r
1112 if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) )
\r
1114 xError = FF_ParseExtended( pxIOManager, pxPartitions[ xPartNr ].ulStartLBA,
\r
1115 pxPartitions[ xPartNr ].ulSectorCount, pPartsFound );
\r
1117 if( ( FF_isERR( xError ) != pdFALSE ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) )
\r
1124 if( pPartsFound->iCount == 0 )
\r
1126 FF_PRINTF( "FF_Part: no partitions, try as PBR\n" );
\r
1132 uint8_t media = FF_getChar( ucDataBuffer, FF_FAT_MEDIA_TYPE );
\r
1134 if( !prvIsValidMedia( media ) )
\r
1136 FF_PRINTF( "FF_Part: Looks like PBR but media %02X\n", media );
\r
1137 xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_PARTITIONSEARCH;
\r
1141 /* This looks like a PBR because it has a valid media type */
\r
1142 p = pPartsFound->pxPartitions;
\r
1143 p->ulStartLBA = 0; /* FF_FAT_PTBL_LBA */
\r
1144 p->ulSectorCount = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS );
\r
1145 if( p->ulSectorCount == 0ul )
\r
1147 p->ulSectorCount = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS );
\r
1150 p->ucActive = 0x80; /* FF_FAT_PTBL_ACTIVE */
\r
1151 p->ucPartitionID = 0x0B; /* FF_FAT_PTBL_ID MSDOS data partition */
\r
1152 p->bIsExtended = 0;
\r
1153 pPartsFound->iCount = 1;
\r
1155 } while( pdFALSE );
\r
1159 FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1160 if( FF_isERR( xError ) == pdFALSE )
\r
1162 xError = xTempError;
\r
1166 pxIOManager->xPartition.ulTotalSectors = prevTotalSectors;
\r
1168 return FF_isERR( xError ) ? xError : pPartsFound->iCount;
\r
1169 } /* FF_PartitionSearch() */
\r
1170 /*-----------------------------------------------------------*/
\r
1173 Mount GPT Partition Tables
\r
1175 #define FF_GPT_HEAD_ENTRY_SIZE 0x54
\r
1176 #define FF_GPT_HEAD_TOTAL_ENTRIES 0x50
\r
1177 #define FF_GPT_HEAD_PART_ENTRY_LBA 0x48
\r
1178 #define FF_GPT_ENTRY_FIRST_SECTOR_LBA 0x20
\r
1179 #define FF_GPT_HEAD_CRC 0x10
\r
1180 #define FF_GPT_HEAD_LENGTH 0x0C
\r
1182 static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t *pxIOManager, uint32_t ulPartitionNumber )
\r
1184 /* Continuing on from FF_Mount() pPartition->ulBeginLBA should be the sector of the GPT Header */
\r
1185 FF_Buffer_t *pxBuffer;
\r
1186 FF_Partition_t *pxPartition = &( pxIOManager->xPartition );
\r
1188 uint32_t ulBeginGPT;
\r
1189 uint32_t ulEntrySector;
\r
1190 uint32_t ulSectorOffset;
\r
1191 uint32_t ulPartitionEntrySize;
\r
1192 uint32_t ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength;
\r
1194 FF_Error_t xError;
\r
1198 if( ulPartitionNumber >= 128 )
\r
1200 xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY;
\r
1203 pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ );
\r
1204 if( pxBuffer == NULL )
\r
1206 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY;
\r
1210 /* Verify this is an EFI header with the text "EFI PART": */
\r
1211 if( memcmp( pxBuffer->pucBuffer, "EFI PART", 8 ) != 0 )
\r
1213 /* Already returning an error, but this error would override the current one. */
\r
1214 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1215 if( FF_isERR( xError ) == pdFALSE )
\r
1217 xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_GETEFIPARTITIONENTRY;
\r
1222 ulBeginGPT = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_PART_ENTRY_LBA );
\r
1223 ulPartitionEntrySize = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_ENTRY_SIZE );
\r
1224 ulGPTHeadCRC = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC );
\r
1225 ulGPTHeadLength = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_LENGTH );
\r
1227 /* Calculate Head CRC */
\r
1228 /* Blank CRC field */
\r
1229 FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, 0x00000000 );
\r
1231 /* Calculate CRC */
\r
1232 ulGPTCrcCheck = FF_GetCRC32( pxBuffer->pucBuffer, ulGPTHeadLength );
\r
1234 /* Restore The CRC field */
\r
1235 FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC );
\r
1237 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1238 if( FF_isERR( xError ) )
\r
1244 if( ulGPTHeadCRC != ulGPTCrcCheck )
\r
1246 xError = FF_ERR_IOMAN_GPT_HEADER_CORRUPT | FF_GETEFIPARTITIONENTRY;
\r
1250 /* Calculate Sector Containing the Partition Entry we want to use. */
\r
1251 ulEntrySector = ( ( ulPartitionNumber * ulPartitionEntrySize ) / pxIOManager->usSectorSize ) + ulBeginGPT;
\r
1252 ulSectorOffset = ( ulPartitionNumber % ( pxIOManager->usSectorSize / ulPartitionEntrySize ) ) * ulPartitionEntrySize;
\r
1254 pxBuffer = FF_GetBuffer( pxIOManager, ulEntrySector, FF_MODE_READ );
\r
1256 if( pxBuffer == NULL )
\r
1258 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY;
\r
1262 pxPartition->ulBeginLBA = FF_getLong( pxBuffer->pucBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA );
\r
1265 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1266 if( FF_isERR( xError ) == pdFALSE )
\r
1268 if( pxPartition->ulBeginLBA == 0ul )
\r
1270 xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY;
\r
1277 } /* FF_GetEfiPartitionEntry() */
\r
1278 /*-----------------------------------------------------------*/
\r
1282 * @brief Mounts the Specified partition, the volume specified by the FF_IOManager_t object provided.
\r
1284 * The device drivers must adhere to the specification provided by
\r
1285 * FF_WriteBlocks_t and FF_ReadBlocks_t.
\r
1287 * @param pxIOManager FF_IOManager_t object.
\r
1288 * @param PartitionNumber The primary or logical partition number to be mounted,
\r
1289 * ranging between 0 and ffconfigMAX_PARTITIONS-1 (normally 0)
\r
1290 * Note that FF_PartitionSearch can be called in advance to
\r
1291 * enumerate all available partitions
\r
1293 * @Return 0 on success.
\r
1294 * @Return FF_ERR_NULL_POINTER if a pxIOManager object wasn't provided.
\r
1295 * @Return FF_ERR_IOMAN_INVALID_PARTITION_NUM if the partition number is out of range.
\r
1296 * @Return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION if no partition was found.
\r
1297 * @Return FF_ERR_IOMAN_INVALID_FORMAT if the master boot record or partition boot block didn't provide sensible data.
\r
1298 * @Return FF_ERR_IOMAN_NOT_FAT_FORMATTED if the volume or partition couldn't be determined to be FAT. (@see FreeRTOSFATConfig.h)
\r
1301 FF_Error_t FF_Mount( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )
\r
1303 FF_Partition_t *pxPartition;
\r
1304 FF_Buffer_t *pxBuffer = 0;
\r
1305 FF_Error_t xError = FF_ERR_NONE;
\r
1306 int16_t rootEntryCount;
\r
1307 FF_IOManager_t *pxIOManager = pxDisk->pxIOManager;
\r
1309 /* HT TODO: find a method to safely determine the FAT type: 32/16/12 */
\r
1310 /* other than only counting Clusters */
\r
1311 /* UBaseType_t fat32Indicator = 0; */
\r
1312 FF_Part_t *pxMyPartition;
\r
1313 #if( ffconfigHASH_CACHE != 0 )
\r
1316 FF_Error_t xPartitionCount = 0;
\r
1317 FF_SPartFound_t partsFound;
\r
1318 partsFound.iCount = 0;
\r
1322 if( pxIOManager == NULL )
\r
1324 xError = FF_ERR_NULL_POINTER | FF_MOUNT;
\r
1328 pxPartition = &( pxIOManager->xPartition );
\r
1330 #if( ffconfigREMOVABLE_MEDIA != 0 )
\r
1332 pxIOManager->ucFlags &= ( uint8_t ) ( ~ ( FF_IOMAN_DEVICE_IS_EXTRACTED ) );
\r
1334 #endif /* ffconfigREMOVABLE_MEDIA */
\r
1336 /* FF_IOMAN_InitBufferDescriptors will clear 'pxBuffers' */
\r
1337 memset( pxIOManager->pucCacheMem, '\0', ( size_t ) pxIOManager->usSectorSize * pxIOManager->usCacheSize );
\r
1339 #if( ffconfigHASH_CACHE != 0 )
\r
1341 memset( pxIOManager->xHashCache, '\0', sizeof( pxIOManager->xHashCache ) );
\r
1342 for( i = 0; i < ffconfigHASH_CACHE_DEPTH; i++ )
\r
1344 /* _HT_ Check why did JW put it to 100? */
\r
1345 pxIOManager->xHashCache[ i ].ulMisses = 100;
\r
1349 #if( ffconfigPATH_CACHE != 0 )
\r
1351 memset( pxPartition->pxPathCache, '\0', sizeof( pxPartition->pxPathCache ) );
\r
1354 FF_IOMAN_InitBufferDescriptors( pxIOManager );
\r
1355 pxIOManager->FirstFile = 0;
\r
1357 xPartitionCount = FF_PartitionSearch( pxIOManager, &partsFound );
\r
1358 if( FF_isERR( xPartitionCount ) )
\r
1360 xError = xPartitionCount;
\r
1364 if( xPartitionCount == 0 )
\r
1366 xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_MOUNT;
\r
1370 if( xPartitionNumber >= xPartitionCount )
\r
1372 xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MOUNT;
\r
1376 pxMyPartition = &( partsFound.pxPartitions[ xPartitionNumber ] );
\r
1378 pxPartition->ulBeginLBA = pxMyPartition->ulStartLBA;
\r
1380 if( pxMyPartition->ucPartitionID == 0xEE )
\r
1382 xError = FF_GetEfiPartitionEntry( pxIOManager, xPartitionNumber );
\r
1384 if( FF_isERR( xError ) )
\r
1390 /* Now we get the Partition sector. */
\r
1391 pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ );
\r
1392 if( pxBuffer == NULL )
\r
1394 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNT;
\r
1398 pxPartition->usBlkSize = FF_getShort( pxBuffer->pucBuffer, FF_FAT_BYTES_PER_SECTOR );
\r
1399 if( ( ( pxPartition->usBlkSize % 512 ) != 0 ) || ( pxPartition->usBlkSize == 0 ) )
\r
1401 /* An error here should override the current error, as its likely fatal. */
\r
1402 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1403 if( FF_isERR( xError ) == pdFALSE )
\r
1405 xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
\r
1410 /* Assume FAT16, then we'll adjust if its FAT32 */
\r
1411 pxPartition->usReservedSectors = FF_getShort( pxBuffer->pucBuffer, FF_FAT_RESERVED_SECTORS );
\r
1412 pxPartition->ulFATBeginLBA = pxPartition->ulBeginLBA + pxPartition->usReservedSectors;
\r
1414 pxPartition->ucNumFATS = ( uint8_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_NUMBER_OF_FATS );
\r
1415 pxPartition->ulSectorsPerFAT = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_SECTORS_PER_FAT );
\r
1417 pxPartition->ulSectorsPerCluster = FF_getChar( pxBuffer->pucBuffer, FF_FAT_SECTORS_PER_CLUS );
\r
1419 /* Set the BlockFactor (How many real-blocks in a fake block!). */
\r
1420 pxPartition->ucBlkFactor = ( uint8_t ) ( pxPartition->usBlkSize / pxIOManager->usSectorSize );
\r
1421 pxPartition->ulTotalSectors = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS );
\r
1422 if( pxPartition->ulTotalSectors == 0 )
\r
1424 pxPartition->ulTotalSectors = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS );
\r
1427 if( pxPartition->ulSectorsPerFAT == 0 )
\r
1429 pxPartition->ulSectorsPerFAT = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_SECTORS_PER_FAT );
\r
1430 pxPartition->ulRootDirCluster = FF_getLong( pxBuffer->pucBuffer, FF_FAT_ROOT_DIR_CLUSTER );
\r
1431 memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_32_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1 );
\r
1435 pxPartition->ulRootDirCluster = 1; /* 1st Cluster is RootDir! */
\r
1436 memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_16_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1);
\r
1439 pxPartition->ulClusterBeginLBA = pxPartition->ulFATBeginLBA + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT );
\r
1440 #if( ffconfigWRITE_FREE_COUNT != 0 )
\r
1442 pxPartition->ulFSInfoLBA = pxPartition->ulBeginLBA + FF_getShort( pxBuffer->pucBuffer, 48 );
\r
1445 FF_ReleaseBuffer( pxIOManager, pxBuffer ); /* Release the buffer finally! */
\r
1446 if( pxPartition->usBlkSize == 0 )
\r
1448 xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
\r
1452 rootEntryCount = FF_getShort( pxBuffer->pucBuffer, FF_FAT_ROOT_ENTRY_COUNT );
\r
1453 pxPartition->ulRootDirSectors = ( ( rootEntryCount * 32 ) + pxPartition->usBlkSize - 1 ) / pxPartition->usBlkSize;
\r
1454 pxPartition->ulFirstDataSector = pxPartition->ulClusterBeginLBA + pxPartition->ulRootDirSectors;
\r
1455 pxPartition->ulDataSectors = pxPartition->ulTotalSectors - ( pxPartition->usReservedSectors + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT ) + pxPartition->ulRootDirSectors );
\r
1458 * HT: fat32Indicator not yet used
\r
1459 * As there is so much confusion about the FAT types
\r
1460 * I was thinking of collecting indications for either FAT12, 16 or 32
\r
1464 if( FF_getShort( pxBuffer->pucBuffer, FF_FAT_EXT_BOOT_SIGNATURE ) == 0x29 )
\r
1466 if( rootEntryCount == 0 )
\r
1469 if( pxPartition->ulSectorsPerCluster == 0 )
\r
1471 xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
\r
1475 pxPartition->ulNumClusters = pxPartition->ulDataSectors / pxPartition->ulSectorsPerCluster;
\r
1477 xError = prvDetermineFatType( pxIOManager );
\r
1478 if( FF_isERR( xError ) )
\r
1483 if( !rootEntryCount && pxPartition->ucType != FF_T_FAT32 )
\r
1485 FF_PRINTF( "No root dir, must be a FAT32\n" );
\r
1486 pxPartition->ucType = FF_T_FAT32;
\r
1489 pxPartition->ucPartitionMounted = pdTRUE;
\r
1490 pxPartition->ulLastFreeCluster = 0;
\r
1491 #if( ffconfigMOUNT_FIND_FREE != 0 )
\r
1493 FF_LockFAT( pxIOManager );
\r
1495 /* The parameter 'pdFALSE' means: do not claim the free cluster found. */
\r
1496 pxPartition->ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
\r
1498 FF_UnlockFAT( pxIOManager );
\r
1500 if( FF_isERR( xError ) )
\r
1502 if( FF_GETERROR( xError ) == FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE )
\r
1504 pxPartition->ulLastFreeCluster = 0;
\r
1512 pxPartition->ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
\r
1513 if( FF_isERR( xError ) )
\r
1520 pxPartition->ulFreeClusterCount = 0;
\r
1522 #endif /* ffconfigMOUNT_FIND_FREE */
\r
1526 if( FF_isERR( xError ) == pdFALSE )
\r
1532 } /* FF_Mount() */
\r
1533 /*-----------------------------------------------------------*/
\r
1537 * @brief Checks the cache for Active Handles
\r
1539 * @param pxIOManager FF_IOManager_t Object.
\r
1541 * @Return pdTRUE if an active handle is found, else pdFALSE.
\r
1543 * @pre This function must be wrapped with the cache handling semaphore.
\r
1545 static BaseType_t prvHasActiveHandles( FF_IOManager_t *pxIOManager )
\r
1547 BaseType_t xResult;
\r
1548 FF_Buffer_t *pxBuffer = pxIOManager->pxBuffers;
\r
1549 FF_Buffer_t *pxLastBuffer = pxBuffer + pxIOManager->usCacheSize;
\r
1553 if( pxBuffer->usNumHandles )
\r
1559 if( pxBuffer == pxLastBuffer )
\r
1561 xResult = pdFALSE;
\r
1567 } /* prvHasActiveHandles() */
\r
1568 /*-----------------------------------------------------------*/
\r
1572 * @brief Unmounts the active partition.
\r
1574 * @param pxIOManager FF_IOManager_t Object.
\r
1576 * @Return FF_ERR_NONE on success.
\r
1578 FF_Error_t FF_Unmount( FF_Disk_t *pxDisk )
\r
1580 FF_Error_t xError = FF_ERR_NONE;
\r
1581 FF_IOManager_t *pxIOManager;
\r
1583 #if( ffconfigMIRROR_FATS_UMOUNT != 0 )
\r
1584 UBaseType_t uxIndex, y;
\r
1585 FF_Buffer_t *pxBuffer;
\r
1588 if( pxDisk->pxIOManager == NULL )
\r
1590 xError = FF_ERR_NULL_POINTER | FF_UNMOUNT;
\r
1592 else if( pxDisk->pxIOManager->xPartition.ucPartitionMounted == 0 )
\r
1594 xError = FF_ERR_NONE;
\r
1598 pxIOManager = pxDisk->pxIOManager;
\r
1599 FF_PendSemaphore( pxIOManager->pvSemaphore ); /* Ensure that there are no File Handles */
\r
1601 if( prvHasActiveHandles( pxIOManager ) != 0 )
\r
1603 /* Active handles found on the cache. */
\r
1604 xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT;
\r
1606 else if( pxIOManager->FirstFile != NULL )
\r
1608 /* Open files in this partition. */
\r
1609 xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT;
\r
1613 /* Release Semaphore to call this function! */
\r
1614 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
1615 /* Flush any unwritten sectors to disk. */
\r
1616 xError = FF_FlushCache( pxIOManager );
\r
1617 /* Reclaim Semaphore */
\r
1618 FF_PendSemaphore( pxIOManager->pvSemaphore );
\r
1620 if( FF_isERR( xError ) == pdFALSE )
\r
1622 pxIOManager->xPartition.ucPartitionMounted = pdFALSE;
\r
1624 #if( ffconfigMIRROR_FATS_UMOUNT != 0 )
\r
1626 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
1627 for( uxIndex = 0; uxIndex < pxIOManager->xPartition.ulSectorsPerFAT; uxIndex++ )
\r
1629 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + uxIndex, FF_MODE_READ );
\r
1632 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_UNMOUNT;
\r
1635 for( y = 0; y < pxIOManager->xPartition.ucNumFATS; y++ )
\r
1637 FF_BlockWrite( pxIOManager,
\r
1638 pxIOManager->xPartition.ulFATBeginLBA + ( y * pxIOManager->xPartition.ulSectorsPerFAT ) + uxIndex, 1,
\r
1639 pxBuffer->pucBuffer, pdFALSE );
\r
1642 FF_PendSemaphore( pxIOManager->pvSemaphore );
\r
1648 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
\r
1652 } /* FF_Unmount() */
\r
1653 /*-----------------------------------------------------------*/
\r
1655 FF_Error_t FF_IncreaseFreeClusters( FF_IOManager_t *pxIOManager, uint32_t Count )
\r
1657 FF_Error_t xError;
\r
1659 #if( ffconfigWRITE_FREE_COUNT != 0 )
\r
1660 FF_Buffer_t *pxBuffer;
\r
1665 /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */
\r
1666 if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
\r
1668 /* Apparently the number of free clusters has not been calculated yet,
\r
1669 or no free cluster was available. Now check it. */
\r
1670 pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
\r
1671 if( FF_isERR( xError ) )
\r
1678 xError = FF_ERR_NONE;
\r
1679 taskENTER_CRITICAL();
\r
1681 pxIOManager->xPartition.ulFreeClusterCount += Count;
\r
1683 taskEXIT_CRITICAL();
\r
1686 if( pxIOManager->xPartition.ulLastFreeCluster == 0 )
\r
1688 BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
\r
1692 FF_LockFAT( pxIOManager );
\r
1694 /* Find the an available cluster. */
\r
1695 pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
\r
1698 FF_UnlockFAT( pxIOManager );
\r
1700 if( FF_isERR( xError ) )
\r
1706 #if( ffconfigWRITE_FREE_COUNT != 0 )
\r
1708 /* FAT32 updates the FSINFO sector. */
\r
1709 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
1711 /* Find the FSINFO sector. */
\r
1712 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE );
\r
1713 if( pxBuffer == NULL )
\r
1715 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_INCREASEFREECLUSTERS;
\r
1719 uint32_t ulSignature1;
\r
1720 uint32_t ulSignature2;
\r
1722 ulSignature1 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 );
\r
1723 ulSignature2 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 );
\r
1725 if( ( ulSignature1 == FS_INFO_SIGNATURE1_0x41615252 ) &&
\r
1726 ( ulSignature2 == FS_INFO_SIGNATURE2_0x61417272 ) )
\r
1728 /* FSINFO sector magic numbers we're verified. Safe to write. */
\r
1729 FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount );
\r
1730 FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster );
\r
1732 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1741 } /* FF_IncreaseFreeClusters() */
\r
1742 /*-----------------------------------------------------------*/
\r
1744 FF_Error_t FF_DecreaseFreeClusters( FF_IOManager_t *pxIOManager, uint32_t Count )
\r
1746 FF_Error_t xError = FF_ERR_NONE;
\r
1747 #if( ffconfigWRITE_FREE_COUNT != 0 )
\r
1748 FF_Buffer_t *pxBuffer;
\r
1751 if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
\r
1753 pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
\r
1757 taskENTER_CRITICAL();
\r
1758 pxIOManager->xPartition.ulFreeClusterCount -= Count;
\r
1759 taskEXIT_CRITICAL();
\r
1762 if( FF_isERR( xError ) == pdFALSE )
\r
1764 if( pxIOManager->xPartition.ulLastFreeCluster == 0 )
\r
1766 FF_LockFAT( pxIOManager );
\r
1768 pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
\r
1770 FF_UnlockFAT( pxIOManager );
\r
1773 if( FF_isERR( xError ) == pdFALSE )
\r
1775 #if( ffconfigWRITE_FREE_COUNT != 0 )
\r
1777 /* FAT32 update the FSINFO sector. */
\r
1778 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
1780 /* Find the FSINFO sector. */
\r
1781 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE );
\r
1782 if( pxBuffer == NULL )
\r
1784 xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DECREASEFREECLUSTERS;
\r
1788 if( ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 ) == FS_INFO_SIGNATURE1_0x41615252 ) &&
\r
1789 ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 ) == FS_INFO_SIGNATURE2_0x61417272 ) )
\r
1791 /* FSINFO sector magic nums we're verified. Safe to write. */
\r
1792 FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount );
\r
1793 FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster );
\r
1795 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1803 } /* FF_DecreaseFreeClusters() */
\r
1804 /*-----------------------------------------------------------*/
\r
1807 * @brief Returns the Block-size of a mounted Partition
\r
1809 * The purpose of this function is to provide API access to information
\r
1810 * that might be useful in special cases. Like USB sticks that require a sector
\r
1811 * knocking sequence for security. After the sector knock, some secure USB
\r
1812 * sticks then present a different BlockSize.
\r
1814 * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger()
\r
1816 * @Return The blocksize of the partition. A value less than 0 when an error occurs.
\r
1817 * @Return Any negative value can be cast to the FF_Error_t type.
\r
1819 int32_t FF_GetPartitionBlockSize( FF_IOManager_t *pxIOManager )
\r
1824 lReturn = ( int32_t ) pxIOManager->xPartition.usBlkSize;
\r
1828 lReturn = FF_ERR_NULL_POINTER | FF_GETPARTITIONBLOCKSIZE;
\r
1832 } /* FF_GetPartitionBlockSize() */
\r
1833 /*-----------------------------------------------------------*/
\r
1835 #if( ffconfig64_NUM_SUPPORT != 0 )
\r
1838 * @brief Returns the number of bytes contained within the mounted partition or volume.
\r
1840 * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger()
\r
1842 * @Return The total number of bytes that the mounted partition or volume contains.
\r
1845 uint64_t FF_GetVolumeSize( FF_IOManager_t *pxIOManager )
\r
1847 uint64_t ullResult;
\r
1851 uint32_t TotalClusters = ( pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster );
\r
1852 ullResult = ( uint64_t )
\r
1854 ( uint64_t ) TotalClusters * ( uint64_t )
\r
1855 ( ( uint64_t ) pxIOManager->xPartition.ulSectorsPerCluster * ( uint64_t ) pxIOManager->xPartition.usBlkSize )
\r
1864 } /* FF_GetVolumeSize() */
\r
1866 uint32_t FF_GetVolumeSize( FF_IOManager_t *pxIOManager )
\r
1868 uint32_t ulResult;
\r
1871 uint32_t TotalClusters = pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster;
\r
1872 ulResult = ( uint32_t ) ( TotalClusters * ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->xPartition.usBlkSize ) );
\r
1880 } /* FF_GetVolumeSize() */
\r
1882 /*-----------------------------------------------------------*/
\r