| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971 |
- /*
- * FreeRTOS+FAT V2.3.3
- * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * https://www.FreeRTOS.org
- * https://github.com/FreeRTOS
- *
- */
- /**
- * @file ff_ioman.c
- * @ingroup IOMAN
- *
- * @defgroup IOMAN I/O Manager
- * @brief Handles IO buffers for FreeRTOS+FAT safely.
- *
- * Provides a simple static interface to the rest of FreeRTOS+FAT to manage
- * buffers. It also defines the public interfaces for Creating and
- * Destroying a FreeRTOS+FAT IO object.
- **/
- #include <time.h>
- #include <string.h>
- #include "ff_headers.h"
- #define FAT16_SECTOR_COUNT_4085 4085
- #define FAT32_SECTOR_COUNT_65525 65525 /* 65536 clusters */
- /* Some values and offsets describing the special sector FS INFO: */
- #define FS_INFO_SIGNATURE1_0x41615252 0x41615252UL
- #define FS_INFO_SIGNATURE2_0x61417272 0x61417272UL
- #define FS_INFO_OFFSET_SIGNATURE1_000 0
- #define FS_INFO_OFFSET_SIGNATURE2_484 484
- #define FS_INFO_OFFSET_FREE_COUNT_488 488
- #define FS_INFO_OFFSET_FREE_CLUSTER_492 492
- /* Inspect the PBR (Partition Boot Record) to determine the type of FAT */
- static FF_Error_t prvDetermineFatType( FF_IOManager_t * pxIOManager );
- /* Check if a given ID introduces an extended partition. */
- static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID );
- /* Return pdTRUE if the media byte in an MBR is valid. */
- static BaseType_t prvIsValidMedia( uint8_t media );
- /* Read the MBR to see what extended partitions have been defined.
- * Definitions of extended partitions may be chained.
- * Walk down the chain to find all extended partitions. */
- static FF_Error_t FF_ParseExtended( FF_IOManager_t * pxIOManager,
- uint32_t ulFirstSector,
- uint32_t ulFirstSize,
- FF_SPartFound_t * pPartsFound );
- static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t * pxIOManager,
- uint32_t ulPartitionNumber );
- static BaseType_t prvHasActiveHandles( FF_IOManager_t * pxIOManager );
- /**
- * @public
- * @brief Creates an FF_IOManager_t object, to initialise FreeRTOS+FAT
- *
- * @param pucCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc).
- * @param ulCacheSize The size of the provided buffer, or size of the cache to be created.
- * (Must be at least 2 * ulSectorSize). Always a multiple of ulSectorSize.
- * @param usSectorSize The block size of devices to be attached. If in doubt use 512.
- * @param pError Pointer to a signed byte for error checking. Can be NULL if not required.
- * To be checked when a NULL pointer is returned.
- *
- * @Return Returns a pointer to an FF_IOManager_t type object. NULL on xError, check the contents of
- * @Return pError
- **/
- FF_IOManager_t * FF_CreateIOManger( FF_CreationParameters_t * pxParameters,
- FF_Error_t * pError )
- {
- FF_IOManager_t * pxIOManager = NULL;
- FF_Error_t xError;
- uint32_t ulCacheSize = pxParameters->ulMemorySize;
- uint32_t usSectorSize = pxParameters->ulSectorSize;
- /* Normally:
- * ulSectorSize = 512
- * ulCacheSize = N x ulSectorSize. */
- if( ( ( usSectorSize % 512 ) != 0 ) || ( usSectorSize == 0 ) )
- {
- /* ulSectorSize Size not a multiple of 512 or it is zero*/
- xError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN;
- }
- else if( ( ( ulCacheSize % ( uint32_t ) usSectorSize ) != 0 ) || ( ulCacheSize == 0 ) ||
- ( ulCacheSize == ( uint32_t ) usSectorSize ) )
- {
- /* The size of the caching memory (ulCacheSize) must now be atleast 2 * ulSectorSize (or a deadlock will occur). */
- xError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN;
- }
- else
- {
- pxIOManager = ( FF_IOManager_t * ) ffconfigMALLOC( sizeof( FF_IOManager_t ) );
- /* Ensure malloc() succeeded. */
- if( pxIOManager != NULL )
- {
- /* Use memset() to clear every single bit. */
- memset( pxIOManager, '\0', sizeof( FF_IOManager_t ) );
- if( FF_CreateEvents( pxIOManager ) != pdFALSE )
- {
- xError = FF_ERR_NONE;
- }
- else
- {
- /* xEventGroupCreate() probably failed. */
- xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
- }
- }
- else
- {
- /* ffconfigMALLOC() failed. */
- xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* pxIOManager is created, FF_CreateEvents() succeeded. */
- if( pxParameters->pucCacheMemory != NULL )
- {
- /* The caller has provided a piece of memory, use it. */
- pxIOManager->pucCacheMem = pxParameters->pucCacheMemory;
- }
- else
- {
- /* No cache buffer provided, call malloc(). */
- pxIOManager->pucCacheMem = ( uint8_t * ) ffconfigMALLOC( ulCacheSize );
- if( pxIOManager->pucCacheMem != NULL )
- {
- /* Indicate that malloc() was used for pucCacheMem. */
- pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFFERS;
- }
- else
- {
- xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
- }
- }
- if( pxIOManager->pucCacheMem != NULL )
- {
- memset( pxIOManager->pucCacheMem, '\0', ulCacheSize );
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- pxIOManager->usSectorSize = usSectorSize;
- pxIOManager->usCacheSize = ( uint16_t ) ( ulCacheSize / ( uint32_t ) usSectorSize );
- /* Malloc() memory for buffer objects. FreeRTOS+FAT never refers to a
- * buffer directly but uses buffer objects instead. Allows for thread
- * safety. */
- pxIOManager->pxBuffers = ( FF_Buffer_t * ) ffconfigMALLOC( sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize );
- if( pxIOManager->pxBuffers != NULL )
- {
- /* From now on a call to FF_IOMAN_InitBufferDescriptors will clear
- * pxBuffers. */
- pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFDESCR;
- FF_IOMAN_InitBufferDescriptors( pxIOManager );
- /* Finally store the semaphore for Buffer Description modifications. */
- pxIOManager->pvSemaphore = pxParameters->pvSemaphore;
- if( pxParameters->xBlockDeviceIsReentrant != pdFALSE )
- {
- pxIOManager->ucFlags |= FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT;
- }
- pxIOManager->xBlkDevice.fnpReadBlocks = pxParameters->fnReadBlocks;
- pxIOManager->xBlkDevice.fnpWriteBlocks = pxParameters->fnWriteBlocks;
- pxIOManager->xBlkDevice.pxDisk = pxParameters->pxDisk;
- }
- else
- {
- xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
- }
- }
- if( FF_isERR( xError ) )
- {
- if( pxIOManager != NULL )
- {
- FF_DeleteIOManager( pxIOManager );
- pxIOManager = NULL;
- }
- }
- if( pError != NULL )
- {
- *pError = xError;
- }
- return pxIOManager;
- } /* FF_CreateIOManger() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Destroys an FF_IOManager_t object, and frees all assigned memory.
- *
- * @param pxIOManager Pointer to an FF_IOManager_t object, as returned from FF_CreateIOManger.
- *
- * @Return FF_ERR_NONE on sucess, or a documented error code on failure. (FF_ERR_NULL_POINTER)
- *
- **/
- FF_Error_t FF_DeleteIOManager( FF_IOManager_t * pxIOManager )
- {
- FF_Error_t xError;
- /* Ensure no NULL pointer was provided. */
- if( pxIOManager == NULL )
- {
- xError = FF_ERR_NULL_POINTER | FF_DESTROYIOMAN;
- }
- else
- {
- xError = FF_ERR_NONE;
- /* Ensure pxBuffers pointer was allocated. */
- if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFDESCR ) != 0 )
- {
- ffconfigFREE( pxIOManager->pxBuffers );
- }
- /* Ensure pucCacheMem pointer was allocated. */
- if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFFERS ) != 0 )
- {
- ffconfigFREE( pxIOManager->pucCacheMem );
- }
- /* Delete the event group object within the IO manager before deleting
- * the manager. */
- FF_DeleteEvents( pxIOManager );
- /* Finally free the FF_IOManager_t object. */
- ffconfigFREE( pxIOManager );
- }
- return xError;
- } /* FF_DeleteIOManager() */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Initialises Buffer Descriptions as part of the FF_IOManager_t object initialisation.
- *
- * @param pxIOManager IOMAN Object.
- *
- **/
- void FF_IOMAN_InitBufferDescriptors( FF_IOManager_t * pxIOManager )
- {
- uint8_t * pucBuffer = pxIOManager->pucCacheMem;
- FF_Buffer_t * pxBuffer = pxIOManager->pxBuffers;
- FF_Buffer_t * pxLastBuffer = pxBuffer + pxIOManager->usCacheSize;
- /* Clear the contents of the buffer descriptors. */
- memset( ( void * ) pxBuffer, '\0', sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize );
- while( pxBuffer < pxLastBuffer )
- {
- pxBuffer->pucBuffer = pucBuffer;
- pxBuffer++;
- pucBuffer += pxIOManager->usSectorSize;
- }
- } /* FF_IOMAN_InitBufferDescriptors() */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Flushes all Write cache buffers with no active Handles.
- *
- * @param pxIOManager IOMAN Object.
- *
- * @Return FF_ERR_NONE on Success.
- **/
- FF_Error_t FF_FlushCache( FF_IOManager_t * pxIOManager )
- {
- BaseType_t xIndex, xIndex2;
- FF_Error_t xError;
- if( pxIOManager == NULL )
- {
- xError = FF_ERR_NULL_POINTER | FF_FLUSHCACHE;
- }
- else
- {
- xError = FF_ERR_NONE;
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- {
- for( xIndex = 0; xIndex < pxIOManager->usCacheSize; xIndex++ )
- {
- /* If a buffers has no users and if it has been modified... */
- if( ( pxIOManager->pxBuffers[ xIndex ].usNumHandles == 0 ) && ( pxIOManager->pxBuffers[ xIndex ].bModified == pdTRUE ) )
- {
- /* The buffer may be flushed to disk. */
- FF_BlockWrite( pxIOManager, pxIOManager->pxBuffers[ xIndex ].ulSector, 1, pxIOManager->pxBuffers[ xIndex ].pucBuffer, pdTRUE );
- /* Buffer has now been flushed, mark it as a read buffer and unmodified. */
- pxIOManager->pxBuffers[ xIndex ].ucMode = FF_MODE_READ;
- pxIOManager->pxBuffers[ xIndex ].bModified = pdFALSE;
- /* Search for other buffers that used this sector, and mark them as modified
- * So that further requests will result in the new sector being fetched. */
- for( xIndex2 = 0; xIndex2 < pxIOManager->usCacheSize; xIndex2++ )
- {
- if( ( xIndex != xIndex2 ) &&
- ( pxIOManager->pxBuffers[ xIndex2 ].ulSector == pxIOManager->pxBuffers[ xIndex ].ulSector ) &&
- ( pxIOManager->pxBuffers[ xIndex2 ].ucMode == FF_MODE_READ ) )
- {
- pxIOManager->pxBuffers[ xIndex2 ].bModified = pdTRUE;
- }
- }
- }
- }
- }
- if( ( pxIOManager->xBlkDevice.pxDisk != NULL ) &&
- ( pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook != NULL ) )
- {
- /* Let the low-level driver also flush data.
- * See comments in ff_ioman.h. */
- pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook( pxIOManager->xBlkDevice.pxDisk );
- }
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- return xError;
- } /* FF_FlushCache() */
- /*-----------------------------------------------------------*/
- /*
- * A new version of FF_GetBuffer() with a simple mechanism for timeout
- */
- #define FF_GETBUFFER_SLEEP_TIME_MS 10
- #define FF_GETBUFFER_WAIT_TIME_MS ( 20000 / FF_GETBUFFER_SLEEP_TIME_MS )
- FF_Buffer_t * FF_GetBuffer( FF_IOManager_t * pxIOManager,
- uint32_t ulSector,
- uint8_t ucMode )
- {
- FF_Buffer_t * pxBuffer;
- /* Least Recently Used Buffer */
- FF_Buffer_t * pxRLUBuffer;
- FF_Buffer_t * pxMatchingBuffer = NULL;
- int32_t lRetVal;
- BaseType_t xLoopCount = FF_GETBUFFER_WAIT_TIME_MS;
- const FF_Buffer_t * pxLastBuffer = &( pxIOManager->pxBuffers[ pxIOManager->usCacheSize ] );
- /* 'pxIOManager->usCacheSize' is bigger than zero and it is a multiple of ulSectorSize. */
- while( pxMatchingBuffer == NULL )
- {
- xLoopCount--;
- if( xLoopCount == 0 )
- {
- break;
- }
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ )
- {
- if( ( pxBuffer->ulSector == ulSector ) && ( pxBuffer->bValid ) )
- {
- pxMatchingBuffer = pxBuffer;
- /* Don't look further if you found a perfect match. */
- break;
- }
- }
- if( pxMatchingBuffer != NULL )
- {
- /* A Match was found process! */
- if( ( ucMode == FF_MODE_READ ) && ( pxMatchingBuffer->ucMode == FF_MODE_READ ) )
- {
- pxMatchingBuffer->usNumHandles += 1;
- pxMatchingBuffer->usPersistance += 1;
- break;
- }
- if( pxMatchingBuffer->usNumHandles == 0 )
- {
- /* Copy the read & write flags. */
- pxMatchingBuffer->ucMode = ( ucMode & FF_MODE_RD_WR );
- if( ( ucMode & FF_MODE_WRITE ) != 0 )
- {
- /* This buffer has no attached handles. */
- pxMatchingBuffer->bModified = pdTRUE;
- }
- pxMatchingBuffer->usNumHandles = 1;
- pxMatchingBuffer->usPersistance += 1;
- break;
- }
- /* Sector is already in use in a different mode, keep yielding until its available! */
- pxMatchingBuffer = NULL;
- }
- else
- {
- /* There is no valid buffer now for the desired sector.
- * Find a free buffer and use it for that sector. */
- pxRLUBuffer = NULL;
- for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ )
- {
- if( pxBuffer->usNumHandles != 0 )
- {
- continue; /* Occupied */
- }
- pxBuffer->ulLRU += 1;
- if( ( pxRLUBuffer == NULL ) ||
- ( pxBuffer->ulLRU > pxRLUBuffer->ulLRU ) ||
- ( ( pxBuffer->ulLRU == pxRLUBuffer->ulLRU ) && ( pxBuffer->usPersistance > pxRLUBuffer->usPersistance ) ) )
- {
- pxRLUBuffer = pxBuffer;
- }
- }
- /* A free buffer with the highest value of 'ulLRU' was found: */
- if( pxRLUBuffer != NULL )
- {
- /* Process the suitable candidate. */
- if( pxRLUBuffer->bModified == pdTRUE )
- {
- /* Along with the pdTRUE parameter to indicate semaphore has been claimed already. */
- lRetVal = FF_BlockWrite( pxIOManager, pxRLUBuffer->ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE );
- if( lRetVal < 0 )
- {
- /* NULL will be returned because 'pxMatchingBuffer' is still NULL. */
- break;
- }
- }
- if( ucMode == FF_MODE_WR_ONLY )
- {
- memset( pxRLUBuffer->pucBuffer, '\0', pxIOManager->usSectorSize );
- }
- else
- {
- lRetVal = FF_BlockRead( pxIOManager, ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE );
- if( lRetVal < 0 )
- {
- /* 'pxMatchingBuffer' is NULL. */
- break;
- }
- }
- pxRLUBuffer->ucMode = ( ucMode & FF_MODE_RD_WR );
- pxRLUBuffer->usPersistance = 1;
- pxRLUBuffer->ulLRU = 0;
- pxRLUBuffer->usNumHandles = 1;
- pxRLUBuffer->ulSector = ulSector;
- pxRLUBuffer->bModified = ( ucMode & FF_MODE_WRITE ) != 0;
- pxRLUBuffer->bValid = pdTRUE;
- pxMatchingBuffer = pxRLUBuffer;
- break;
- } /* if( pxRLUBuffer != NULL ) */
- } /* else ( pxMatchingBuffer == NULL ) */
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- /* Better to go asleep to give low-priority task a chance to release buffer(s). */
- FF_BufferWait( pxIOManager, FF_GETBUFFER_SLEEP_TIME_MS );
- } /* while( pxMatchingBuffer == NULL ) */
- if( xLoopCount > 0 )
- {
- /* If xLoopCount is 0 here, the semaphore was not taken. */
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- if( pxMatchingBuffer == NULL )
- {
- FF_PRINTF( "FF_GetBuffer[0x%X]: failed mode 0x%X\n", ( unsigned ) ulSector, ( unsigned ) ucMode );
- }
- return pxMatchingBuffer; /* Return the Matched Buffer! */
- } /* FF_GetBuffer() */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Releases a buffer resource.
- *
- * @param pxIOManager Pointer to an FF_IOManager_t object.
- * @param pxBuffer Pointer to an FF_Buffer_t object.
- *
- **/
- FF_Error_t FF_ReleaseBuffer( FF_IOManager_t * pxIOManager,
- FF_Buffer_t * pxBuffer )
- {
- FF_Error_t xError = FF_ERR_NONE;
- /* Protect description changes with a semaphore. */
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- {
- #if ( ffconfigCACHE_WRITE_THROUGH != 0 )
- if( pxBuffer->bModified == pdTRUE )
- {
- xError = FF_BlockWrite( pxIOManager, pxBuffer->ulSector, 1, pxBuffer->pucBuffer, pdTRUE );
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Ensure if an error occurs its still possible to write the block again. */
- pxBuffer->bModified = pdFALSE;
- }
- }
- #endif /* if ( ffconfigCACHE_WRITE_THROUGH != 0 ) */
- configASSERT( pxBuffer->usNumHandles != 0 );
- if( pxBuffer->usNumHandles != 0 )
- {
- pxBuffer->usNumHandles--;
- }
- else
- {
- /*printf ("FF_ReleaseBuffer: buffer not claimed\n"); */
- }
- }
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- /* Notify tasks which may be waiting in FF_GetBuffer() */
- FF_BufferProceed( pxIOManager );
- return xError;
- } /* FF_ReleaseBuffer() */
- /*-----------------------------------------------------------*/
- /* New Interface for FreeRTOS+FAT to read blocks. */
- int32_t FF_BlockRead( FF_IOManager_t * pxIOManager,
- uint32_t ulSectorLBA,
- uint32_t ulNumSectors,
- void * pxBuffer,
- BaseType_t xSemLocked )
- {
- int32_t slRetVal = 0;
- if( pxIOManager->xPartition.ulTotalSectors != 0ul )
- {
- /* At some point while formatting a partition, ulTotalSectors might be unknown.
- * In that case this test will be skipped. */
- if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) )
- {
- slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD;
- }
- }
- if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpReadBlocks != NULL ) )
- {
- do
- {
- /* Make sure we don't execute a NULL. */
- if( ( xSemLocked == pdFALSE ) &&
- ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
- {
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- }
- slRetVal = pxIOManager->xBlkDevice.fnpReadBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk );
- if( ( xSemLocked == pdFALSE ) &&
- ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
- {
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY )
- {
- break;
- }
- FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS );
- } while( pdTRUE );
- }
- return slRetVal;
- } /* FF_BlockRead() */
- /*-----------------------------------------------------------*/
- int32_t FF_BlockWrite( FF_IOManager_t * pxIOManager,
- uint32_t ulSectorLBA,
- uint32_t ulNumSectors,
- void * pxBuffer,
- BaseType_t xSemLocked )
- {
- int32_t slRetVal = 0;
- if( pxIOManager->xPartition.ulTotalSectors != 0 )
- {
- /* At some point while formatting a partition, ulTotalSectors might be unknown.
- * In that case this test will be skipped. */
- if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) )
- {
- slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE;
- }
- }
- if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpWriteBlocks != NULL ) )
- {
- do
- { /* Make sure we don't execute a NULL. */
- if( ( xSemLocked == pdFALSE ) &&
- ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
- {
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- }
- slRetVal = pxIOManager->xBlkDevice.fnpWriteBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk );
- if( ( xSemLocked == pdFALSE ) &&
- ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
- {
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY )
- {
- break;
- }
- FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS );
- } while( pdTRUE );
- }
- return slRetVal;
- } /* FF_BlockWrite() */
- /*-----------------------------------------------------------*/
- /*
- * This global variable is a kind of expert option:
- * It may be set to one of these values: FF_T_FAT[12,16,32]
- * just to force the driver to assume a certain FAT type.
- */
- uint8_t ucAssumeFATType;
- /* The history of FAT types:
- * The Microsoft documents says that the actual type: FAT-12, FAT-16 and FAT-32
- * of a partition can be found by looking at the total number of data clusters:
- *
- * if( clusters < 4085 )
- * Assume FAT-12
- * else if( clusters < 65525 )
- * Assume FAT-16
- * else
- * Assume FAT-32
- *
- * In practice however, this does not always seem to be a correct assumption.
- *
- * The first 12 or 16 bits in the FAT table may also help to determine the
- * correct FAT-type:
- *
- * FAT-12: ( firstWord & 0x3FF ) == 0x3F8 )
- * FAT-16: ( firstWord == 0xFFF8 )
- */
- static FF_Error_t prvDetermineFatType( FF_IOManager_t * pxIOManager )
- {
- FF_Partition_t * pxPartition;
- FF_Buffer_t * pxBuffer;
- uint32_t ulFirstWord = 0ul;
- FF_Error_t xError = FF_ERR_NONE;
- pxPartition = &( pxIOManager->xPartition );
- if( ucAssumeFATType != 0 )
- {
- switch( ucAssumeFATType )
- {
- case FF_T_FAT12:
- case FF_T_FAT16:
- case FF_T_FAT32:
- pxPartition->ucType = ucAssumeFATType;
- break;
- default:
- /* An invalid value will be ignored, and the FAT type is determined dynamically. */
- ucAssumeFATType = 0;
- break;
- }
- xError = FF_ERR_NONE;
- }
- /* Test again, the value may have become zero now: */
- if( ucAssumeFATType == 0 )
- {
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE;
- }
- else
- {
- ulFirstWord = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, 0x0000 );
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- }
- }
- if( ( ucAssumeFATType == 0 ) && ( FF_isERR( xError ) == pdFALSE ) )
- {
- #if ( ffconfigFAT12_SUPPORT != 0 )
- if( pxPartition->ulNumClusters < FAT16_SECTOR_COUNT_4085 )
- {
- /* FAT12 */
- pxPartition->ucType = FF_T_FAT12;
- #if ( ffconfigFAT_CHECK != 0 )
- if( ( ulFirstWord & 0x3FF ) != 0x3F8 )
- {
- xError = FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE;
- }
- else
- #endif /* ffconfigFAT_CHECK */
- {
- xError = FF_ERR_NONE;
- }
- }
- else
- #endif /* ffconfigFAT12_SUPPORT */
- if( pxPartition->ulNumClusters < FAT32_SECTOR_COUNT_65525 )
- {
- /* FAT 16 */
- pxPartition->ucType = FF_T_FAT16;
- #if ( ffconfigFAT_CHECK != 0 )
- {
- if( ulFirstWord == 0xFFF8 )
- {
- xError = FF_ERR_NONE;
- }
- else
- {
- if( ( ulFirstWord & 0x3FF ) != 0x3F8 )
- {
- FF_PRINTF( "Part at %lu is probably a FAT12\n", pxIOManager->xPartition.ulFATBeginLBA );
- }
- else
- {
- FF_PRINTF( "Partition at %lu has strange FAT data %08lX\n",
- pxIOManager->xPartition.ulFATBeginLBA, ulFirstWord );
- }
- xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_DETERMINEFATTYPE;
- }
- }
- #endif /* ffconfigFAT_CHECK */
- }
- else
- {
- /* FAT 32! */
- pxPartition->ucType = FF_T_FAT32;
- #if ( ffconfigFAT_CHECK != 0 )
- if( ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF8 ) &&
- ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF0 ) )
- {
- /* _HT_
- * I had an SD-card which worked well in Linux/W32
- * but FreeRTOS+FAT returned me this error
- * So for me I left out this check (just issue a warning for now)
- */
- FF_PRINTF( "prvDetermineFatType: firstWord %08lX\n", ulFirstWord );
- xError = FF_ERR_NONE; /* FF_ERR_IOMAN_NOT_FAT_FORMATTED; */
- }
- #endif /* ffconfigFAT_CHECK */
- xError = FF_ERR_NONE;
- }
- }
- return xError;
- } /* prvDetermineFatType() */
- /*-----------------------------------------------------------*/
- /* Check if ucPartitionID introduces an extended partition. */
- static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID )
- {
- BaseType_t xResult;
- if( ( ucPartitionID == FF_DOS_EXT_PART ) ||
- ( ucPartitionID == FF_WIN98_EXT_PART ) ||
- ( ucPartitionID == FF_LINUX_EXT_PART ) )
- {
- xResult = pdTRUE;
- }
- else
- {
- xResult = pdFALSE;
- }
- return xResult;
- } /* prvIsExtendedPartition() */
- /*-----------------------------------------------------------*/
- /* Check if the media byte in an MBR is valid */
- static BaseType_t prvIsValidMedia( uint8_t media )
- {
- BaseType_t xResult;
- /*
- * 0xF8 is the standard value for “fixed” (non-removable) media. For
- * removable media, 0xF0 is frequently used. The legal values for this
- * field are 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, and
- * 0xFF. The only other important point is that whatever value is put
- * in here must also be put in the low byte of the FAT[0] entry. This
- * dates back to the old MS-DOS 1.x media determination noted
- * earlier and is no longer usually used for anything.
- */
- if( ( 0xf8 <= media ) || ( media == 0xf0 ) )
- {
- xResult = pdTRUE;
- }
- else
- {
- xResult = pdFALSE;
- }
- return xResult;
- } /* prvIsValidMedia() */
- /*-----------------------------------------------------------*/
- void FF_ReadParts( uint8_t * pucBuffer,
- FF_Part_t * pxParts )
- {
- BaseType_t xPartNr;
- UBaseType_t uxOffset = FF_FAT_PTBL;
- /* pxParts is expected to be declared as an array of 4 elements:
- * FF_Part_t pxParts[4];
- * FF_ReadParts( pxBuffer->pucBuffer, pxParts );
- */
- for( xPartNr = 0; xPartNr < 4; xPartNr++, uxOffset += 16, pxParts++ )
- {
- pxParts->ucActive = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ACTIVE );
- pxParts->ucPartitionID = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ID );
- pxParts->ulSectorCount = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_SECT_COUNT );
- pxParts->ulStartLBA = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_LBA );
- }
- }
- /*-----------------------------------------------------------*/
- /* This function will traverse through a chain of extended partitions. */
- /* It is protected against rubbish data by a counter. */
- static FF_Error_t FF_ParseExtended( FF_IOManager_t * pxIOManager,
- uint32_t ulFirstSector,
- uint32_t ulFirstSize,
- FF_SPartFound_t * pPartsFound )
- {
- uint32_t ulThisSector, ulThisSize;
- uint32_t ulSectorSize = pxIOManager->usSectorSize / 512;
- uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors;
- FF_Buffer_t * pxBuffer = NULL;
- BaseType_t xTryCount = 100;
- BaseType_t xPartNr;
- BaseType_t xExtendedPartNr;
- FF_Error_t xError = FF_ERR_NONE;
- FF_Part_t pxPartitions[ 4 ];
- ulThisSector = ulFirstSector;
- ulThisSize = ulFirstSize;
- /* Disable sector checking in FF_BlockRead, because the
- * exact disk (partition) parameters are not yet known.
- * Let user driver return an error is appropriate. */
- pxIOManager->xPartition.ulTotalSectors = 0;
- while( xTryCount-- )
- {
- if( ( pxBuffer == NULL ) || ( pxBuffer->ulSector != ulThisSector ) )
- {
- /* Moving to a different sector. Release the
- * previous one and allocate a new buffer. */
- if( pxBuffer != NULL )
- {
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- pxBuffer = NULL;
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- FF_PRINTF( "FF_ParseExtended: Read sector %u\n", ( unsigned ) ulThisSector );
- pxBuffer = FF_GetBuffer( pxIOManager, ulThisSector, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = FF_PARSEEXTENDED | FF_ERR_DEVICE_DRIVER_FAILED; /* | FUNCTION...; */
- break;
- }
- }
- {
- uint8_t a = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 0 );
- uint8_t b = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 1 );
- if( ( a != 0x55 ) || ( b != 0xAA ) )
- {
- FF_PRINTF( "FF_ParseExtended: No signature %02X,%02X\n", a, b );
- break;
- }
- }
- /* Check for data partition(s),
- * and remember if there is an extended partition */
- FF_ReadParts( pxBuffer->pucBuffer, pxPartitions );
- /* Assume there is no next ext partition. */
- xExtendedPartNr = -1;
- for( xPartNr = 0; xPartNr < 4; xPartNr++ )
- {
- uint32_t ulOffset, ulSize, ulNext;
- if( pxPartitions[ xPartNr ].ulSectorCount == 0 )
- {
- /* Partition is empty */
- continue;
- }
- if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) )
- {
- if( xExtendedPartNr < 0 )
- {
- xExtendedPartNr = xPartNr;
- }
- continue; /* We'll examine this ext partition later */
- }
- /* Some sanity checks */
- ulOffset = pxPartitions[ xPartNr ].ulStartLBA * ulSectorSize;
- ulSize = pxPartitions[ xPartNr ].ulSectorCount * ulSectorSize;
- ulNext = ulThisSector + ulOffset;
- if(
- /* Is it oversized? */
- ( ulOffset + ulSize > ulThisSize ) ||
- /* or going backward? */
- ( ulNext < ulFirstSector ) ||
- /* Or outsize the logical partition? */
- ( ulNext > ulFirstSector + ulFirstSize )
- )
- {
- FF_PRINTF( "Part %d looks insane: ulThisSector %u ulOffset %u ulNext %u\n",
- ( int ) xPartNr, ( unsigned ) ulThisSector, ( unsigned ) ulOffset, ( unsigned ) ulNext );
- continue;
- }
- {
- /* Store this partition for the caller */
- FF_Part_t * p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ];
- /* Copy the whole structure */
- memcpy( p, pxPartitions + xPartNr, sizeof( *p ) );
- /* and make LBA absolute to sector-0. */
- p->ulStartLBA += ulThisSector;
- p->bIsExtended = pdTRUE;
- }
- if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS )
- {
- break;
- }
- xTryCount = 100;
- } /* for( xPartNr = 0; xPartNr < 4; xPartNr++ ) */
- if( xExtendedPartNr < 0 )
- {
- FF_PRINTF( "No more extended partitions\n" );
- break; /* nothing left to do */
- }
- /* Examine the ulNext extended partition */
- ulThisSector = ulFirstSector + pxPartitions[ xExtendedPartNr ].ulStartLBA * ulSectorSize;
- ulThisSize = pxPartitions[ xExtendedPartNr ].ulSectorCount * ulSectorSize;
- }
- if( pxBuffer != NULL )
- {
- FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- pxIOManager->xPartition.ulTotalSectors = prevTotalSectors;
- return xError;
- } /* FF_ParseExtended() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Searches a disk for all primary and extended/logical partitions
- * @brief Previously called FF_PartitionCount
- *
- * @param pxIOManager FF_IOManager_t object.
- * @param pPartsFound Contains an array of ffconfigMAX_PARTITIONS partitions
- *
- * @Return >=0 Number of partitions found
- * @Return <0 error
- **/
- FF_Error_t FF_PartitionSearch( FF_IOManager_t * pxIOManager,
- FF_SPartFound_t * pPartsFound )
- {
- BaseType_t xPartNr;
- FF_Buffer_t * pxBuffer;
- uint8_t * ucDataBuffer;
- BaseType_t isPBR = pdFALSE;
- FF_Error_t xError = FF_ERR_NONE;
- uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors;
- FF_Part_t pxPartitions[ 4 ];
- memset( pPartsFound, '\0', sizeof( *pPartsFound ) );
- do
- {
- pxBuffer = FF_GetBuffer( pxIOManager, 0, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_PARTITIONSEARCH;
- break;
- }
- /* Disable sector checking in FF_BlockRead
- * Let user driver return an error is appropriate. */
- pxIOManager->xPartition.ulTotalSectors = 0;
- ucDataBuffer = pxBuffer->pucBuffer;
- /* Check MBR (Master Boot Record) or
- * PBR (Partition Boot Record) signature. */
- if( ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ) != 0x55 ) ||
- ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE + 1 ) != 0xAA ) )
- {
- /* No MBR, but is it a PBR ?
- * Partition Boot Record */
- if( ( FF_getChar( ucDataBuffer, 0 ) == 0xEB ) && /* PBR Byte 0 */
- ( FF_getChar( ucDataBuffer, 2 ) == 0x90 ) )
- {
- /* PBR Byte 2
- * No MBR but PBR exist then there is only one partition
- * Handle this later. */
- isPBR = pdTRUE;
- }
- else
- {
- FF_PRINTF( "FF_PartitionSearch: [%02X,%02X] No signature (%02X %02X), no PBR neither\n",
- FF_getChar( ucDataBuffer, 0 ),
- FF_getChar( ucDataBuffer, 2 ),
- FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ),
- FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE + 1 ) );
- /* No MBR and no PBR then no partition found. */
- xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH;
- break;
- }
- }
- /* Copy the 4 partition records into 'pxPartitions': */
- FF_ReadParts( ucDataBuffer, pxPartitions );
- for( xPartNr = 0; ( xPartNr < 4 ) && ( isPBR == pdFALSE ); xPartNr++ )
- {
- /* FF_PRINTF ("FF_Part[%d]: id %02X act %02X Start %6lu Len %6lu (sectors)\n", */
- /* xPartNr, pxPartitions[ xPartNr ].ucPartitionID, */
- /* pxPartitions[ xPartNr ].ucActive, */
- /* pxPartitions[ xPartNr ].ulStartLBA, */
- /* pxPartitions[ xPartNr ].ulSectorCount); */
- if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) != pdFALSE )
- {
- continue; /* Do this later */
- }
- /* The first sector must be a MBR, then check the partition entry in the MBR */
- if( ( pxPartitions[ xPartNr ].ucActive != 0x80 ) &&
- ( pxPartitions[ xPartNr ].ucActive != 0x00 ) )
- {
- if( ( xPartNr == 0 ) &&
- ( FF_getShort( ucDataBuffer, FF_FAT_RESERVED_SECTORS ) != 0 ) &&
- ( FF_getChar( ucDataBuffer, FF_FAT_NUMBER_OF_FATS ) != 0 ) )
- {
- isPBR = pdTRUE;
- }
- else
- {
- xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH;
- break;
- }
- }
- else if( pxPartitions[ xPartNr ].ulSectorCount )
- {
- FF_Part_t * p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ];
- *p = pxPartitions[ xPartNr ];
- p->bIsExtended = 0;
- if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS )
- {
- break;
- }
- }
- }
- if( FF_isERR( xError ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) )
- {
- break;
- }
- for( xPartNr = 0; xPartNr < 4; xPartNr++ )
- {
- if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) )
- {
- xError = FF_ParseExtended( pxIOManager, pxPartitions[ xPartNr ].ulStartLBA,
- pxPartitions[ xPartNr ].ulSectorCount, pPartsFound );
- if( ( FF_isERR( xError ) != pdFALSE ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) )
- {
- goto done;
- }
- }
- }
- if( pPartsFound->iCount == 0 )
- {
- FF_PRINTF( "FF_Part: no partitions, try as PBR\n" );
- isPBR = pdTRUE;
- }
- if( isPBR )
- {
- uint8_t media = FF_getChar( ucDataBuffer, FF_FAT_MEDIA_TYPE );
- FF_Part_t * p;
- if( !prvIsValidMedia( media ) )
- {
- FF_PRINTF( "FF_Part: Looks like PBR but media %02X\n", media );
- xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_PARTITIONSEARCH;
- goto done;
- }
- /* This looks like a PBR because it has a valid media type */
- p = pPartsFound->pxPartitions;
- p->ulStartLBA = 0; /* FF_FAT_PTBL_LBA */
- p->ulSectorCount = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS );
- if( p->ulSectorCount == 0ul )
- {
- p->ulSectorCount = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS );
- }
- p->ucActive = 0x80; /* FF_FAT_PTBL_ACTIVE */
- p->ucPartitionID = 0x0B; /* FF_FAT_PTBL_ID MSDOS data partition */
- p->bIsExtended = 0;
- pPartsFound->iCount = 1;
- }
- } while( pdFALSE );
- done:
- if( pxBuffer )
- {
- FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- pxIOManager->xPartition.ulTotalSectors = prevTotalSectors;
- return FF_isERR( xError ) ? xError : pPartsFound->iCount;
- } /* FF_PartitionSearch() */
- /*-----------------------------------------------------------*/
- /*
- * Mount GPT Partition Tables
- */
- #define FF_GPT_HEAD_ENTRY_SIZE 0x54
- #define FF_GPT_HEAD_TOTAL_ENTRIES 0x50
- #define FF_GPT_HEAD_PART_ENTRY_LBA 0x48
- #define FF_GPT_ENTRY_FIRST_SECTOR_LBA 0x20
- #define FF_GPT_HEAD_CRC 0x10
- #define FF_GPT_HEAD_LENGTH 0x0C
- static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t * pxIOManager,
- uint32_t ulPartitionNumber )
- {
- /* Continuing on from FF_Mount() pPartition->ulBeginLBA should be the sector of the GPT Header */
- FF_Buffer_t * pxBuffer;
- FF_Partition_t * pxPartition = &( pxIOManager->xPartition );
- uint32_t ulBeginGPT;
- uint32_t ulEntrySector;
- uint32_t ulSectorOffset;
- uint32_t ulPartitionEntrySize;
- uint32_t ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength;
- FF_Error_t xError;
- do
- {
- if( ulPartitionNumber >= 128 )
- {
- xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY;
- break;
- }
- pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY;
- break;
- }
- /* Verify this is an EFI header with the text "EFI PART": */
- if( memcmp( pxBuffer->pucBuffer, "EFI PART", 8 ) != 0 )
- {
- /* Already returning an error, but this error would override the current one. */
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_GETEFIPARTITIONENTRY;
- }
- break;
- }
- ulBeginGPT = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_PART_ENTRY_LBA );
- ulPartitionEntrySize = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_ENTRY_SIZE );
- ulGPTHeadCRC = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC );
- ulGPTHeadLength = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_LENGTH );
- /* Calculate Head CRC */
- /* Blank CRC field */
- FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, 0x00000000 );
- /* Calculate CRC */
- ulGPTCrcCheck = FF_GetCRC32( pxBuffer->pucBuffer, ulGPTHeadLength );
- /* Restore The CRC field */
- FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC );
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) )
- {
- break;
- }
- /* Check CRC */
- if( ulGPTHeadCRC != ulGPTCrcCheck )
- {
- xError = FF_ERR_IOMAN_GPT_HEADER_CORRUPT | FF_GETEFIPARTITIONENTRY;
- break;
- }
- /* Calculate Sector Containing the Partition Entry we want to use. */
- ulEntrySector = ( ( ulPartitionNumber * ulPartitionEntrySize ) / pxIOManager->usSectorSize ) + ulBeginGPT;
- ulSectorOffset = ( ulPartitionNumber % ( pxIOManager->usSectorSize / ulPartitionEntrySize ) ) * ulPartitionEntrySize;
- pxBuffer = FF_GetBuffer( pxIOManager, ulEntrySector, FF_MODE_READ );
- {
- if( pxBuffer == NULL )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY;
- break;
- }
- pxPartition->ulBeginLBA = FF_getLong( pxBuffer->pucBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA );
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( pxPartition->ulBeginLBA == 0ul )
- {
- xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY;
- }
- }
- }
- while( pdFALSE );
- return xError;
- } /* FF_GetEfiPartitionEntry() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Mounts the Specified partition, the volume specified by the FF_IOManager_t object provided.
- *
- * The device drivers must adhere to the specification provided by
- * FF_WriteBlocks_t and FF_ReadBlocks_t.
- *
- * @param pxIOManager FF_IOManager_t object.
- * @param PartitionNumber The primary or logical partition number to be mounted,
- * ranging between 0 and ffconfigMAX_PARTITIONS-1 (normally 0)
- * Note that FF_PartitionSearch can be called in advance to
- * enumerate all available partitions
- *
- * @Return 0 on success.
- * @Return FF_ERR_NULL_POINTER if a pxIOManager object wasn't provided.
- * @Return FF_ERR_IOMAN_INVALID_PARTITION_NUM if the partition number is out of range.
- * @Return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION if no partition was found.
- * @Return FF_ERR_IOMAN_INVALID_FORMAT if the master boot record or partition boot block didn't provide sensible data.
- * @Return FF_ERR_IOMAN_NOT_FAT_FORMATTED if the volume or partition couldn't be determined to be FAT. (@see FreeRTOSFATConfig.h)
- *
- **/
- FF_Error_t FF_Mount( FF_Disk_t * pxDisk,
- BaseType_t xPartitionNumber )
- {
- FF_Partition_t * pxPartition;
- FF_Buffer_t * pxBuffer = 0;
- FF_Error_t xError = FF_ERR_NONE;
- int16_t rootEntryCount;
- FF_IOManager_t * pxIOManager = pxDisk->pxIOManager;
- /* HT TODO: find a method to safely determine the FAT type: 32/16/12 */
- /* other than only counting Clusters */
- /* UBaseType_t fat32Indicator = 0; */
- FF_Part_t * pxMyPartition;
- #if ( ffconfigHASH_CACHE != 0 )
- BaseType_t i;
- #endif
- FF_Error_t xPartitionCount = 0;
- FF_SPartFound_t partsFound;
- partsFound.iCount = 0;
- do
- {
- if( pxIOManager == NULL )
- {
- xError = FF_ERR_NULL_POINTER | FF_MOUNT;
- break;
- }
- pxPartition = &( pxIOManager->xPartition );
- #if ( ffconfigREMOVABLE_MEDIA != 0 )
- {
- pxIOManager->ucFlags &= ( uint8_t ) ( ~( FF_IOMAN_DEVICE_IS_EXTRACTED ) );
- }
- #endif /* ffconfigREMOVABLE_MEDIA */
- /* FF_IOMAN_InitBufferDescriptors will clear 'pxBuffers' */
- memset( pxIOManager->pucCacheMem, '\0', ( size_t ) pxIOManager->usSectorSize * pxIOManager->usCacheSize );
- #if ( ffconfigHASH_CACHE != 0 )
- {
- memset( pxIOManager->xHashCache, '\0', sizeof( pxIOManager->xHashCache ) );
- for( i = 0; i < ffconfigHASH_CACHE_DEPTH; i++ )
- {
- /* _HT_ Check why did JW put it to 100? */
- pxIOManager->xHashCache[ i ].ulMisses = 100;
- }
- }
- #endif
- #if ( ffconfigPATH_CACHE != 0 )
- {
- memset( pxPartition->pxPathCache, '\0', sizeof( pxPartition->pxPathCache ) );
- }
- #endif
- FF_IOMAN_InitBufferDescriptors( pxIOManager );
- pxIOManager->FirstFile = 0;
- xPartitionCount = FF_PartitionSearch( pxIOManager, &partsFound );
- if( FF_isERR( xPartitionCount ) )
- {
- xError = xPartitionCount;
- break;
- }
- if( xPartitionCount == 0 )
- {
- xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_MOUNT;
- break;
- }
- if( xPartitionNumber >= xPartitionCount )
- {
- xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MOUNT;
- break;
- }
- pxMyPartition = &( partsFound.pxPartitions[ xPartitionNumber ] );
- pxPartition->ulBeginLBA = pxMyPartition->ulStartLBA;
- if( pxMyPartition->ucPartitionID == 0xEE )
- {
- xError = FF_GetEfiPartitionEntry( pxIOManager, xPartitionNumber );
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- /* Now we get the Partition sector. */
- pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNT;
- break;
- }
- pxPartition->usBlkSize = FF_getShort( pxBuffer->pucBuffer, FF_FAT_BYTES_PER_SECTOR );
- if( ( ( pxPartition->usBlkSize % 512 ) != 0 ) || ( pxPartition->usBlkSize == 0 ) )
- {
- /* An error here should override the current error, as its likely fatal. */
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
- }
- break;
- }
- /* Assume FAT16, then we'll adjust if its FAT32 */
- pxPartition->usReservedSectors = FF_getShort( pxBuffer->pucBuffer, FF_FAT_RESERVED_SECTORS );
- pxPartition->ulFATBeginLBA = pxPartition->ulBeginLBA + pxPartition->usReservedSectors;
- pxPartition->ucNumFATS = ( uint8_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_NUMBER_OF_FATS );
- pxPartition->ulSectorsPerFAT = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_SECTORS_PER_FAT );
- pxPartition->ulSectorsPerCluster = FF_getChar( pxBuffer->pucBuffer, FF_FAT_SECTORS_PER_CLUS );
- /* Set the BlockFactor (How many real-blocks in a fake block!). */
- pxPartition->ucBlkFactor = ( uint8_t ) ( pxPartition->usBlkSize / pxIOManager->usSectorSize );
- pxPartition->ulTotalSectors = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS );
- if( pxPartition->ulTotalSectors == 0 )
- {
- pxPartition->ulTotalSectors = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS );
- }
- if( pxPartition->ulSectorsPerFAT == 0 )
- { /* FAT32 */
- pxPartition->ulSectorsPerFAT = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_SECTORS_PER_FAT );
- pxPartition->ulRootDirCluster = FF_getLong( pxBuffer->pucBuffer, FF_FAT_ROOT_DIR_CLUSTER );
- memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_32_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1 );
- }
- else
- { /* FAT16 */
- pxPartition->ulRootDirCluster = 1; /* 1st Cluster is RootDir! */
- memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_16_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1 );
- }
- pxPartition->ulClusterBeginLBA = pxPartition->ulFATBeginLBA + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT );
- #if ( ffconfigWRITE_FREE_COUNT != 0 )
- {
- pxPartition->ulFSInfoLBA = pxPartition->ulBeginLBA + FF_getShort( pxBuffer->pucBuffer, 48 );
- }
- #endif
- FF_ReleaseBuffer( pxIOManager, pxBuffer ); /* Release the buffer finally! */
- if( pxPartition->usBlkSize == 0 )
- {
- xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
- break;
- }
- rootEntryCount = FF_getShort( pxBuffer->pucBuffer, FF_FAT_ROOT_ENTRY_COUNT );
- pxPartition->ulRootDirSectors = ( ( rootEntryCount * 32 ) + pxPartition->usBlkSize - 1 ) / pxPartition->usBlkSize;
- pxPartition->ulFirstDataSector = pxPartition->ulClusterBeginLBA + pxPartition->ulRootDirSectors;
- pxPartition->ulDataSectors = pxPartition->ulTotalSectors - ( pxPartition->usReservedSectors + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT ) + pxPartition->ulRootDirSectors );
- /*
- * HT: fat32Indicator not yet used
- * As there is so much confusion about the FAT types
- * I was thinking of collecting indications for either FAT12, 16 or 32
- */
- /*
- * if( FF_getShort( pxBuffer->pucBuffer, FF_FAT_EXT_BOOT_SIGNATURE ) == 0x29 )
- * fat32Indicator++;
- * if( rootEntryCount == 0 )
- * fat32Indicator++;
- */
- if( pxPartition->ulSectorsPerCluster == 0 )
- {
- xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
- break;
- }
- pxPartition->ulNumClusters = pxPartition->ulDataSectors / pxPartition->ulSectorsPerCluster;
- xError = prvDetermineFatType( pxIOManager );
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( !rootEntryCount && ( pxPartition->ucType != FF_T_FAT32 ) )
- {
- FF_PRINTF( "No root dir, must be a FAT32\n" );
- pxPartition->ucType = FF_T_FAT32;
- }
- pxPartition->ucPartitionMounted = pdTRUE;
- pxPartition->ulLastFreeCluster = 0;
- #if ( ffconfigMOUNT_FIND_FREE != 0 )
- {
- FF_LockFAT( pxIOManager );
- {
- /* The parameter 'pdFALSE' means: do not claim the free cluster found. */
- pxPartition->ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
- }
- FF_UnlockFAT( pxIOManager );
- if( FF_isERR( xError ) )
- {
- if( FF_GETERROR( xError ) == FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE )
- {
- pxPartition->ulLastFreeCluster = 0;
- }
- else
- {
- break;
- }
- }
- pxPartition->ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- #else /* if ( ffconfigMOUNT_FIND_FREE != 0 ) */
- {
- pxPartition->ulFreeClusterCount = 0;
- }
- #endif /* ffconfigMOUNT_FIND_FREE */
- }
- while( pdFALSE );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = 0;
- }
- return xError;
- } /* FF_Mount() */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Checks the cache for Active Handles
- *
- * @param pxIOManager FF_IOManager_t Object.
- *
- * @Return pdTRUE if an active handle is found, else pdFALSE.
- *
- * @pre This function must be wrapped with the cache handling semaphore.
- **/
- static BaseType_t prvHasActiveHandles( FF_IOManager_t * pxIOManager )
- {
- BaseType_t xResult;
- FF_Buffer_t * pxBuffer = pxIOManager->pxBuffers;
- FF_Buffer_t * pxLastBuffer = pxBuffer + pxIOManager->usCacheSize;
- for( ; ; )
- {
- if( pxBuffer->usNumHandles )
- {
- xResult = pdTRUE;
- break;
- }
- pxBuffer++;
- if( pxBuffer == pxLastBuffer )
- {
- xResult = pdFALSE;
- break;
- }
- }
- return xResult;
- } /* prvHasActiveHandles() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Unmounts the active partition.
- *
- * @param pxIOManager FF_IOManager_t Object.
- *
- * @Return FF_ERR_NONE on success.
- **/
- FF_Error_t FF_Unmount( FF_Disk_t * pxDisk )
- {
- FF_Error_t xError = FF_ERR_NONE;
- FF_IOManager_t * pxIOManager;
- #if ( ffconfigMIRROR_FATS_UMOUNT != 0 )
- UBaseType_t uxIndex, y;
- FF_Buffer_t * pxBuffer;
- #endif
- if( pxDisk->pxIOManager == NULL )
- {
- xError = FF_ERR_NULL_POINTER | FF_UNMOUNT;
- }
- else if( pxDisk->pxIOManager->xPartition.ucPartitionMounted == 0 )
- {
- xError = FF_ERR_NONE;
- }
- else
- {
- pxIOManager = pxDisk->pxIOManager;
- FF_PendSemaphore( pxIOManager->pvSemaphore ); /* Ensure that there are no File Handles */
- {
- if( prvHasActiveHandles( pxIOManager ) != 0 )
- {
- /* Active handles found on the cache. */
- xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT;
- }
- else if( pxIOManager->FirstFile != NULL )
- {
- /* Open files in this partition. */
- xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT;
- }
- else
- {
- /* Release Semaphore to call this function! */
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- /* Flush any unwritten sectors to disk. */
- xError = FF_FlushCache( pxIOManager );
- /* Reclaim Semaphore */
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- if( FF_isERR( xError ) == pdFALSE )
- {
- pxIOManager->xPartition.ucPartitionMounted = pdFALSE;
- #if ( ffconfigMIRROR_FATS_UMOUNT != 0 )
- {
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- for( uxIndex = 0; uxIndex < pxIOManager->xPartition.ulSectorsPerFAT; uxIndex++ )
- {
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + uxIndex, FF_MODE_READ );
- if( !pxBuffer )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_UNMOUNT;
- break;
- }
- for( y = 0; y < pxIOManager->xPartition.ucNumFATS; y++ )
- {
- FF_BlockWrite( pxIOManager,
- pxIOManager->xPartition.ulFATBeginLBA + ( y * pxIOManager->xPartition.ulSectorsPerFAT ) + uxIndex, 1,
- pxBuffer->pucBuffer, pdFALSE );
- }
- }
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- }
- #endif /* if ( ffconfigMIRROR_FATS_UMOUNT != 0 ) */
- }
- }
- }
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- return xError;
- } /* FF_Unmount() */
- /*-----------------------------------------------------------*/
- FF_Error_t FF_IncreaseFreeClusters( FF_IOManager_t * pxIOManager,
- uint32_t Count )
- {
- FF_Error_t xError;
- #if ( ffconfigWRITE_FREE_COUNT != 0 )
- FF_Buffer_t * pxBuffer;
- #endif
- do
- {
- /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */
- if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
- {
- /* Apparently the number of free clusters has not been calculated yet,
- * or no free cluster was available. Now check it. */
- pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- else
- {
- xError = FF_ERR_NONE;
- taskENTER_CRITICAL();
- {
- pxIOManager->xPartition.ulFreeClusterCount += Count;
- }
- taskEXIT_CRITICAL();
- }
- if( pxIOManager->xPartition.ulLastFreeCluster == 0 )
- {
- BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
- if( xTakeLock )
- {
- FF_LockFAT( pxIOManager );
- }
- /* Find the an available cluster. */
- pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
- if( xTakeLock )
- {
- FF_UnlockFAT( pxIOManager );
- }
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- #if ( ffconfigWRITE_FREE_COUNT != 0 )
- {
- /* FAT32 updates the FSINFO sector. */
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- /* Find the FSINFO sector. */
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE );
- if( pxBuffer == NULL )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_INCREASEFREECLUSTERS;
- }
- else
- {
- uint32_t ulSignature1;
- uint32_t ulSignature2;
- ulSignature1 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 );
- ulSignature2 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 );
- if( ( ulSignature1 == FS_INFO_SIGNATURE1_0x41615252 ) &&
- ( ulSignature2 == FS_INFO_SIGNATURE2_0x61417272 ) )
- {
- /* FSINFO sector magic numbers we're verified. Safe to write. */
- FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount );
- FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster );
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- }
- }
- }
- #endif /* if ( ffconfigWRITE_FREE_COUNT != 0 ) */
- }
- while( pdFALSE );
- return xError;
- } /* FF_IncreaseFreeClusters() */
- /*-----------------------------------------------------------*/
- FF_Error_t FF_DecreaseFreeClusters( FF_IOManager_t * pxIOManager,
- uint32_t Count )
- {
- FF_Error_t xError = FF_ERR_NONE;
- #if ( ffconfigWRITE_FREE_COUNT != 0 )
- FF_Buffer_t * pxBuffer;
- #endif
- if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
- {
- pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
- }
- else
- {
- taskENTER_CRITICAL();
- pxIOManager->xPartition.ulFreeClusterCount -= Count;
- taskEXIT_CRITICAL();
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( pxIOManager->xPartition.ulLastFreeCluster == 0 )
- {
- FF_LockFAT( pxIOManager );
- {
- pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
- }
- FF_UnlockFAT( pxIOManager );
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- #if ( ffconfigWRITE_FREE_COUNT != 0 )
- {
- /* FAT32 update the FSINFO sector. */
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- /* Find the FSINFO sector. */
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE );
- if( pxBuffer == NULL )
- {
- xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DECREASEFREECLUSTERS;
- }
- else
- {
- if( ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 ) == FS_INFO_SIGNATURE1_0x41615252 ) &&
- ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 ) == FS_INFO_SIGNATURE2_0x61417272 ) )
- {
- /* FSINFO sector magic nums we're verified. Safe to write. */
- FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount );
- FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster );
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- }
- }
- }
- #endif /* if ( ffconfigWRITE_FREE_COUNT != 0 ) */
- }
- return xError;
- } /* FF_DecreaseFreeClusters() */
- /*-----------------------------------------------------------*/
- /**
- * @brief Returns the Block-size of a mounted Partition
- *
- * The purpose of this function is to provide API access to information
- * that might be useful in special cases. Like USB sticks that require a sector
- * knocking sequence for security. After the sector knock, some secure USB
- * sticks then present a different BlockSize.
- *
- * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger()
- *
- * @Return The blocksize of the partition. A value less than 0 when an error occurs.
- * @Return Any negative value can be cast to the FF_Error_t type.
- **/
- int32_t FF_GetPartitionBlockSize( FF_IOManager_t * pxIOManager )
- {
- int32_t lReturn;
- if( pxIOManager )
- {
- lReturn = ( int32_t ) pxIOManager->xPartition.usBlkSize;
- }
- else
- {
- lReturn = FF_ERR_NULL_POINTER | FF_GETPARTITIONBLOCKSIZE;
- }
- return lReturn;
- } /* FF_GetPartitionBlockSize() */
- /*-----------------------------------------------------------*/
- #if ( ffconfig64_NUM_SUPPORT != 0 )
- /**
- * @brief Returns the number of bytes contained within the mounted partition or volume.
- *
- * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger()
- *
- * @Return The total number of bytes that the mounted partition or volume contains.
- *
- **/
- uint64_t FF_GetVolumeSize( FF_IOManager_t * pxIOManager )
- {
- uint64_t ullResult;
- if( pxIOManager )
- {
- uint32_t TotalClusters = ( pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster );
- ullResult = ( uint64_t )
- (
- ( uint64_t ) TotalClusters * ( uint64_t )
- ( ( uint64_t ) pxIOManager->xPartition.ulSectorsPerCluster * ( uint64_t ) pxIOManager->xPartition.usBlkSize )
- );
- }
- else
- {
- ullResult = 0ULL;
- }
- return ullResult;
- } /* FF_GetVolumeSize() */
- #else /* if ( ffconfig64_NUM_SUPPORT != 0 ) */
- uint32_t FF_GetVolumeSize( FF_IOManager_t * pxIOManager )
- {
- uint32_t ulResult;
- if( pxIOManager )
- {
- uint32_t TotalClusters = pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster;
- ulResult = ( uint32_t ) ( TotalClusters * ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->xPartition.usBlkSize ) );
- }
- else
- {
- ulResult = 0UL;
- }
- return ulResult;
- } /* FF_GetVolumeSize() */
- #endif /* if ( ffconfig64_NUM_SUPPORT != 0 ) */
- /*-----------------------------------------------------------*/
|