static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk ) { FF_PartitionParameters_t xPartition; FF_Error_t xError; /* Create a single partition that fills all available space on the disk. */ memset( &xPartition, '\0', sizeof( xPartition ) ); xPartition.ulSectorCount = pxDisk->ulNumberOfSectors; xPartition.ulHiddenSectors = ramHIDDEN_SECTOR_COUNT; xPartition.xPrimaryCount = ramPRIMARY_PARTITIONS; xPartition.eSizeType = eSizeIsQuota; /* Partition the disk */ xError = FF_Partition( pxDisk, &xPartition ); FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); if( FF_isERR( xError ) == pdFALSE ) { /* Format the partition. */ xError = FF_Format( pxDisk, 0, pdTRUE, pdTRUE ); FF_PRINTF( "FF_RAMDiskInit: FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); } return xError; }
FF_T_SINT32 FF_BlockWrite(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer, FF_T_BOOL aSemLocked) { FF_T_SINT32 slRetVal = 0; if(pIoman->pPartition->TotalSectors) { if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) { return (FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE); } } if(pIoman->pBlkDevice->fnpWriteBlocks) do { // Make sure we don't execute a NULL. #ifdef FF_BLKDEV_USES_SEM if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore) FF_PendSemaphore(pIoman->pBlkDevSemaphore); #endif slRetVal = pIoman->pBlkDevice->fnpWriteBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam); #ifdef FF_BLKDEV_USES_SEM if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore) FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore); #endif if(!FF_isERR(slRetVal) && FF_GETERROR(slRetVal) != FF_ERR_DRIVER_BUSY) { break; } FF_Sleep(FF_DRIVER_BUSY_SLEEP); } while (FF_TRUE); return slRetVal; }
const FF_T_INT8 *FF_GetErrDescription(FF_ERROR iErrorCode, char *apBuf, int aMaxlen) { if (FF_isERR(iErrorCode)) { snprintf (apBuf, aMaxlen, "%s::%s::%s", FF_GetErrModule(iErrorCode), FF_GetErrFunction(iErrorCode), FF_GetErrMessage(iErrorCode)); } else { snprintf (apBuf, aMaxlen, "No error"); } return apBuf; }
FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { FF_ERROR Error; #ifdef FF_WRITE_FREE_COUNT FF_BUFFER *pBuffer; #endif if(!pIoman->pPartition->FreeClusterCount) { pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); if(FF_isERR(Error)) { return Error; } } else { pIoman->pPartition->FreeClusterCount += Count; } #ifdef FF_WRITE_FREE_COUNT // FAT32 update the FSINFO sector. if(pIoman->pPartition->Type == FF_T_FAT32) { // Find the FSINFO sector. pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FSInfoLBA, FF_MODE_WRITE); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_INCREASEFREECLUSTERS; } if(FF_getLong(pBuffer->pBuffer, 0) == 0x41615252 && FF_getLong(pBuffer->pBuffer, 484) == 0x61417272) { // FSINFO sector magic nums we're verified. Safe to write. FF_putLong(pBuffer->pBuffer, 488, pIoman->pPartition->FreeClusterCount); FF_putLong(pBuffer->pBuffer, 492, pIoman->pPartition->LastFreeCluster); } } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } } #endif return FF_ERR_NONE; }
/** * @public * @brief Unmounts the active partition. * * @param pIoman FF_IOMAN Object. * * @return FF_ERR_NONE on success. **/ FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) { FF_ERROR RetVal = FF_ERR_NONE; #ifdef FF_MIRROR_FATS_UMOUNT FF_T_UINT i, y; FF_BUFFER *pBuffer; #endif if(!pIoman || !pIoman->pPartition) { return FF_ERR_NULL_POINTER | FF_UNMOUNTPARTITION; } if (!pIoman->pPartition->PartitionMounted) return FF_ERR_NONE; FF_PendSemaphore(pIoman->pSemaphore); // Ensure that there are no File Handles { if(!FF_ActiveHandles(pIoman)) { if(pIoman->FirstFile == NULL) { // Release Semaphore to call this function! FF_ReleaseSemaphore(pIoman->pSemaphore); RetVal = FF_FlushCache(pIoman); // Flush any unwritten sectors to disk. if(FF_isERR(RetVal)) { return RetVal; } // Reclaim Semaphore FF_PendSemaphore(pIoman->pSemaphore); pIoman->pPartition->PartitionMounted = FF_FALSE; #ifdef FF_MIRROR_FATS_UMOUNT FF_ReleaseSemaphore(pIoman->pSemaphore); for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) { pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ); if(!pBuffer) { RetVal = FF_ERR_DEVICE_DRIVER_FAILED | FF_UNMOUNTPARTITION; break; } for(y = 0; y < pIoman->pPartition->NumFATS; y++) { FF_BlockWrite(pIoman, pIoman->pPartition->FatBeginLBA + (y*pIoman->pPartition->SectorsPerFAT) + i, 1, pBuffer->pBuffer, FF_FALSE); } } FF_PendSemaphore(pIoman->pSemaphore); #endif } else { RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNTPARTITION; } } else { RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNTPARTITION; // Active handles found on the cache. } } FF_ReleaseSemaphore(pIoman->pSemaphore); return RetVal; }
/** * @private * @brief Releases a buffer resource. * * @param pIoman Pointer to an FF_IOMAN object. * @param pBuffer Pointer to an FF_BUFFER object. * **/ FF_ERROR FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) { FF_ERROR Error = FF_ERR_NONE; // Protect description changes with a semaphore. FF_PendSemaphore(pIoman->pSemaphore); { if (pBuffer->NumHandles) { pBuffer->NumHandles--; } else { //printf ("FF_ReleaseBuffer: buffer not claimed\n"); } #ifdef FF_CACHE_WRITE_THROUGH if(pBuffer->Modified == FF_TRUE) { Error = FF_BlockWrite(pIoman, pBuffer->Sector, 1, pBuffer->pBuffer, FF_TRUE); if(!FF_isERR(Error)) { // Ensure if an error occurs its still possible to write the block again. pBuffer->Modified = FF_FALSE; } } #endif } FF_ReleaseSemaphore(pIoman->pSemaphore); return Error; }
/** * @public * @brief Mounts the Specified partition, the volume specified by the FF_IOMAN object provided. * * The device drivers must adhere to the specification provided by * FF_WRITE_BLOCKS and FF_READ_BLOCKS. * * @param pIoman FF_IOMAN object. * @param PartitionNumber The primary partition number to be mounted. (0 - 3). * * @return 0 on success. * @return FF_ERR_NULL_POINTER if a pIoman object wasn't provided. * @return FF_ERR_IOMAN_INVALID_PARTITION_NUM if the partition number is out of range. * @return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION if no partition was found. * @return FF_ERR_IOMAN_INVALID_FORMAT if the master boot record or partition boot block didn't provide sensible data. * @return FF_ERR_IOMAN_NOT_FAT_FORMATTED if the volume or partition couldn't be determined to be FAT. (@see ff_config.h) * **/ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { FF_PARTITION *pPart; FF_BUFFER *pBuffer = 0; FF_ERROR Error; FF_T_UINT8 ucPartitionType; #ifdef FF_HASH_CACHE FF_T_INT i; #endif int partCount; if(!pIoman) { return FF_ERR_NULL_POINTER | FF_MOUNTPARTITION; } /*if(PartitionNumber > 3) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM; }*/ pPart = pIoman->pPartition; memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize); memset (pIoman->pCacheMem, '\0', pIoman->BlkSize * pIoman->CacheSize); #ifdef FF_HASH_CACHE for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { FF_ClearHashTable(pIoman->HashCache[i].pHashTable); } #endif FF_IOMAN_InitBufferDescriptors(pIoman); pIoman->FirstFile = 0; pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNTPARTITION; } partCount = FF_PartitionCount (pBuffer->pBuffer); pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); if (partCount == 0) { //(pPart->BlkSize % 512) == 0 && pPart->BlkSize > 0) { // Volume is not partitioned (MBR Found) pPart->BeginLBA = 0; } else { ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID); // Ensure its not an EFI partition! if(ucPartitionType != 0xEE) { if(PartitionNumber > 3) { Error = FF_ReleaseBuffer(pIoman, pBuffer); // Already returning an error, but an error from ReleaseBuf would override it. if(FF_isERR(Error)) { return Error; } return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MOUNTPARTITION; } // Primary Partitions to deal with! pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber)); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if(ucPartitionType == 0xEE) { pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA); Error = FF_GetEfiPartitionEntry(pIoman, PartitionNumber); if(FF_isERR(Error)) { return Error; } } if(!pPart->BeginLBA) { return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_MOUNTPARTITION; } // Now we get the Partition sector. pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNTPARTITION; } pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); if((pPart->BlkSize % 512) != 0 || pPart->BlkSize == 0) { Error = FF_ReleaseBuffer(pIoman, pBuffer); // An error here should override the current error, as its likely fatal. if(FF_isERR(Error)) { return Error; } return FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNTPARTITION; } } // Assume FAT16, then we'll adjust if its FAT32 pPart->ReservedSectors = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); pPart->FatBeginLBA = pPart->BeginLBA + pPart->ReservedSectors; pPart->NumFATS = (FF_T_UINT8) FF_getShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS); pPart->SectorsPerFAT = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT); pPart->SectorsPerCluster = FF_getChar(pBuffer->pBuffer, FF_FAT_SECTORS_PER_CLUS); pPart->BlkFactor = (FF_T_UINT8) (pPart->BlkSize / pIoman->BlkSize); // Set the BlockFactor (How many real-blocks in a fake block!). if(pPart->SectorsPerFAT == 0) { // FAT32 pPart->SectorsPerFAT = FF_getLong(pBuffer->pBuffer, FF_FAT_32_SECTORS_PER_FAT); pPart->RootDirCluster = FF_getLong(pBuffer->pBuffer, FF_FAT_ROOT_DIR_CLUSTER); pPart->ClusterBeginLBA = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT); pPart->TotalSectors = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); if(pPart->TotalSectors == 0) { pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_32_VOL_LABEL, sizeof pPart->VolLabel); } else { // FAT16 pPart->ClusterBeginLBA = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT); pPart->TotalSectors = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); pPart->RootDirCluster = 1; // 1st Cluster is RootDir! if(pPart->TotalSectors == 0) { pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_16_VOL_LABEL, sizeof pPart->VolLabel); } #ifdef FF_WRITE_FREE_COUNT pPart->FSInfoLBA = pPart->BeginLBA + FF_getShort(pBuffer->pBuffer, 48); #endif Error = FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally! if(FF_isERR(Error)) { return Error; } if(!pPart->BlkSize) { return FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNTPARTITION; } pPart->RootDirSectors = ((FF_getShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT) * 32) + pPart->BlkSize - 1) / pPart->BlkSize; pPart->FirstDataSector = pPart->ClusterBeginLBA + pPart->RootDirSectors; pPart->DataSectors = pPart->TotalSectors - (pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT) + pPart->RootDirSectors); if(!pPart->SectorsPerCluster) { return FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNTPARTITION; } pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster; Error = FF_DetermineFatType(pIoman); if(FF_isERR(Error)) { return Error; } pPart->PartitionMounted = FF_TRUE; pPart->LastFreeCluster = 0; #ifdef FF_MOUNT_FIND_FREE pPart->LastFreeCluster = FF_FindFreeCluster(pIoman, &Error); if(FF_isERR(Error)) { return Error; } pPart->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); if(FF_isERR(Error)) { return Error; } #else pPart->FreeClusterCount = 0; #endif return FF_ERR_NONE; }
static FF_ERROR FF_GetEfiPartitionEntry(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber) { // Continuing on from FF_MountPartition() pPartition->BeginLBA should be the sector of the GPT Header FF_BUFFER *pBuffer; FF_PARTITION *pPart = pIoman->pPartition; FF_T_UINT32 ulBeginGPT; FF_T_UINT32 ulEntrySector; FF_T_UINT32 ulSectorOffset; FF_T_UINT32 ulPartitionEntrySize; FF_T_UINT32 ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength; FF_ERROR Error; if(ulPartitionNumber >= 128) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY; } pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY; } // Verify this is an EFI header if(memcmp(pBuffer->pBuffer, "EFI PART", 8) != 0) { Error = FF_ReleaseBuffer(pIoman, pBuffer); // Already returning an error, but this error would override the current one. if(FF_isERR(Error)) { return Error; } return FF_ERR_IOMAN_INVALID_FORMAT | FF_GETEFIPARTITIONENTRY; } ulBeginGPT = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_PART_ENTRY_LBA); ulPartitionEntrySize = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_ENTRY_SIZE); ulGPTHeadCRC = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC); ulGPTHeadLength = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_LENGTH); // Calculate Head CRC // Blank CRC field FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, 0x00000000); // Calculate CRC ulGPTCrcCheck = FF_GetCRC32(pBuffer->pBuffer, ulGPTHeadLength); // Restore The CRC field FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } // Check CRC if(ulGPTHeadCRC != ulGPTCrcCheck) { return FF_ERR_IOMAN_GPT_HEADER_CORRUPT | FF_GETEFIPARTITIONENTRY; } // Calculate Sector Containing the Partition Entry we want to use. ulEntrySector = ((ulPartitionNumber * ulPartitionEntrySize) / pIoman->BlkSize) + ulBeginGPT; ulSectorOffset = (ulPartitionNumber % (pIoman->BlkSize / ulPartitionEntrySize)) * ulPartitionEntrySize; pBuffer = FF_GetBuffer(pIoman, ulEntrySector, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY; } pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if(!pPart->BeginLBA) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY; } return FF_ERR_NONE; }
/** * @private **/ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { FF_PARTITION *pPart; FF_BUFFER *pBuffer; FF_T_UINT32 testLong; FF_ERROR Error; if(pIoman) { pPart = pIoman->pPartition; if(pPart->NumClusters < 4085) { // FAT12 pPart->Type = FF_T_FAT12; #ifdef FF_FAT_CHECK #ifdef FF_FAT12_SUPPORT pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if((testLong & 0x3FF) != 0x3F8) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; } #else return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; #endif #endif #ifdef FF_FAT12_SUPPORT return FF_ERR_NONE; #endif } else if(pPart->NumClusters < 65525) { // FAT 16 pPart->Type = FF_T_FAT16; #ifdef FF_FAT_CHECK pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if(testLong == 0xFFF8) return FF_ERR_NONE; #endif } else { // FAT 32! pPart->Type = FF_T_FAT32; #ifdef FF_FAT_CHECK pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = FF_getLong(pBuffer->pBuffer, 0x0000); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) { // HT: // I had an SD-card which worked well in Linux/W32 // but FullFAT returned me this error // So for me I left out this check (just issue a warning for now) return FF_ERR_NONE; // FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #endif return FF_ERR_NONE; } } return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; }
/* This is the prototype of the function used to initialise the RAM disk driver. Other media drivers do not have to have the same prototype. In this example: + pcName is the name to give the disk within FreeRTOS+FAT's virtual file system. + pucDataBuffer is the start of the RAM to use as the disk. + ulSectorCount is effectively the size of the disk, each sector is 512 bytes. + xIOManagerCacheSize is the size of the IO manager's cache, which must be a multiple of the sector size, and at least twice as big as the sector size. */ FF_Disk_t *FF_RAMDiskInit( char *pcName, uint8_t *pucDataBuffer, uint32_t ulSectorCount, size_t xIOManagerCacheSize ) { FF_Error_t xError; FF_Disk_t *pxDisk = NULL; FF_CreationParameters_t xParameters; /* Check the validity of the xIOManagerCacheSize parameter. */ configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 ); configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) ); /* Attempt to allocated the FF_Disk_t structure. */ pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) ); if( pxDisk != NULL ) { /* Start with every member of the structure set to zero. */ memset( pxDisk, '\0', sizeof( FF_Disk_t ) ); /* Clear the entire space. */ memset( pucDataBuffer, '\0', ulSectorCount * ramSECTOR_SIZE ); /* The pvTag member of the FF_Disk_t structure allows the structure to be extended to also include media specific parameters. The only media specific data that needs to be stored in the FF_Disk_t structure for a RAM disk is the location of the RAM buffer itself - so this is stored directly in the FF_Disk_t's pvTag member. */ pxDisk->pvTag = ( void * ) pucDataBuffer; /* The signature is used by the disk read and disk write functions to ensure the disk being accessed is a RAM disk. */ pxDisk->ulSignature = ramSIGNATURE; /* The number of sectors is recorded for bounds checking in the read and write functions. */ pxDisk->ulNumberOfSectors = ulSectorCount; /* Create the IO manager that will be used to control the RAM disk. */ memset( &xParameters, '\0', sizeof xParameters ); xParameters.pucCacheMemory = NULL; xParameters.ulMemorySize = xIOManagerCacheSize; xParameters.ulSectorSize = ramSECTOR_SIZE; xParameters.fnWriteBlocks = prvWriteRAM; xParameters.fnReadBlocks = prvReadRAM; xParameters.pxDisk = pxDisk; /* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE. In this case the semaphore is only used to protect FAT data structures. */ xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex(); xParameters.xBlockDeviceIsReentrant = pdFALSE; pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError ); if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) ) { /* Record that the RAM disk has been initialised. */ pxDisk->xStatus.bIsInitialised = pdTRUE; /* Create a partition on the RAM disk. NOTE! The disk is only being partitioned here because it is a new RAM disk. It is known that the disk has not been used before, and cannot already contain any partitions. Most media drivers will not perform this step because the media will have already been partitioned. */ xError = prvPartitionAndFormatDisk( pxDisk ); if( FF_isERR( xError ) == pdFALSE ) { /* Record the partition number the FF_Disk_t structure is, then mount the partition. */ pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER; /* Mount the partition. */ xError = FF_Mount( pxDisk, ramPARTITION_NUMBER ); FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); } if( FF_isERR( xError ) == pdFALSE ) { /* The partition mounted successfully, add it to the virtual file system - where it will appear as a directory off the file system's root directory. */ FF_FS_Add( pcName, pxDisk ); } } else { FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); /* The disk structure was allocated, but the disk's IO manager could not be allocated, so free the disk again. */ FF_RAMDiskDelete( pxDisk ); pxDisk = NULL; } } else { FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" ); } return pxDisk; }