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