ff_ioman.c 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971
  1. /*
  2. * FreeRTOS+FAT V2.3.3
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * https://www.FreeRTOS.org
  23. * https://github.com/FreeRTOS
  24. *
  25. */
  26. /**
  27. * @file ff_ioman.c
  28. * @ingroup IOMAN
  29. *
  30. * @defgroup IOMAN I/O Manager
  31. * @brief Handles IO buffers for FreeRTOS+FAT safely.
  32. *
  33. * Provides a simple static interface to the rest of FreeRTOS+FAT to manage
  34. * buffers. It also defines the public interfaces for Creating and
  35. * Destroying a FreeRTOS+FAT IO object.
  36. **/
  37. #include <time.h>
  38. #include <string.h>
  39. #include "ff_headers.h"
  40. #define FAT16_SECTOR_COUNT_4085 4085
  41. #define FAT32_SECTOR_COUNT_65525 65525 /* 65536 clusters */
  42. /* Some values and offsets describing the special sector FS INFO: */
  43. #define FS_INFO_SIGNATURE1_0x41615252 0x41615252UL
  44. #define FS_INFO_SIGNATURE2_0x61417272 0x61417272UL
  45. #define FS_INFO_OFFSET_SIGNATURE1_000 0
  46. #define FS_INFO_OFFSET_SIGNATURE2_484 484
  47. #define FS_INFO_OFFSET_FREE_COUNT_488 488
  48. #define FS_INFO_OFFSET_FREE_CLUSTER_492 492
  49. /* Inspect the PBR (Partition Boot Record) to determine the type of FAT */
  50. static FF_Error_t prvDetermineFatType( FF_IOManager_t * pxIOManager );
  51. /* Check if a given ID introduces an extended partition. */
  52. static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID );
  53. /* Return pdTRUE if the media byte in an MBR is valid. */
  54. static BaseType_t prvIsValidMedia( uint8_t media );
  55. /* Read the MBR to see what extended partitions have been defined.
  56. * Definitions of extended partitions may be chained.
  57. * Walk down the chain to find all extended partitions. */
  58. static FF_Error_t FF_ParseExtended( FF_IOManager_t * pxIOManager,
  59. uint32_t ulFirstSector,
  60. uint32_t ulFirstSize,
  61. FF_SPartFound_t * pPartsFound );
  62. static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t * pxIOManager,
  63. uint32_t ulPartitionNumber );
  64. static BaseType_t prvHasActiveHandles( FF_IOManager_t * pxIOManager );
  65. /**
  66. * @public
  67. * @brief Creates an FF_IOManager_t object, to initialise FreeRTOS+FAT
  68. *
  69. * @param pucCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc).
  70. * @param ulCacheSize The size of the provided buffer, or size of the cache to be created.
  71. * (Must be at least 2 * ulSectorSize). Always a multiple of ulSectorSize.
  72. * @param usSectorSize The block size of devices to be attached. If in doubt use 512.
  73. * @param pError Pointer to a signed byte for error checking. Can be NULL if not required.
  74. * To be checked when a NULL pointer is returned.
  75. *
  76. * @Return Returns a pointer to an FF_IOManager_t type object. NULL on xError, check the contents of
  77. * @Return pError
  78. **/
  79. FF_IOManager_t * FF_CreateIOManger( FF_CreationParameters_t * pxParameters,
  80. FF_Error_t * pError )
  81. {
  82. FF_IOManager_t * pxIOManager = NULL;
  83. FF_Error_t xError;
  84. uint32_t ulCacheSize = pxParameters->ulMemorySize;
  85. uint32_t usSectorSize = pxParameters->ulSectorSize;
  86. /* Normally:
  87. * ulSectorSize = 512
  88. * ulCacheSize = N x ulSectorSize. */
  89. if( ( ( usSectorSize % 512 ) != 0 ) || ( usSectorSize == 0 ) )
  90. {
  91. /* ulSectorSize Size not a multiple of 512 or it is zero*/
  92. xError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN;
  93. }
  94. else if( ( ( ulCacheSize % ( uint32_t ) usSectorSize ) != 0 ) || ( ulCacheSize == 0 ) ||
  95. ( ulCacheSize == ( uint32_t ) usSectorSize ) )
  96. {
  97. /* The size of the caching memory (ulCacheSize) must now be atleast 2 * ulSectorSize (or a deadlock will occur). */
  98. xError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN;
  99. }
  100. else
  101. {
  102. pxIOManager = ( FF_IOManager_t * ) ffconfigMALLOC( sizeof( FF_IOManager_t ) );
  103. /* Ensure malloc() succeeded. */
  104. if( pxIOManager != NULL )
  105. {
  106. /* Use memset() to clear every single bit. */
  107. memset( pxIOManager, '\0', sizeof( FF_IOManager_t ) );
  108. if( FF_CreateEvents( pxIOManager ) != pdFALSE )
  109. {
  110. xError = FF_ERR_NONE;
  111. }
  112. else
  113. {
  114. /* xEventGroupCreate() probably failed. */
  115. xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
  116. }
  117. }
  118. else
  119. {
  120. /* ffconfigMALLOC() failed. */
  121. xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
  122. }
  123. }
  124. if( FF_isERR( xError ) == pdFALSE )
  125. {
  126. /* pxIOManager is created, FF_CreateEvents() succeeded. */
  127. if( pxParameters->pucCacheMemory != NULL )
  128. {
  129. /* The caller has provided a piece of memory, use it. */
  130. pxIOManager->pucCacheMem = pxParameters->pucCacheMemory;
  131. }
  132. else
  133. {
  134. /* No cache buffer provided, call malloc(). */
  135. pxIOManager->pucCacheMem = ( uint8_t * ) ffconfigMALLOC( ulCacheSize );
  136. if( pxIOManager->pucCacheMem != NULL )
  137. {
  138. /* Indicate that malloc() was used for pucCacheMem. */
  139. pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFFERS;
  140. }
  141. else
  142. {
  143. xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
  144. }
  145. }
  146. if( pxIOManager->pucCacheMem != NULL )
  147. {
  148. memset( pxIOManager->pucCacheMem, '\0', ulCacheSize );
  149. }
  150. }
  151. if( FF_isERR( xError ) == pdFALSE )
  152. {
  153. pxIOManager->usSectorSize = usSectorSize;
  154. pxIOManager->usCacheSize = ( uint16_t ) ( ulCacheSize / ( uint32_t ) usSectorSize );
  155. /* Malloc() memory for buffer objects. FreeRTOS+FAT never refers to a
  156. * buffer directly but uses buffer objects instead. Allows for thread
  157. * safety. */
  158. pxIOManager->pxBuffers = ( FF_Buffer_t * ) ffconfigMALLOC( sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize );
  159. if( pxIOManager->pxBuffers != NULL )
  160. {
  161. /* From now on a call to FF_IOMAN_InitBufferDescriptors will clear
  162. * pxBuffers. */
  163. pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFDESCR;
  164. FF_IOMAN_InitBufferDescriptors( pxIOManager );
  165. /* Finally store the semaphore for Buffer Description modifications. */
  166. pxIOManager->pvSemaphore = pxParameters->pvSemaphore;
  167. if( pxParameters->xBlockDeviceIsReentrant != pdFALSE )
  168. {
  169. pxIOManager->ucFlags |= FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT;
  170. }
  171. pxIOManager->xBlkDevice.fnpReadBlocks = pxParameters->fnReadBlocks;
  172. pxIOManager->xBlkDevice.fnpWriteBlocks = pxParameters->fnWriteBlocks;
  173. pxIOManager->xBlkDevice.pxDisk = pxParameters->pxDisk;
  174. }
  175. else
  176. {
  177. xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
  178. }
  179. }
  180. if( FF_isERR( xError ) )
  181. {
  182. if( pxIOManager != NULL )
  183. {
  184. FF_DeleteIOManager( pxIOManager );
  185. pxIOManager = NULL;
  186. }
  187. }
  188. if( pError != NULL )
  189. {
  190. *pError = xError;
  191. }
  192. return pxIOManager;
  193. } /* FF_CreateIOManger() */
  194. /*-----------------------------------------------------------*/
  195. /**
  196. * @public
  197. * @brief Destroys an FF_IOManager_t object, and frees all assigned memory.
  198. *
  199. * @param pxIOManager Pointer to an FF_IOManager_t object, as returned from FF_CreateIOManger.
  200. *
  201. * @Return FF_ERR_NONE on sucess, or a documented error code on failure. (FF_ERR_NULL_POINTER)
  202. *
  203. **/
  204. FF_Error_t FF_DeleteIOManager( FF_IOManager_t * pxIOManager )
  205. {
  206. FF_Error_t xError;
  207. /* Ensure no NULL pointer was provided. */
  208. if( pxIOManager == NULL )
  209. {
  210. xError = FF_ERR_NULL_POINTER | FF_DESTROYIOMAN;
  211. }
  212. else
  213. {
  214. xError = FF_ERR_NONE;
  215. /* Ensure pxBuffers pointer was allocated. */
  216. if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFDESCR ) != 0 )
  217. {
  218. ffconfigFREE( pxIOManager->pxBuffers );
  219. }
  220. /* Ensure pucCacheMem pointer was allocated. */
  221. if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFFERS ) != 0 )
  222. {
  223. ffconfigFREE( pxIOManager->pucCacheMem );
  224. }
  225. /* Delete the event group object within the IO manager before deleting
  226. * the manager. */
  227. FF_DeleteEvents( pxIOManager );
  228. /* Finally free the FF_IOManager_t object. */
  229. ffconfigFREE( pxIOManager );
  230. }
  231. return xError;
  232. } /* FF_DeleteIOManager() */
  233. /*-----------------------------------------------------------*/
  234. /**
  235. * @private
  236. * @brief Initialises Buffer Descriptions as part of the FF_IOManager_t object initialisation.
  237. *
  238. * @param pxIOManager IOMAN Object.
  239. *
  240. **/
  241. void FF_IOMAN_InitBufferDescriptors( FF_IOManager_t * pxIOManager )
  242. {
  243. uint8_t * pucBuffer = pxIOManager->pucCacheMem;
  244. FF_Buffer_t * pxBuffer = pxIOManager->pxBuffers;
  245. FF_Buffer_t * pxLastBuffer = pxBuffer + pxIOManager->usCacheSize;
  246. /* Clear the contents of the buffer descriptors. */
  247. memset( ( void * ) pxBuffer, '\0', sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize );
  248. while( pxBuffer < pxLastBuffer )
  249. {
  250. pxBuffer->pucBuffer = pucBuffer;
  251. pxBuffer++;
  252. pucBuffer += pxIOManager->usSectorSize;
  253. }
  254. } /* FF_IOMAN_InitBufferDescriptors() */
  255. /*-----------------------------------------------------------*/
  256. /**
  257. * @private
  258. * @brief Flushes all Write cache buffers with no active Handles.
  259. *
  260. * @param pxIOManager IOMAN Object.
  261. *
  262. * @Return FF_ERR_NONE on Success.
  263. **/
  264. FF_Error_t FF_FlushCache( FF_IOManager_t * pxIOManager )
  265. {
  266. BaseType_t xIndex, xIndex2;
  267. FF_Error_t xError;
  268. if( pxIOManager == NULL )
  269. {
  270. xError = FF_ERR_NULL_POINTER | FF_FLUSHCACHE;
  271. }
  272. else
  273. {
  274. xError = FF_ERR_NONE;
  275. FF_PendSemaphore( pxIOManager->pvSemaphore );
  276. {
  277. for( xIndex = 0; xIndex < pxIOManager->usCacheSize; xIndex++ )
  278. {
  279. /* If a buffers has no users and if it has been modified... */
  280. if( ( pxIOManager->pxBuffers[ xIndex ].usNumHandles == 0 ) && ( pxIOManager->pxBuffers[ xIndex ].bModified == pdTRUE ) )
  281. {
  282. /* The buffer may be flushed to disk. */
  283. FF_BlockWrite( pxIOManager, pxIOManager->pxBuffers[ xIndex ].ulSector, 1, pxIOManager->pxBuffers[ xIndex ].pucBuffer, pdTRUE );
  284. /* Buffer has now been flushed, mark it as a read buffer and unmodified. */
  285. pxIOManager->pxBuffers[ xIndex ].ucMode = FF_MODE_READ;
  286. pxIOManager->pxBuffers[ xIndex ].bModified = pdFALSE;
  287. /* Search for other buffers that used this sector, and mark them as modified
  288. * So that further requests will result in the new sector being fetched. */
  289. for( xIndex2 = 0; xIndex2 < pxIOManager->usCacheSize; xIndex2++ )
  290. {
  291. if( ( xIndex != xIndex2 ) &&
  292. ( pxIOManager->pxBuffers[ xIndex2 ].ulSector == pxIOManager->pxBuffers[ xIndex ].ulSector ) &&
  293. ( pxIOManager->pxBuffers[ xIndex2 ].ucMode == FF_MODE_READ ) )
  294. {
  295. pxIOManager->pxBuffers[ xIndex2 ].bModified = pdTRUE;
  296. }
  297. }
  298. }
  299. }
  300. }
  301. if( ( pxIOManager->xBlkDevice.pxDisk != NULL ) &&
  302. ( pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook != NULL ) )
  303. {
  304. /* Let the low-level driver also flush data.
  305. * See comments in ff_ioman.h. */
  306. pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook( pxIOManager->xBlkDevice.pxDisk );
  307. }
  308. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  309. }
  310. return xError;
  311. } /* FF_FlushCache() */
  312. /*-----------------------------------------------------------*/
  313. /*
  314. * A new version of FF_GetBuffer() with a simple mechanism for timeout
  315. */
  316. #define FF_GETBUFFER_SLEEP_TIME_MS 10
  317. #define FF_GETBUFFER_WAIT_TIME_MS ( 20000 / FF_GETBUFFER_SLEEP_TIME_MS )
  318. FF_Buffer_t * FF_GetBuffer( FF_IOManager_t * pxIOManager,
  319. uint32_t ulSector,
  320. uint8_t ucMode )
  321. {
  322. FF_Buffer_t * pxBuffer;
  323. /* Least Recently Used Buffer */
  324. FF_Buffer_t * pxRLUBuffer;
  325. FF_Buffer_t * pxMatchingBuffer = NULL;
  326. int32_t lRetVal;
  327. BaseType_t xLoopCount = FF_GETBUFFER_WAIT_TIME_MS;
  328. const FF_Buffer_t * pxLastBuffer = &( pxIOManager->pxBuffers[ pxIOManager->usCacheSize ] );
  329. /* 'pxIOManager->usCacheSize' is bigger than zero and it is a multiple of ulSectorSize. */
  330. while( pxMatchingBuffer == NULL )
  331. {
  332. xLoopCount--;
  333. if( xLoopCount == 0 )
  334. {
  335. break;
  336. }
  337. FF_PendSemaphore( pxIOManager->pvSemaphore );
  338. for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ )
  339. {
  340. if( ( pxBuffer->ulSector == ulSector ) && ( pxBuffer->bValid ) )
  341. {
  342. pxMatchingBuffer = pxBuffer;
  343. /* Don't look further if you found a perfect match. */
  344. break;
  345. }
  346. }
  347. if( pxMatchingBuffer != NULL )
  348. {
  349. /* A Match was found process! */
  350. if( ( ucMode == FF_MODE_READ ) && ( pxMatchingBuffer->ucMode == FF_MODE_READ ) )
  351. {
  352. pxMatchingBuffer->usNumHandles += 1;
  353. pxMatchingBuffer->usPersistance += 1;
  354. break;
  355. }
  356. if( pxMatchingBuffer->usNumHandles == 0 )
  357. {
  358. /* Copy the read & write flags. */
  359. pxMatchingBuffer->ucMode = ( ucMode & FF_MODE_RD_WR );
  360. if( ( ucMode & FF_MODE_WRITE ) != 0 )
  361. {
  362. /* This buffer has no attached handles. */
  363. pxMatchingBuffer->bModified = pdTRUE;
  364. }
  365. pxMatchingBuffer->usNumHandles = 1;
  366. pxMatchingBuffer->usPersistance += 1;
  367. break;
  368. }
  369. /* Sector is already in use in a different mode, keep yielding until its available! */
  370. pxMatchingBuffer = NULL;
  371. }
  372. else
  373. {
  374. /* There is no valid buffer now for the desired sector.
  375. * Find a free buffer and use it for that sector. */
  376. pxRLUBuffer = NULL;
  377. for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ )
  378. {
  379. if( pxBuffer->usNumHandles != 0 )
  380. {
  381. continue; /* Occupied */
  382. }
  383. pxBuffer->ulLRU += 1;
  384. if( ( pxRLUBuffer == NULL ) ||
  385. ( pxBuffer->ulLRU > pxRLUBuffer->ulLRU ) ||
  386. ( ( pxBuffer->ulLRU == pxRLUBuffer->ulLRU ) && ( pxBuffer->usPersistance > pxRLUBuffer->usPersistance ) ) )
  387. {
  388. pxRLUBuffer = pxBuffer;
  389. }
  390. }
  391. /* A free buffer with the highest value of 'ulLRU' was found: */
  392. if( pxRLUBuffer != NULL )
  393. {
  394. /* Process the suitable candidate. */
  395. if( pxRLUBuffer->bModified == pdTRUE )
  396. {
  397. /* Along with the pdTRUE parameter to indicate semaphore has been claimed already. */
  398. lRetVal = FF_BlockWrite( pxIOManager, pxRLUBuffer->ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE );
  399. if( lRetVal < 0 )
  400. {
  401. /* NULL will be returned because 'pxMatchingBuffer' is still NULL. */
  402. break;
  403. }
  404. }
  405. if( ucMode == FF_MODE_WR_ONLY )
  406. {
  407. memset( pxRLUBuffer->pucBuffer, '\0', pxIOManager->usSectorSize );
  408. }
  409. else
  410. {
  411. lRetVal = FF_BlockRead( pxIOManager, ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE );
  412. if( lRetVal < 0 )
  413. {
  414. /* 'pxMatchingBuffer' is NULL. */
  415. break;
  416. }
  417. }
  418. pxRLUBuffer->ucMode = ( ucMode & FF_MODE_RD_WR );
  419. pxRLUBuffer->usPersistance = 1;
  420. pxRLUBuffer->ulLRU = 0;
  421. pxRLUBuffer->usNumHandles = 1;
  422. pxRLUBuffer->ulSector = ulSector;
  423. pxRLUBuffer->bModified = ( ucMode & FF_MODE_WRITE ) != 0;
  424. pxRLUBuffer->bValid = pdTRUE;
  425. pxMatchingBuffer = pxRLUBuffer;
  426. break;
  427. } /* if( pxRLUBuffer != NULL ) */
  428. } /* else ( pxMatchingBuffer == NULL ) */
  429. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  430. /* Better to go asleep to give low-priority task a chance to release buffer(s). */
  431. FF_BufferWait( pxIOManager, FF_GETBUFFER_SLEEP_TIME_MS );
  432. } /* while( pxMatchingBuffer == NULL ) */
  433. if( xLoopCount > 0 )
  434. {
  435. /* If xLoopCount is 0 here, the semaphore was not taken. */
  436. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  437. }
  438. if( pxMatchingBuffer == NULL )
  439. {
  440. FF_PRINTF( "FF_GetBuffer[0x%X]: failed mode 0x%X\n", ( unsigned ) ulSector, ( unsigned ) ucMode );
  441. }
  442. return pxMatchingBuffer; /* Return the Matched Buffer! */
  443. } /* FF_GetBuffer() */
  444. /*-----------------------------------------------------------*/
  445. /**
  446. * @private
  447. * @brief Releases a buffer resource.
  448. *
  449. * @param pxIOManager Pointer to an FF_IOManager_t object.
  450. * @param pxBuffer Pointer to an FF_Buffer_t object.
  451. *
  452. **/
  453. FF_Error_t FF_ReleaseBuffer( FF_IOManager_t * pxIOManager,
  454. FF_Buffer_t * pxBuffer )
  455. {
  456. FF_Error_t xError = FF_ERR_NONE;
  457. /* Protect description changes with a semaphore. */
  458. FF_PendSemaphore( pxIOManager->pvSemaphore );
  459. {
  460. #if ( ffconfigCACHE_WRITE_THROUGH != 0 )
  461. if( pxBuffer->bModified == pdTRUE )
  462. {
  463. xError = FF_BlockWrite( pxIOManager, pxBuffer->ulSector, 1, pxBuffer->pucBuffer, pdTRUE );
  464. if( FF_isERR( xError ) == pdFALSE )
  465. {
  466. /* Ensure if an error occurs its still possible to write the block again. */
  467. pxBuffer->bModified = pdFALSE;
  468. }
  469. }
  470. #endif /* if ( ffconfigCACHE_WRITE_THROUGH != 0 ) */
  471. configASSERT( pxBuffer->usNumHandles != 0 );
  472. if( pxBuffer->usNumHandles != 0 )
  473. {
  474. pxBuffer->usNumHandles--;
  475. }
  476. else
  477. {
  478. /*printf ("FF_ReleaseBuffer: buffer not claimed\n"); */
  479. }
  480. }
  481. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  482. /* Notify tasks which may be waiting in FF_GetBuffer() */
  483. FF_BufferProceed( pxIOManager );
  484. return xError;
  485. } /* FF_ReleaseBuffer() */
  486. /*-----------------------------------------------------------*/
  487. /* New Interface for FreeRTOS+FAT to read blocks. */
  488. int32_t FF_BlockRead( FF_IOManager_t * pxIOManager,
  489. uint32_t ulSectorLBA,
  490. uint32_t ulNumSectors,
  491. void * pxBuffer,
  492. BaseType_t xSemLocked )
  493. {
  494. int32_t slRetVal = 0;
  495. if( pxIOManager->xPartition.ulTotalSectors != 0ul )
  496. {
  497. /* At some point while formatting a partition, ulTotalSectors might be unknown.
  498. * In that case this test will be skipped. */
  499. if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) )
  500. {
  501. slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD;
  502. }
  503. }
  504. if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpReadBlocks != NULL ) )
  505. {
  506. do
  507. {
  508. /* Make sure we don't execute a NULL. */
  509. if( ( xSemLocked == pdFALSE ) &&
  510. ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
  511. {
  512. FF_PendSemaphore( pxIOManager->pvSemaphore );
  513. }
  514. slRetVal = pxIOManager->xBlkDevice.fnpReadBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk );
  515. if( ( xSemLocked == pdFALSE ) &&
  516. ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
  517. {
  518. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  519. }
  520. if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY )
  521. {
  522. break;
  523. }
  524. FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS );
  525. } while( pdTRUE );
  526. }
  527. return slRetVal;
  528. } /* FF_BlockRead() */
  529. /*-----------------------------------------------------------*/
  530. int32_t FF_BlockWrite( FF_IOManager_t * pxIOManager,
  531. uint32_t ulSectorLBA,
  532. uint32_t ulNumSectors,
  533. void * pxBuffer,
  534. BaseType_t xSemLocked )
  535. {
  536. int32_t slRetVal = 0;
  537. if( pxIOManager->xPartition.ulTotalSectors != 0 )
  538. {
  539. /* At some point while formatting a partition, ulTotalSectors might be unknown.
  540. * In that case this test will be skipped. */
  541. if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) )
  542. {
  543. slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE;
  544. }
  545. }
  546. if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpWriteBlocks != NULL ) )
  547. {
  548. do
  549. { /* Make sure we don't execute a NULL. */
  550. if( ( xSemLocked == pdFALSE ) &&
  551. ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
  552. {
  553. FF_PendSemaphore( pxIOManager->pvSemaphore );
  554. }
  555. slRetVal = pxIOManager->xBlkDevice.fnpWriteBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk );
  556. if( ( xSemLocked == pdFALSE ) &&
  557. ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) )
  558. {
  559. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  560. }
  561. if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY )
  562. {
  563. break;
  564. }
  565. FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS );
  566. } while( pdTRUE );
  567. }
  568. return slRetVal;
  569. } /* FF_BlockWrite() */
  570. /*-----------------------------------------------------------*/
  571. /*
  572. * This global variable is a kind of expert option:
  573. * It may be set to one of these values: FF_T_FAT[12,16,32]
  574. * just to force the driver to assume a certain FAT type.
  575. */
  576. uint8_t ucAssumeFATType;
  577. /* The history of FAT types:
  578. * The Microsoft documents says that the actual type: FAT-12, FAT-16 and FAT-32
  579. * of a partition can be found by looking at the total number of data clusters:
  580. *
  581. * if( clusters < 4085 )
  582. * Assume FAT-12
  583. * else if( clusters < 65525 )
  584. * Assume FAT-16
  585. * else
  586. * Assume FAT-32
  587. *
  588. * In practice however, this does not always seem to be a correct assumption.
  589. *
  590. * The first 12 or 16 bits in the FAT table may also help to determine the
  591. * correct FAT-type:
  592. *
  593. * FAT-12: ( firstWord & 0x3FF ) == 0x3F8 )
  594. * FAT-16: ( firstWord == 0xFFF8 )
  595. */
  596. static FF_Error_t prvDetermineFatType( FF_IOManager_t * pxIOManager )
  597. {
  598. FF_Partition_t * pxPartition;
  599. FF_Buffer_t * pxBuffer;
  600. uint32_t ulFirstWord = 0ul;
  601. FF_Error_t xError = FF_ERR_NONE;
  602. pxPartition = &( pxIOManager->xPartition );
  603. if( ucAssumeFATType != 0 )
  604. {
  605. switch( ucAssumeFATType )
  606. {
  607. case FF_T_FAT12:
  608. case FF_T_FAT16:
  609. case FF_T_FAT32:
  610. pxPartition->ucType = ucAssumeFATType;
  611. break;
  612. default:
  613. /* An invalid value will be ignored, and the FAT type is determined dynamically. */
  614. ucAssumeFATType = 0;
  615. break;
  616. }
  617. xError = FF_ERR_NONE;
  618. }
  619. /* Test again, the value may have become zero now: */
  620. if( ucAssumeFATType == 0 )
  621. {
  622. pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA, FF_MODE_READ );
  623. if( pxBuffer == NULL )
  624. {
  625. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE;
  626. }
  627. else
  628. {
  629. ulFirstWord = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, 0x0000 );
  630. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  631. }
  632. }
  633. if( ( ucAssumeFATType == 0 ) && ( FF_isERR( xError ) == pdFALSE ) )
  634. {
  635. #if ( ffconfigFAT12_SUPPORT != 0 )
  636. if( pxPartition->ulNumClusters < FAT16_SECTOR_COUNT_4085 )
  637. {
  638. /* FAT12 */
  639. pxPartition->ucType = FF_T_FAT12;
  640. #if ( ffconfigFAT_CHECK != 0 )
  641. if( ( ulFirstWord & 0x3FF ) != 0x3F8 )
  642. {
  643. xError = FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE;
  644. }
  645. else
  646. #endif /* ffconfigFAT_CHECK */
  647. {
  648. xError = FF_ERR_NONE;
  649. }
  650. }
  651. else
  652. #endif /* ffconfigFAT12_SUPPORT */
  653. if( pxPartition->ulNumClusters < FAT32_SECTOR_COUNT_65525 )
  654. {
  655. /* FAT 16 */
  656. pxPartition->ucType = FF_T_FAT16;
  657. #if ( ffconfigFAT_CHECK != 0 )
  658. {
  659. if( ulFirstWord == 0xFFF8 )
  660. {
  661. xError = FF_ERR_NONE;
  662. }
  663. else
  664. {
  665. if( ( ulFirstWord & 0x3FF ) != 0x3F8 )
  666. {
  667. FF_PRINTF( "Part at %lu is probably a FAT12\n", pxIOManager->xPartition.ulFATBeginLBA );
  668. }
  669. else
  670. {
  671. FF_PRINTF( "Partition at %lu has strange FAT data %08lX\n",
  672. pxIOManager->xPartition.ulFATBeginLBA, ulFirstWord );
  673. }
  674. xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_DETERMINEFATTYPE;
  675. }
  676. }
  677. #endif /* ffconfigFAT_CHECK */
  678. }
  679. else
  680. {
  681. /* FAT 32! */
  682. pxPartition->ucType = FF_T_FAT32;
  683. #if ( ffconfigFAT_CHECK != 0 )
  684. if( ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF8 ) &&
  685. ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF0 ) )
  686. {
  687. /* _HT_
  688. * I had an SD-card which worked well in Linux/W32
  689. * but FreeRTOS+FAT returned me this error
  690. * So for me I left out this check (just issue a warning for now)
  691. */
  692. FF_PRINTF( "prvDetermineFatType: firstWord %08lX\n", ulFirstWord );
  693. xError = FF_ERR_NONE; /* FF_ERR_IOMAN_NOT_FAT_FORMATTED; */
  694. }
  695. #endif /* ffconfigFAT_CHECK */
  696. xError = FF_ERR_NONE;
  697. }
  698. }
  699. return xError;
  700. } /* prvDetermineFatType() */
  701. /*-----------------------------------------------------------*/
  702. /* Check if ucPartitionID introduces an extended partition. */
  703. static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID )
  704. {
  705. BaseType_t xResult;
  706. if( ( ucPartitionID == FF_DOS_EXT_PART ) ||
  707. ( ucPartitionID == FF_WIN98_EXT_PART ) ||
  708. ( ucPartitionID == FF_LINUX_EXT_PART ) )
  709. {
  710. xResult = pdTRUE;
  711. }
  712. else
  713. {
  714. xResult = pdFALSE;
  715. }
  716. return xResult;
  717. } /* prvIsExtendedPartition() */
  718. /*-----------------------------------------------------------*/
  719. /* Check if the media byte in an MBR is valid */
  720. static BaseType_t prvIsValidMedia( uint8_t media )
  721. {
  722. BaseType_t xResult;
  723. /*
  724. * 0xF8 is the standard value for “fixed” (non-removable) media. For
  725. * removable media, 0xF0 is frequently used. The legal values for this
  726. * field are 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, and
  727. * 0xFF. The only other important point is that whatever value is put
  728. * in here must also be put in the low byte of the FAT[0] entry. This
  729. * dates back to the old MS-DOS 1.x media determination noted
  730. * earlier and is no longer usually used for anything.
  731. */
  732. if( ( 0xf8 <= media ) || ( media == 0xf0 ) )
  733. {
  734. xResult = pdTRUE;
  735. }
  736. else
  737. {
  738. xResult = pdFALSE;
  739. }
  740. return xResult;
  741. } /* prvIsValidMedia() */
  742. /*-----------------------------------------------------------*/
  743. void FF_ReadParts( uint8_t * pucBuffer,
  744. FF_Part_t * pxParts )
  745. {
  746. BaseType_t xPartNr;
  747. UBaseType_t uxOffset = FF_FAT_PTBL;
  748. /* pxParts is expected to be declared as an array of 4 elements:
  749. * FF_Part_t pxParts[4];
  750. * FF_ReadParts( pxBuffer->pucBuffer, pxParts );
  751. */
  752. for( xPartNr = 0; xPartNr < 4; xPartNr++, uxOffset += 16, pxParts++ )
  753. {
  754. pxParts->ucActive = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ACTIVE );
  755. pxParts->ucPartitionID = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ID );
  756. pxParts->ulSectorCount = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_SECT_COUNT );
  757. pxParts->ulStartLBA = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_LBA );
  758. }
  759. }
  760. /*-----------------------------------------------------------*/
  761. /* This function will traverse through a chain of extended partitions. */
  762. /* It is protected against rubbish data by a counter. */
  763. static FF_Error_t FF_ParseExtended( FF_IOManager_t * pxIOManager,
  764. uint32_t ulFirstSector,
  765. uint32_t ulFirstSize,
  766. FF_SPartFound_t * pPartsFound )
  767. {
  768. uint32_t ulThisSector, ulThisSize;
  769. uint32_t ulSectorSize = pxIOManager->usSectorSize / 512;
  770. uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors;
  771. FF_Buffer_t * pxBuffer = NULL;
  772. BaseType_t xTryCount = 100;
  773. BaseType_t xPartNr;
  774. BaseType_t xExtendedPartNr;
  775. FF_Error_t xError = FF_ERR_NONE;
  776. FF_Part_t pxPartitions[ 4 ];
  777. ulThisSector = ulFirstSector;
  778. ulThisSize = ulFirstSize;
  779. /* Disable sector checking in FF_BlockRead, because the
  780. * exact disk (partition) parameters are not yet known.
  781. * Let user driver return an error is appropriate. */
  782. pxIOManager->xPartition.ulTotalSectors = 0;
  783. while( xTryCount-- )
  784. {
  785. if( ( pxBuffer == NULL ) || ( pxBuffer->ulSector != ulThisSector ) )
  786. {
  787. /* Moving to a different sector. Release the
  788. * previous one and allocate a new buffer. */
  789. if( pxBuffer != NULL )
  790. {
  791. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  792. pxBuffer = NULL;
  793. if( FF_isERR( xError ) )
  794. {
  795. break;
  796. }
  797. }
  798. FF_PRINTF( "FF_ParseExtended: Read sector %u\n", ( unsigned ) ulThisSector );
  799. pxBuffer = FF_GetBuffer( pxIOManager, ulThisSector, FF_MODE_READ );
  800. if( pxBuffer == NULL )
  801. {
  802. xError = FF_PARSEEXTENDED | FF_ERR_DEVICE_DRIVER_FAILED; /* | FUNCTION...; */
  803. break;
  804. }
  805. }
  806. {
  807. uint8_t a = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 0 );
  808. uint8_t b = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 1 );
  809. if( ( a != 0x55 ) || ( b != 0xAA ) )
  810. {
  811. FF_PRINTF( "FF_ParseExtended: No signature %02X,%02X\n", a, b );
  812. break;
  813. }
  814. }
  815. /* Check for data partition(s),
  816. * and remember if there is an extended partition */
  817. FF_ReadParts( pxBuffer->pucBuffer, pxPartitions );
  818. /* Assume there is no next ext partition. */
  819. xExtendedPartNr = -1;
  820. for( xPartNr = 0; xPartNr < 4; xPartNr++ )
  821. {
  822. uint32_t ulOffset, ulSize, ulNext;
  823. if( pxPartitions[ xPartNr ].ulSectorCount == 0 )
  824. {
  825. /* Partition is empty */
  826. continue;
  827. }
  828. if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) )
  829. {
  830. if( xExtendedPartNr < 0 )
  831. {
  832. xExtendedPartNr = xPartNr;
  833. }
  834. continue; /* We'll examine this ext partition later */
  835. }
  836. /* Some sanity checks */
  837. ulOffset = pxPartitions[ xPartNr ].ulStartLBA * ulSectorSize;
  838. ulSize = pxPartitions[ xPartNr ].ulSectorCount * ulSectorSize;
  839. ulNext = ulThisSector + ulOffset;
  840. if(
  841. /* Is it oversized? */
  842. ( ulOffset + ulSize > ulThisSize ) ||
  843. /* or going backward? */
  844. ( ulNext < ulFirstSector ) ||
  845. /* Or outsize the logical partition? */
  846. ( ulNext > ulFirstSector + ulFirstSize )
  847. )
  848. {
  849. FF_PRINTF( "Part %d looks insane: ulThisSector %u ulOffset %u ulNext %u\n",
  850. ( int ) xPartNr, ( unsigned ) ulThisSector, ( unsigned ) ulOffset, ( unsigned ) ulNext );
  851. continue;
  852. }
  853. {
  854. /* Store this partition for the caller */
  855. FF_Part_t * p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ];
  856. /* Copy the whole structure */
  857. memcpy( p, pxPartitions + xPartNr, sizeof( *p ) );
  858. /* and make LBA absolute to sector-0. */
  859. p->ulStartLBA += ulThisSector;
  860. p->bIsExtended = pdTRUE;
  861. }
  862. if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS )
  863. {
  864. break;
  865. }
  866. xTryCount = 100;
  867. } /* for( xPartNr = 0; xPartNr < 4; xPartNr++ ) */
  868. if( xExtendedPartNr < 0 )
  869. {
  870. FF_PRINTF( "No more extended partitions\n" );
  871. break; /* nothing left to do */
  872. }
  873. /* Examine the ulNext extended partition */
  874. ulThisSector = ulFirstSector + pxPartitions[ xExtendedPartNr ].ulStartLBA * ulSectorSize;
  875. ulThisSize = pxPartitions[ xExtendedPartNr ].ulSectorCount * ulSectorSize;
  876. }
  877. if( pxBuffer != NULL )
  878. {
  879. FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  880. if( FF_isERR( xError ) == pdFALSE )
  881. {
  882. xError = xTempError;
  883. }
  884. }
  885. pxIOManager->xPartition.ulTotalSectors = prevTotalSectors;
  886. return xError;
  887. } /* FF_ParseExtended() */
  888. /*-----------------------------------------------------------*/
  889. /**
  890. * @public
  891. * @brief Searches a disk for all primary and extended/logical partitions
  892. * @brief Previously called FF_PartitionCount
  893. *
  894. * @param pxIOManager FF_IOManager_t object.
  895. * @param pPartsFound Contains an array of ffconfigMAX_PARTITIONS partitions
  896. *
  897. * @Return >=0 Number of partitions found
  898. * @Return <0 error
  899. **/
  900. FF_Error_t FF_PartitionSearch( FF_IOManager_t * pxIOManager,
  901. FF_SPartFound_t * pPartsFound )
  902. {
  903. BaseType_t xPartNr;
  904. FF_Buffer_t * pxBuffer;
  905. uint8_t * ucDataBuffer;
  906. BaseType_t isPBR = pdFALSE;
  907. FF_Error_t xError = FF_ERR_NONE;
  908. uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors;
  909. FF_Part_t pxPartitions[ 4 ];
  910. memset( pPartsFound, '\0', sizeof( *pPartsFound ) );
  911. do
  912. {
  913. pxBuffer = FF_GetBuffer( pxIOManager, 0, FF_MODE_READ );
  914. if( pxBuffer == NULL )
  915. {
  916. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_PARTITIONSEARCH;
  917. break;
  918. }
  919. /* Disable sector checking in FF_BlockRead
  920. * Let user driver return an error is appropriate. */
  921. pxIOManager->xPartition.ulTotalSectors = 0;
  922. ucDataBuffer = pxBuffer->pucBuffer;
  923. /* Check MBR (Master Boot Record) or
  924. * PBR (Partition Boot Record) signature. */
  925. if( ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ) != 0x55 ) ||
  926. ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE + 1 ) != 0xAA ) )
  927. {
  928. /* No MBR, but is it a PBR ?
  929. * Partition Boot Record */
  930. if( ( FF_getChar( ucDataBuffer, 0 ) == 0xEB ) && /* PBR Byte 0 */
  931. ( FF_getChar( ucDataBuffer, 2 ) == 0x90 ) )
  932. {
  933. /* PBR Byte 2
  934. * No MBR but PBR exist then there is only one partition
  935. * Handle this later. */
  936. isPBR = pdTRUE;
  937. }
  938. else
  939. {
  940. FF_PRINTF( "FF_PartitionSearch: [%02X,%02X] No signature (%02X %02X), no PBR neither\n",
  941. FF_getChar( ucDataBuffer, 0 ),
  942. FF_getChar( ucDataBuffer, 2 ),
  943. FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ),
  944. FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE + 1 ) );
  945. /* No MBR and no PBR then no partition found. */
  946. xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH;
  947. break;
  948. }
  949. }
  950. /* Copy the 4 partition records into 'pxPartitions': */
  951. FF_ReadParts( ucDataBuffer, pxPartitions );
  952. for( xPartNr = 0; ( xPartNr < 4 ) && ( isPBR == pdFALSE ); xPartNr++ )
  953. {
  954. /* FF_PRINTF ("FF_Part[%d]: id %02X act %02X Start %6lu Len %6lu (sectors)\n", */
  955. /* xPartNr, pxPartitions[ xPartNr ].ucPartitionID, */
  956. /* pxPartitions[ xPartNr ].ucActive, */
  957. /* pxPartitions[ xPartNr ].ulStartLBA, */
  958. /* pxPartitions[ xPartNr ].ulSectorCount); */
  959. if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) != pdFALSE )
  960. {
  961. continue; /* Do this later */
  962. }
  963. /* The first sector must be a MBR, then check the partition entry in the MBR */
  964. if( ( pxPartitions[ xPartNr ].ucActive != 0x80 ) &&
  965. ( pxPartitions[ xPartNr ].ucActive != 0x00 ) )
  966. {
  967. if( ( xPartNr == 0 ) &&
  968. ( FF_getShort( ucDataBuffer, FF_FAT_RESERVED_SECTORS ) != 0 ) &&
  969. ( FF_getChar( ucDataBuffer, FF_FAT_NUMBER_OF_FATS ) != 0 ) )
  970. {
  971. isPBR = pdTRUE;
  972. }
  973. else
  974. {
  975. xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH;
  976. break;
  977. }
  978. }
  979. else if( pxPartitions[ xPartNr ].ulSectorCount )
  980. {
  981. FF_Part_t * p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ];
  982. *p = pxPartitions[ xPartNr ];
  983. p->bIsExtended = 0;
  984. if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS )
  985. {
  986. break;
  987. }
  988. }
  989. }
  990. if( FF_isERR( xError ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) )
  991. {
  992. break;
  993. }
  994. for( xPartNr = 0; xPartNr < 4; xPartNr++ )
  995. {
  996. if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) )
  997. {
  998. xError = FF_ParseExtended( pxIOManager, pxPartitions[ xPartNr ].ulStartLBA,
  999. pxPartitions[ xPartNr ].ulSectorCount, pPartsFound );
  1000. if( ( FF_isERR( xError ) != pdFALSE ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) )
  1001. {
  1002. goto done;
  1003. }
  1004. }
  1005. }
  1006. if( pPartsFound->iCount == 0 )
  1007. {
  1008. FF_PRINTF( "FF_Part: no partitions, try as PBR\n" );
  1009. isPBR = pdTRUE;
  1010. }
  1011. if( isPBR )
  1012. {
  1013. uint8_t media = FF_getChar( ucDataBuffer, FF_FAT_MEDIA_TYPE );
  1014. FF_Part_t * p;
  1015. if( !prvIsValidMedia( media ) )
  1016. {
  1017. FF_PRINTF( "FF_Part: Looks like PBR but media %02X\n", media );
  1018. xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_PARTITIONSEARCH;
  1019. goto done;
  1020. }
  1021. /* This looks like a PBR because it has a valid media type */
  1022. p = pPartsFound->pxPartitions;
  1023. p->ulStartLBA = 0; /* FF_FAT_PTBL_LBA */
  1024. p->ulSectorCount = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS );
  1025. if( p->ulSectorCount == 0ul )
  1026. {
  1027. p->ulSectorCount = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS );
  1028. }
  1029. p->ucActive = 0x80; /* FF_FAT_PTBL_ACTIVE */
  1030. p->ucPartitionID = 0x0B; /* FF_FAT_PTBL_ID MSDOS data partition */
  1031. p->bIsExtended = 0;
  1032. pPartsFound->iCount = 1;
  1033. }
  1034. } while( pdFALSE );
  1035. done:
  1036. if( pxBuffer )
  1037. {
  1038. FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  1039. if( FF_isERR( xError ) == pdFALSE )
  1040. {
  1041. xError = xTempError;
  1042. }
  1043. }
  1044. pxIOManager->xPartition.ulTotalSectors = prevTotalSectors;
  1045. return FF_isERR( xError ) ? xError : pPartsFound->iCount;
  1046. } /* FF_PartitionSearch() */
  1047. /*-----------------------------------------------------------*/
  1048. /*
  1049. * Mount GPT Partition Tables
  1050. */
  1051. #define FF_GPT_HEAD_ENTRY_SIZE 0x54
  1052. #define FF_GPT_HEAD_TOTAL_ENTRIES 0x50
  1053. #define FF_GPT_HEAD_PART_ENTRY_LBA 0x48
  1054. #define FF_GPT_ENTRY_FIRST_SECTOR_LBA 0x20
  1055. #define FF_GPT_HEAD_CRC 0x10
  1056. #define FF_GPT_HEAD_LENGTH 0x0C
  1057. static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t * pxIOManager,
  1058. uint32_t ulPartitionNumber )
  1059. {
  1060. /* Continuing on from FF_Mount() pPartition->ulBeginLBA should be the sector of the GPT Header */
  1061. FF_Buffer_t * pxBuffer;
  1062. FF_Partition_t * pxPartition = &( pxIOManager->xPartition );
  1063. uint32_t ulBeginGPT;
  1064. uint32_t ulEntrySector;
  1065. uint32_t ulSectorOffset;
  1066. uint32_t ulPartitionEntrySize;
  1067. uint32_t ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength;
  1068. FF_Error_t xError;
  1069. do
  1070. {
  1071. if( ulPartitionNumber >= 128 )
  1072. {
  1073. xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY;
  1074. break;
  1075. }
  1076. pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ );
  1077. if( pxBuffer == NULL )
  1078. {
  1079. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY;
  1080. break;
  1081. }
  1082. /* Verify this is an EFI header with the text "EFI PART": */
  1083. if( memcmp( pxBuffer->pucBuffer, "EFI PART", 8 ) != 0 )
  1084. {
  1085. /* Already returning an error, but this error would override the current one. */
  1086. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  1087. if( FF_isERR( xError ) == pdFALSE )
  1088. {
  1089. xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_GETEFIPARTITIONENTRY;
  1090. }
  1091. break;
  1092. }
  1093. ulBeginGPT = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_PART_ENTRY_LBA );
  1094. ulPartitionEntrySize = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_ENTRY_SIZE );
  1095. ulGPTHeadCRC = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC );
  1096. ulGPTHeadLength = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_LENGTH );
  1097. /* Calculate Head CRC */
  1098. /* Blank CRC field */
  1099. FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, 0x00000000 );
  1100. /* Calculate CRC */
  1101. ulGPTCrcCheck = FF_GetCRC32( pxBuffer->pucBuffer, ulGPTHeadLength );
  1102. /* Restore The CRC field */
  1103. FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC );
  1104. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  1105. if( FF_isERR( xError ) )
  1106. {
  1107. break;
  1108. }
  1109. /* Check CRC */
  1110. if( ulGPTHeadCRC != ulGPTCrcCheck )
  1111. {
  1112. xError = FF_ERR_IOMAN_GPT_HEADER_CORRUPT | FF_GETEFIPARTITIONENTRY;
  1113. break;
  1114. }
  1115. /* Calculate Sector Containing the Partition Entry we want to use. */
  1116. ulEntrySector = ( ( ulPartitionNumber * ulPartitionEntrySize ) / pxIOManager->usSectorSize ) + ulBeginGPT;
  1117. ulSectorOffset = ( ulPartitionNumber % ( pxIOManager->usSectorSize / ulPartitionEntrySize ) ) * ulPartitionEntrySize;
  1118. pxBuffer = FF_GetBuffer( pxIOManager, ulEntrySector, FF_MODE_READ );
  1119. {
  1120. if( pxBuffer == NULL )
  1121. {
  1122. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY;
  1123. break;
  1124. }
  1125. pxPartition->ulBeginLBA = FF_getLong( pxBuffer->pucBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA );
  1126. }
  1127. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  1128. if( FF_isERR( xError ) == pdFALSE )
  1129. {
  1130. if( pxPartition->ulBeginLBA == 0ul )
  1131. {
  1132. xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY;
  1133. }
  1134. }
  1135. }
  1136. while( pdFALSE );
  1137. return xError;
  1138. } /* FF_GetEfiPartitionEntry() */
  1139. /*-----------------------------------------------------------*/
  1140. /**
  1141. * @public
  1142. * @brief Mounts the Specified partition, the volume specified by the FF_IOManager_t object provided.
  1143. *
  1144. * The device drivers must adhere to the specification provided by
  1145. * FF_WriteBlocks_t and FF_ReadBlocks_t.
  1146. *
  1147. * @param pxIOManager FF_IOManager_t object.
  1148. * @param PartitionNumber The primary or logical partition number to be mounted,
  1149. * ranging between 0 and ffconfigMAX_PARTITIONS-1 (normally 0)
  1150. * Note that FF_PartitionSearch can be called in advance to
  1151. * enumerate all available partitions
  1152. *
  1153. * @Return 0 on success.
  1154. * @Return FF_ERR_NULL_POINTER if a pxIOManager object wasn't provided.
  1155. * @Return FF_ERR_IOMAN_INVALID_PARTITION_NUM if the partition number is out of range.
  1156. * @Return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION if no partition was found.
  1157. * @Return FF_ERR_IOMAN_INVALID_FORMAT if the master boot record or partition boot block didn't provide sensible data.
  1158. * @Return FF_ERR_IOMAN_NOT_FAT_FORMATTED if the volume or partition couldn't be determined to be FAT. (@see FreeRTOSFATConfig.h)
  1159. *
  1160. **/
  1161. FF_Error_t FF_Mount( FF_Disk_t * pxDisk,
  1162. BaseType_t xPartitionNumber )
  1163. {
  1164. FF_Partition_t * pxPartition;
  1165. FF_Buffer_t * pxBuffer = 0;
  1166. FF_Error_t xError = FF_ERR_NONE;
  1167. int16_t rootEntryCount;
  1168. FF_IOManager_t * pxIOManager = pxDisk->pxIOManager;
  1169. /* HT TODO: find a method to safely determine the FAT type: 32/16/12 */
  1170. /* other than only counting Clusters */
  1171. /* UBaseType_t fat32Indicator = 0; */
  1172. FF_Part_t * pxMyPartition;
  1173. #if ( ffconfigHASH_CACHE != 0 )
  1174. BaseType_t i;
  1175. #endif
  1176. FF_Error_t xPartitionCount = 0;
  1177. FF_SPartFound_t partsFound;
  1178. partsFound.iCount = 0;
  1179. do
  1180. {
  1181. if( pxIOManager == NULL )
  1182. {
  1183. xError = FF_ERR_NULL_POINTER | FF_MOUNT;
  1184. break;
  1185. }
  1186. pxPartition = &( pxIOManager->xPartition );
  1187. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  1188. {
  1189. pxIOManager->ucFlags &= ( uint8_t ) ( ~( FF_IOMAN_DEVICE_IS_EXTRACTED ) );
  1190. }
  1191. #endif /* ffconfigREMOVABLE_MEDIA */
  1192. /* FF_IOMAN_InitBufferDescriptors will clear 'pxBuffers' */
  1193. memset( pxIOManager->pucCacheMem, '\0', ( size_t ) pxIOManager->usSectorSize * pxIOManager->usCacheSize );
  1194. #if ( ffconfigHASH_CACHE != 0 )
  1195. {
  1196. memset( pxIOManager->xHashCache, '\0', sizeof( pxIOManager->xHashCache ) );
  1197. for( i = 0; i < ffconfigHASH_CACHE_DEPTH; i++ )
  1198. {
  1199. /* _HT_ Check why did JW put it to 100? */
  1200. pxIOManager->xHashCache[ i ].ulMisses = 100;
  1201. }
  1202. }
  1203. #endif
  1204. #if ( ffconfigPATH_CACHE != 0 )
  1205. {
  1206. memset( pxPartition->pxPathCache, '\0', sizeof( pxPartition->pxPathCache ) );
  1207. }
  1208. #endif
  1209. FF_IOMAN_InitBufferDescriptors( pxIOManager );
  1210. pxIOManager->FirstFile = 0;
  1211. xPartitionCount = FF_PartitionSearch( pxIOManager, &partsFound );
  1212. if( FF_isERR( xPartitionCount ) )
  1213. {
  1214. xError = xPartitionCount;
  1215. break;
  1216. }
  1217. if( xPartitionCount == 0 )
  1218. {
  1219. xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_MOUNT;
  1220. break;
  1221. }
  1222. if( xPartitionNumber >= xPartitionCount )
  1223. {
  1224. xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MOUNT;
  1225. break;
  1226. }
  1227. pxMyPartition = &( partsFound.pxPartitions[ xPartitionNumber ] );
  1228. pxPartition->ulBeginLBA = pxMyPartition->ulStartLBA;
  1229. if( pxMyPartition->ucPartitionID == 0xEE )
  1230. {
  1231. xError = FF_GetEfiPartitionEntry( pxIOManager, xPartitionNumber );
  1232. if( FF_isERR( xError ) )
  1233. {
  1234. break;
  1235. }
  1236. }
  1237. /* Now we get the Partition sector. */
  1238. pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ );
  1239. if( pxBuffer == NULL )
  1240. {
  1241. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNT;
  1242. break;
  1243. }
  1244. pxPartition->usBlkSize = FF_getShort( pxBuffer->pucBuffer, FF_FAT_BYTES_PER_SECTOR );
  1245. if( ( ( pxPartition->usBlkSize % 512 ) != 0 ) || ( pxPartition->usBlkSize == 0 ) )
  1246. {
  1247. /* An error here should override the current error, as its likely fatal. */
  1248. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  1249. if( FF_isERR( xError ) == pdFALSE )
  1250. {
  1251. xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
  1252. }
  1253. break;
  1254. }
  1255. /* Assume FAT16, then we'll adjust if its FAT32 */
  1256. pxPartition->usReservedSectors = FF_getShort( pxBuffer->pucBuffer, FF_FAT_RESERVED_SECTORS );
  1257. pxPartition->ulFATBeginLBA = pxPartition->ulBeginLBA + pxPartition->usReservedSectors;
  1258. pxPartition->ucNumFATS = ( uint8_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_NUMBER_OF_FATS );
  1259. pxPartition->ulSectorsPerFAT = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_SECTORS_PER_FAT );
  1260. pxPartition->ulSectorsPerCluster = FF_getChar( pxBuffer->pucBuffer, FF_FAT_SECTORS_PER_CLUS );
  1261. /* Set the BlockFactor (How many real-blocks in a fake block!). */
  1262. pxPartition->ucBlkFactor = ( uint8_t ) ( pxPartition->usBlkSize / pxIOManager->usSectorSize );
  1263. pxPartition->ulTotalSectors = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS );
  1264. if( pxPartition->ulTotalSectors == 0 )
  1265. {
  1266. pxPartition->ulTotalSectors = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS );
  1267. }
  1268. if( pxPartition->ulSectorsPerFAT == 0 )
  1269. { /* FAT32 */
  1270. pxPartition->ulSectorsPerFAT = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_SECTORS_PER_FAT );
  1271. pxPartition->ulRootDirCluster = FF_getLong( pxBuffer->pucBuffer, FF_FAT_ROOT_DIR_CLUSTER );
  1272. memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_32_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1 );
  1273. }
  1274. else
  1275. { /* FAT16 */
  1276. pxPartition->ulRootDirCluster = 1; /* 1st Cluster is RootDir! */
  1277. memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_16_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1 );
  1278. }
  1279. pxPartition->ulClusterBeginLBA = pxPartition->ulFATBeginLBA + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT );
  1280. #if ( ffconfigWRITE_FREE_COUNT != 0 )
  1281. {
  1282. pxPartition->ulFSInfoLBA = pxPartition->ulBeginLBA + FF_getShort( pxBuffer->pucBuffer, 48 );
  1283. }
  1284. #endif
  1285. FF_ReleaseBuffer( pxIOManager, pxBuffer ); /* Release the buffer finally! */
  1286. if( pxPartition->usBlkSize == 0 )
  1287. {
  1288. xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
  1289. break;
  1290. }
  1291. rootEntryCount = FF_getShort( pxBuffer->pucBuffer, FF_FAT_ROOT_ENTRY_COUNT );
  1292. pxPartition->ulRootDirSectors = ( ( rootEntryCount * 32 ) + pxPartition->usBlkSize - 1 ) / pxPartition->usBlkSize;
  1293. pxPartition->ulFirstDataSector = pxPartition->ulClusterBeginLBA + pxPartition->ulRootDirSectors;
  1294. pxPartition->ulDataSectors = pxPartition->ulTotalSectors - ( pxPartition->usReservedSectors + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT ) + pxPartition->ulRootDirSectors );
  1295. /*
  1296. * HT: fat32Indicator not yet used
  1297. * As there is so much confusion about the FAT types
  1298. * I was thinking of collecting indications for either FAT12, 16 or 32
  1299. */
  1300. /*
  1301. * if( FF_getShort( pxBuffer->pucBuffer, FF_FAT_EXT_BOOT_SIGNATURE ) == 0x29 )
  1302. * fat32Indicator++;
  1303. * if( rootEntryCount == 0 )
  1304. * fat32Indicator++;
  1305. */
  1306. if( pxPartition->ulSectorsPerCluster == 0 )
  1307. {
  1308. xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT;
  1309. break;
  1310. }
  1311. pxPartition->ulNumClusters = pxPartition->ulDataSectors / pxPartition->ulSectorsPerCluster;
  1312. xError = prvDetermineFatType( pxIOManager );
  1313. if( FF_isERR( xError ) )
  1314. {
  1315. break;
  1316. }
  1317. if( !rootEntryCount && ( pxPartition->ucType != FF_T_FAT32 ) )
  1318. {
  1319. FF_PRINTF( "No root dir, must be a FAT32\n" );
  1320. pxPartition->ucType = FF_T_FAT32;
  1321. }
  1322. pxPartition->ucPartitionMounted = pdTRUE;
  1323. pxPartition->ulLastFreeCluster = 0;
  1324. #if ( ffconfigMOUNT_FIND_FREE != 0 )
  1325. {
  1326. FF_LockFAT( pxIOManager );
  1327. {
  1328. /* The parameter 'pdFALSE' means: do not claim the free cluster found. */
  1329. pxPartition->ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
  1330. }
  1331. FF_UnlockFAT( pxIOManager );
  1332. if( FF_isERR( xError ) )
  1333. {
  1334. if( FF_GETERROR( xError ) == FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE )
  1335. {
  1336. pxPartition->ulLastFreeCluster = 0;
  1337. }
  1338. else
  1339. {
  1340. break;
  1341. }
  1342. }
  1343. pxPartition->ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
  1344. if( FF_isERR( xError ) )
  1345. {
  1346. break;
  1347. }
  1348. }
  1349. #else /* if ( ffconfigMOUNT_FIND_FREE != 0 ) */
  1350. {
  1351. pxPartition->ulFreeClusterCount = 0;
  1352. }
  1353. #endif /* ffconfigMOUNT_FIND_FREE */
  1354. }
  1355. while( pdFALSE );
  1356. if( FF_isERR( xError ) == pdFALSE )
  1357. {
  1358. xError = 0;
  1359. }
  1360. return xError;
  1361. } /* FF_Mount() */
  1362. /*-----------------------------------------------------------*/
  1363. /**
  1364. * @private
  1365. * @brief Checks the cache for Active Handles
  1366. *
  1367. * @param pxIOManager FF_IOManager_t Object.
  1368. *
  1369. * @Return pdTRUE if an active handle is found, else pdFALSE.
  1370. *
  1371. * @pre This function must be wrapped with the cache handling semaphore.
  1372. **/
  1373. static BaseType_t prvHasActiveHandles( FF_IOManager_t * pxIOManager )
  1374. {
  1375. BaseType_t xResult;
  1376. FF_Buffer_t * pxBuffer = pxIOManager->pxBuffers;
  1377. FF_Buffer_t * pxLastBuffer = pxBuffer + pxIOManager->usCacheSize;
  1378. for( ; ; )
  1379. {
  1380. if( pxBuffer->usNumHandles )
  1381. {
  1382. xResult = pdTRUE;
  1383. break;
  1384. }
  1385. pxBuffer++;
  1386. if( pxBuffer == pxLastBuffer )
  1387. {
  1388. xResult = pdFALSE;
  1389. break;
  1390. }
  1391. }
  1392. return xResult;
  1393. } /* prvHasActiveHandles() */
  1394. /*-----------------------------------------------------------*/
  1395. /**
  1396. * @public
  1397. * @brief Unmounts the active partition.
  1398. *
  1399. * @param pxIOManager FF_IOManager_t Object.
  1400. *
  1401. * @Return FF_ERR_NONE on success.
  1402. **/
  1403. FF_Error_t FF_Unmount( FF_Disk_t * pxDisk )
  1404. {
  1405. FF_Error_t xError = FF_ERR_NONE;
  1406. FF_IOManager_t * pxIOManager;
  1407. #if ( ffconfigMIRROR_FATS_UMOUNT != 0 )
  1408. UBaseType_t uxIndex, y;
  1409. FF_Buffer_t * pxBuffer;
  1410. #endif
  1411. if( pxDisk->pxIOManager == NULL )
  1412. {
  1413. xError = FF_ERR_NULL_POINTER | FF_UNMOUNT;
  1414. }
  1415. else if( pxDisk->pxIOManager->xPartition.ucPartitionMounted == 0 )
  1416. {
  1417. xError = FF_ERR_NONE;
  1418. }
  1419. else
  1420. {
  1421. pxIOManager = pxDisk->pxIOManager;
  1422. FF_PendSemaphore( pxIOManager->pvSemaphore ); /* Ensure that there are no File Handles */
  1423. {
  1424. if( prvHasActiveHandles( pxIOManager ) != 0 )
  1425. {
  1426. /* Active handles found on the cache. */
  1427. xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT;
  1428. }
  1429. else if( pxIOManager->FirstFile != NULL )
  1430. {
  1431. /* Open files in this partition. */
  1432. xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT;
  1433. }
  1434. else
  1435. {
  1436. /* Release Semaphore to call this function! */
  1437. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  1438. /* Flush any unwritten sectors to disk. */
  1439. xError = FF_FlushCache( pxIOManager );
  1440. /* Reclaim Semaphore */
  1441. FF_PendSemaphore( pxIOManager->pvSemaphore );
  1442. if( FF_isERR( xError ) == pdFALSE )
  1443. {
  1444. pxIOManager->xPartition.ucPartitionMounted = pdFALSE;
  1445. #if ( ffconfigMIRROR_FATS_UMOUNT != 0 )
  1446. {
  1447. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  1448. for( uxIndex = 0; uxIndex < pxIOManager->xPartition.ulSectorsPerFAT; uxIndex++ )
  1449. {
  1450. pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + uxIndex, FF_MODE_READ );
  1451. if( !pxBuffer )
  1452. {
  1453. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_UNMOUNT;
  1454. break;
  1455. }
  1456. for( y = 0; y < pxIOManager->xPartition.ucNumFATS; y++ )
  1457. {
  1458. FF_BlockWrite( pxIOManager,
  1459. pxIOManager->xPartition.ulFATBeginLBA + ( y * pxIOManager->xPartition.ulSectorsPerFAT ) + uxIndex, 1,
  1460. pxBuffer->pucBuffer, pdFALSE );
  1461. }
  1462. }
  1463. FF_PendSemaphore( pxIOManager->pvSemaphore );
  1464. }
  1465. #endif /* if ( ffconfigMIRROR_FATS_UMOUNT != 0 ) */
  1466. }
  1467. }
  1468. }
  1469. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  1470. }
  1471. return xError;
  1472. } /* FF_Unmount() */
  1473. /*-----------------------------------------------------------*/
  1474. FF_Error_t FF_IncreaseFreeClusters( FF_IOManager_t * pxIOManager,
  1475. uint32_t Count )
  1476. {
  1477. FF_Error_t xError;
  1478. #if ( ffconfigWRITE_FREE_COUNT != 0 )
  1479. FF_Buffer_t * pxBuffer;
  1480. #endif
  1481. do
  1482. {
  1483. /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */
  1484. if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
  1485. {
  1486. /* Apparently the number of free clusters has not been calculated yet,
  1487. * or no free cluster was available. Now check it. */
  1488. pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
  1489. if( FF_isERR( xError ) )
  1490. {
  1491. break;
  1492. }
  1493. }
  1494. else
  1495. {
  1496. xError = FF_ERR_NONE;
  1497. taskENTER_CRITICAL();
  1498. {
  1499. pxIOManager->xPartition.ulFreeClusterCount += Count;
  1500. }
  1501. taskEXIT_CRITICAL();
  1502. }
  1503. if( pxIOManager->xPartition.ulLastFreeCluster == 0 )
  1504. {
  1505. BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
  1506. if( xTakeLock )
  1507. {
  1508. FF_LockFAT( pxIOManager );
  1509. }
  1510. /* Find the an available cluster. */
  1511. pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
  1512. if( xTakeLock )
  1513. {
  1514. FF_UnlockFAT( pxIOManager );
  1515. }
  1516. if( FF_isERR( xError ) )
  1517. {
  1518. break;
  1519. }
  1520. }
  1521. #if ( ffconfigWRITE_FREE_COUNT != 0 )
  1522. {
  1523. /* FAT32 updates the FSINFO sector. */
  1524. if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
  1525. {
  1526. /* Find the FSINFO sector. */
  1527. pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE );
  1528. if( pxBuffer == NULL )
  1529. {
  1530. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_INCREASEFREECLUSTERS;
  1531. }
  1532. else
  1533. {
  1534. uint32_t ulSignature1;
  1535. uint32_t ulSignature2;
  1536. ulSignature1 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 );
  1537. ulSignature2 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 );
  1538. if( ( ulSignature1 == FS_INFO_SIGNATURE1_0x41615252 ) &&
  1539. ( ulSignature2 == FS_INFO_SIGNATURE2_0x61417272 ) )
  1540. {
  1541. /* FSINFO sector magic numbers we're verified. Safe to write. */
  1542. FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount );
  1543. FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster );
  1544. }
  1545. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  1546. }
  1547. }
  1548. }
  1549. #endif /* if ( ffconfigWRITE_FREE_COUNT != 0 ) */
  1550. }
  1551. while( pdFALSE );
  1552. return xError;
  1553. } /* FF_IncreaseFreeClusters() */
  1554. /*-----------------------------------------------------------*/
  1555. FF_Error_t FF_DecreaseFreeClusters( FF_IOManager_t * pxIOManager,
  1556. uint32_t Count )
  1557. {
  1558. FF_Error_t xError = FF_ERR_NONE;
  1559. #if ( ffconfigWRITE_FREE_COUNT != 0 )
  1560. FF_Buffer_t * pxBuffer;
  1561. #endif
  1562. if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
  1563. {
  1564. pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
  1565. }
  1566. else
  1567. {
  1568. taskENTER_CRITICAL();
  1569. pxIOManager->xPartition.ulFreeClusterCount -= Count;
  1570. taskEXIT_CRITICAL();
  1571. }
  1572. if( FF_isERR( xError ) == pdFALSE )
  1573. {
  1574. if( pxIOManager->xPartition.ulLastFreeCluster == 0 )
  1575. {
  1576. FF_LockFAT( pxIOManager );
  1577. {
  1578. pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE );
  1579. }
  1580. FF_UnlockFAT( pxIOManager );
  1581. }
  1582. }
  1583. if( FF_isERR( xError ) == pdFALSE )
  1584. {
  1585. #if ( ffconfigWRITE_FREE_COUNT != 0 )
  1586. {
  1587. /* FAT32 update the FSINFO sector. */
  1588. if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
  1589. {
  1590. /* Find the FSINFO sector. */
  1591. pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE );
  1592. if( pxBuffer == NULL )
  1593. {
  1594. xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DECREASEFREECLUSTERS;
  1595. }
  1596. else
  1597. {
  1598. if( ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 ) == FS_INFO_SIGNATURE1_0x41615252 ) &&
  1599. ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 ) == FS_INFO_SIGNATURE2_0x61417272 ) )
  1600. {
  1601. /* FSINFO sector magic nums we're verified. Safe to write. */
  1602. FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount );
  1603. FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster );
  1604. }
  1605. xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
  1606. }
  1607. }
  1608. }
  1609. #endif /* if ( ffconfigWRITE_FREE_COUNT != 0 ) */
  1610. }
  1611. return xError;
  1612. } /* FF_DecreaseFreeClusters() */
  1613. /*-----------------------------------------------------------*/
  1614. /**
  1615. * @brief Returns the Block-size of a mounted Partition
  1616. *
  1617. * The purpose of this function is to provide API access to information
  1618. * that might be useful in special cases. Like USB sticks that require a sector
  1619. * knocking sequence for security. After the sector knock, some secure USB
  1620. * sticks then present a different BlockSize.
  1621. *
  1622. * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger()
  1623. *
  1624. * @Return The blocksize of the partition. A value less than 0 when an error occurs.
  1625. * @Return Any negative value can be cast to the FF_Error_t type.
  1626. **/
  1627. int32_t FF_GetPartitionBlockSize( FF_IOManager_t * pxIOManager )
  1628. {
  1629. int32_t lReturn;
  1630. if( pxIOManager )
  1631. {
  1632. lReturn = ( int32_t ) pxIOManager->xPartition.usBlkSize;
  1633. }
  1634. else
  1635. {
  1636. lReturn = FF_ERR_NULL_POINTER | FF_GETPARTITIONBLOCKSIZE;
  1637. }
  1638. return lReturn;
  1639. } /* FF_GetPartitionBlockSize() */
  1640. /*-----------------------------------------------------------*/
  1641. #if ( ffconfig64_NUM_SUPPORT != 0 )
  1642. /**
  1643. * @brief Returns the number of bytes contained within the mounted partition or volume.
  1644. *
  1645. * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger()
  1646. *
  1647. * @Return The total number of bytes that the mounted partition or volume contains.
  1648. *
  1649. **/
  1650. uint64_t FF_GetVolumeSize( FF_IOManager_t * pxIOManager )
  1651. {
  1652. uint64_t ullResult;
  1653. if( pxIOManager )
  1654. {
  1655. uint32_t TotalClusters = ( pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster );
  1656. ullResult = ( uint64_t )
  1657. (
  1658. ( uint64_t ) TotalClusters * ( uint64_t )
  1659. ( ( uint64_t ) pxIOManager->xPartition.ulSectorsPerCluster * ( uint64_t ) pxIOManager->xPartition.usBlkSize )
  1660. );
  1661. }
  1662. else
  1663. {
  1664. ullResult = 0ULL;
  1665. }
  1666. return ullResult;
  1667. } /* FF_GetVolumeSize() */
  1668. #else /* if ( ffconfig64_NUM_SUPPORT != 0 ) */
  1669. uint32_t FF_GetVolumeSize( FF_IOManager_t * pxIOManager )
  1670. {
  1671. uint32_t ulResult;
  1672. if( pxIOManager )
  1673. {
  1674. uint32_t TotalClusters = pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster;
  1675. ulResult = ( uint32_t ) ( TotalClusters * ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->xPartition.usBlkSize ) );
  1676. }
  1677. else
  1678. {
  1679. ulResult = 0UL;
  1680. }
  1681. return ulResult;
  1682. } /* FF_GetVolumeSize() */
  1683. #endif /* if ( ffconfig64_NUM_SUPPORT != 0 ) */
  1684. /*-----------------------------------------------------------*/