ff_usbdisk.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*
  2. * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
  3. * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. * Authors include James Walmsley, Hein Tibosch and Richard Barry
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  7. * this software and associated documentation files (the "Software"), to deal in
  8. * the Software without restriction, including without limitation the rights to
  9. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10. * the Software, and to permit persons to whom the Software is furnished to do so,
  11. * subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. *
  23. * https://www.FreeRTOS.org
  24. *
  25. */
  26. /* Standard includes. */
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <stdio.h>
  31. /* LPC18xx includes. */
  32. #include "chip.h"
  33. #include "board.h"
  34. /* FreeRTOS includes. */
  35. #include "FreeRTOS.h"
  36. #include "task.h"
  37. #include "semphr.h"
  38. #include "portmacro.h"
  39. /* FreeRTOS+FAT includes. */
  40. #include "ff_usbdisk.h"
  41. #include "usb_massstorage.h"
  42. #include "ff_sys.h"
  43. /* Misc definitions. */
  44. #define usbSIGNATURE 0x41404342UL
  45. #define usbHUNDRED_64_BIT ( 100ull )
  46. #define usbBYTES_PER_MB ( 1024ull * 1024ull )
  47. #define usbSECTORS_PER_MB ( usbBYTES_PER_MB / 512ull )
  48. #define usbIOMAN_MEM_SIZE 4096
  49. #define usbAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 )
  50. /*-----------------------------------------------------------*/
  51. /*_RB_ Functions require comment blocks. */
  52. static int32_t prvUSBDisk_Init( void );
  53. static int32_t prvFFUSBDiskRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
  54. static int32_t prvFFUSBDiskWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
  55. /*-----------------------------------------------------------*/
  56. /*_RB_ Variables require a comment block where appropriate. */
  57. static struct blk_desc *xUSBInfo;
  58. static BaseType_t xUSBDiskStatus;
  59. static SemaphoreHandle_t xPlusFATMutex;
  60. /*-----------------------------------------------------------*/
  61. static int32_t prvFFUSBDiskRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
  62. {
  63. int32_t iReturn;
  64. /*_RB_ Many of the comments in this file apply to other functions in the file. */
  65. if( ( pxDisk != NULL ) && NULL != xUSBInfo->block_read &&
  66. ( xUSBDiskStatus == pdPASS ) &&
  67. ( pxDisk->ulSignature == usbSIGNATURE ) &&
  68. ( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
  69. ( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
  70. ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
  71. {
  72. iReturn = xUSBInfo->block_read(xUSBInfo, ulSectorNumber, ulSectorCount, (void *)pucBuffer);
  73. /*_RB_ I'm guessing 512 is a sector size, but that needs to be clear.
  74. Is it defined in a header somewhere? If so we can do a search and
  75. replace in files on it as it seems to be used everywhere. */
  76. if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
  77. {
  78. iReturn = FF_ERR_NONE;
  79. }
  80. else
  81. {
  82. /*_RB_ Signed number used to return bitmap (again below). */
  83. iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
  84. }
  85. }
  86. else
  87. {
  88. memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
  89. if( pxDisk->xStatus.bIsInitialised != 0 )
  90. {
  91. FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
  92. }
  93. iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
  94. }
  95. return iReturn;
  96. }
  97. /*-----------------------------------------------------------*/
  98. static int32_t prvFFUSBDiskWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
  99. {
  100. int32_t iReturn;
  101. if( ( pxDisk != NULL ) && NULL != xUSBInfo->block_write &&
  102. ( xUSBDiskStatus == pdPASS ) &&
  103. ( pxDisk->ulSignature == usbSIGNATURE ) &&
  104. ( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
  105. ( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
  106. ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
  107. {
  108. iReturn = xUSBInfo->block_write(xUSBInfo, ulSectorNumber, ulSectorCount, (const void *)pucBuffer);
  109. if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
  110. {
  111. iReturn = FF_ERR_NONE;
  112. }
  113. else
  114. {
  115. iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
  116. }
  117. }
  118. else
  119. {
  120. memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
  121. if( pxDisk->xStatus.bIsInitialised )
  122. {
  123. FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
  124. }
  125. iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
  126. }
  127. return iReturn;
  128. }
  129. /*-----------------------------------------------------------*/
  130. void FF_USBDiskFlush( FF_Disk_t *pxDisk )
  131. {
  132. if( ( pxDisk != NULL ) &&
  133. ( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
  134. ( pxDisk->pxIOManager != NULL ) )
  135. {
  136. FF_FlushCache( pxDisk->pxIOManager );
  137. }
  138. }
  139. /*-----------------------------------------------------------*/
  140. /* Initialise the USB driver and mount an Udisk */
  141. FF_Disk_t *FF_USBDiskInit( const char *pcName )
  142. {
  143. FF_Error_t xFFError;
  144. BaseType_t xPartitionNumber = 0;
  145. FF_CreationParameters_t xParameters;
  146. FF_Disk_t * pxDisk;
  147. xUSBDiskStatus = prvUSBDisk_Init();
  148. if( xUSBDiskStatus == pdPASS )
  149. {
  150. pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( *pxDisk ) );
  151. if( pxDisk != NULL )
  152. {
  153. /* Initialise the created disk structure. */
  154. memset( pxDisk, '\0', sizeof( *pxDisk ) );
  155. if( xPlusFATMutex == NULL)
  156. {
  157. xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
  158. }
  159. pxDisk->ulNumberOfSectors = xUSBInfo->lba;
  160. pxDisk->ulSignature = usbSIGNATURE;
  161. if( xPlusFATMutex != NULL)
  162. {
  163. memset( &xParameters, '\0', sizeof( xParameters ) );
  164. xParameters.ulMemorySize = usbIOMAN_MEM_SIZE;
  165. xParameters.ulSectorSize = 512;
  166. xParameters.fnWriteBlocks = prvFFUSBDiskWrite;
  167. xParameters.fnReadBlocks = prvFFUSBDiskRead;
  168. xParameters.pxDisk = pxDisk;
  169. /* prvFFRead()/prvFFWrite() are not re-entrant and must be
  170. protected with the use of a semaphore. */
  171. xParameters.xBlockDeviceIsReentrant = pdFALSE;
  172. /* The semaphore will be used to protect critical sections in
  173. the +FAT driver, and also to avoid concurrent calls to
  174. prvFFRead()/prvFFWrite() from different tasks. */
  175. xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
  176. pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
  177. if( pxDisk->pxIOManager == NULL )
  178. {
  179. FF_PRINTF( "FF_USBDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xFFError ) );
  180. FF_USBDiskDelete( pxDisk );
  181. pxDisk = NULL;
  182. }
  183. else
  184. {
  185. pxDisk->xStatus.bIsInitialised = pdTRUE;
  186. pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
  187. if( FF_USBDiskMount( pxDisk ) == 0 )
  188. {
  189. FF_USBDiskDelete( pxDisk );
  190. pxDisk = NULL;
  191. }
  192. else
  193. {
  194. if( pcName == NULL )
  195. {
  196. pcName = "/";
  197. }
  198. FF_FS_Add( pcName, pxDisk );
  199. FF_PRINTF( "FF_USBDiskInit: Mounted Udisk as root \"%s\"\n", pcName );
  200. FF_USBDiskShowPartition( pxDisk );
  201. }
  202. } /* if( pxDisk->pxIOManager != NULL ) */
  203. } /* if( xPlusFATMutex != NULL) */
  204. } /* if( pxDisk != NULL ) */
  205. else
  206. {
  207. FF_PRINTF( "FF_USBDiskInit: Malloc failed\n" );
  208. }
  209. } /* if( xUSBDiskStatus == pdPASS ) */
  210. else
  211. {
  212. FF_PRINTF( "FF_USBDiskInit: prvUSBDisk_Init failed\n" );
  213. pxDisk = NULL;
  214. }
  215. return pxDisk;
  216. }
  217. /*-----------------------------------------------------------*/
  218. BaseType_t FF_USBDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )
  219. {
  220. FF_Error_t xError;
  221. BaseType_t xReturn = pdFAIL;
  222. xError = FF_Unmount( pxDisk );
  223. if( FF_isERR( xError ) != pdFALSE )
  224. {
  225. FF_PRINTF( "FF_USBDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
  226. }
  227. else
  228. {
  229. /* Format the drive - try FAT32 with large clusters. */
  230. xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE);
  231. if( FF_isERR( xError ) )
  232. {
  233. FF_PRINTF( "FF_USBDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
  234. }
  235. else
  236. {
  237. FF_PRINTF( "FF_USBDiskFormat: OK, now remounting\n" );
  238. pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
  239. xError = FF_USBDiskMount( pxDisk );
  240. FF_PRINTF( "FF_USBDiskFormat: rc %08x\n", ( unsigned )xError );
  241. if( FF_isERR( xError ) == pdFALSE )
  242. {
  243. xReturn = pdPASS;
  244. }
  245. }
  246. }
  247. return xReturn;
  248. }
  249. /*-----------------------------------------------------------*/
  250. /* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */
  251. BaseType_t FF_USBDiskMount( FF_Disk_t *pxDisk )
  252. {
  253. FF_Error_t xFFError;
  254. BaseType_t xReturn;
  255. /* Mount the partition */
  256. xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
  257. if( FF_isERR( xFFError ) )
  258. {
  259. FF_PRINTF( "FF_USBDiskMount: %08lX\n", xFFError );
  260. xReturn = pdFAIL;
  261. }
  262. else
  263. {
  264. pxDisk->xStatus.bIsMounted = pdTRUE;
  265. FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
  266. FF_USBDiskShowPartition( pxDisk );
  267. xReturn = pdPASS;
  268. }
  269. return xReturn;
  270. }
  271. /*-----------------------------------------------------------*/
  272. FF_IOManager_t *usbdisk_ioman( FF_Disk_t *pxDisk )
  273. {
  274. FF_IOManager_t *pxReturn;
  275. if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )
  276. {
  277. pxReturn = pxDisk->pxIOManager;
  278. }
  279. else
  280. {
  281. pxReturn = NULL;
  282. }
  283. return pxReturn;
  284. }
  285. /*-----------------------------------------------------------*/
  286. /* Release all resources */
  287. BaseType_t FF_USBDiskDelete( FF_Disk_t *pxDisk )
  288. {
  289. if( pxDisk != NULL )
  290. {
  291. pxDisk->ulSignature = 0;
  292. pxDisk->xStatus.bIsInitialised = 0;
  293. if( pxDisk->pxIOManager != NULL )
  294. {
  295. if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
  296. {
  297. FF_Unmount( pxDisk );
  298. }
  299. FF_DeleteIOManager( pxDisk->pxIOManager );
  300. }
  301. vPortFree( pxDisk );
  302. }
  303. return 1;
  304. }
  305. /*-----------------------------------------------------------*/
  306. BaseType_t FF_USBDiskShowPartition( FF_Disk_t *pxDisk )
  307. {
  308. FF_Error_t xError;
  309. uint64_t ullFreeSectors;
  310. uint32_t ulTotalSizeMB, ulFreeSizeMB;
  311. int iPercentageFree;
  312. FF_IOManager_t *pxIOManager;
  313. const char *pcTypeName = "unknown type";
  314. BaseType_t xReturn = pdPASS;
  315. if( pxDisk == NULL )
  316. {
  317. xReturn = pdFAIL;
  318. }
  319. else
  320. {
  321. pxIOManager = pxDisk->pxIOManager;
  322. FF_PRINTF( "Reading FAT and calculating Free Space\n" );
  323. switch( pxIOManager->xPartition.ucType )
  324. {
  325. case FF_T_FAT12:
  326. pcTypeName = "FAT12";
  327. break;
  328. case FF_T_FAT16:
  329. pcTypeName = "FAT16";
  330. break;
  331. case FF_T_FAT32:
  332. pcTypeName = "FAT32";
  333. break;
  334. default:
  335. pcTypeName = "UNKOWN";
  336. break;
  337. }
  338. FF_GetFreeSize( pxIOManager, &xError );
  339. ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
  340. iPercentageFree = ( int ) ( ( usbHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
  341. ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
  342. ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / usbSECTORS_PER_MB;
  343. ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / usbSECTORS_PER_MB );
  344. /* It is better not to use the 64-bit format such as %Lu because it
  345. might not be implemented. */
  346. FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
  347. FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
  348. FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
  349. FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
  350. FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
  351. FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
  352. FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
  353. }
  354. return xReturn;
  355. }
  356. /*-----------------------------------------------------------*/
  357. static int32_t prvUSBDisk_Init( void )
  358. {
  359. xUSBInfo = &usb_dev_desc[0];//use the first device
  360. return pdPASS;
  361. }
  362. /*-----------------------------------------------------------*/