⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 blkmdd.c

📁 一个SD卡和FAT16读写源代码
💻 C
字号:
//file: blkmdd.c
//功能:块设备模型设备驱动层
#include "fsdefs.h"
#include "blkmdd.h"
#include <memory.h>
static DS_MDDCB sg_mddcb;
static BOOL sg_isStarted=FALSE;
static U8 sg_sctBuf[CON_SectorSize];	//用电大户!


BOOL PHDRegisterHandlers(pfnPHDRdSct_t pfnRdSct, pfnPHDWrSct_t pfnWrSct)
{
	if (NULL==pfnRdSct || NULL==pfnWrSct)
	{
		return FALSE;
	}
	sg_mddcb.pfnPHDRdSct=pfnRdSct;
	sg_mddcb.pfnPHDWrSct=pfnWrSct;
	return TRUE;
}

#if CFG_CacheUnitCnt>=1

BOOL CacheInit()
{
	I32 i;
	DS_SctCache *p;
	p= sg_mddcb.cacheAry;
	for (i=0;i<CFG_CacheUnitCnt;i++,p++)
	{
		p->sctNum=CON_MaxU32;
	}
	return TRUE;
}

BOOL CacheSearch(U32 sctNum, DS_SctCache** OUT ppCch)
{
	IFAV i;
	DS_SctCache *p;
	p= sg_mddcb.cacheAry;
	for (i=0;i<CFG_CacheUnitCnt;i++,p++)
	{
		if (p->sctNum==sctNum)
		{
			break;
		}
	}

	if (i==CFG_CacheUnitCnt)
	{
		*ppCch=NULL;
		return FALSE;
	}
	else
	{
		*ppCch=p;
		return TRUE;
	}

}

BOOL CacheRelease(DS_SctCache *p)
{
	if (CON_MaxU32==p->sctNum)
	{
		return FALSE;
	}
	if (p->isDirty)
	{
		//数据已脏,需写回
		sg_mddcb.pfnPHDWrSct(p->sctNum, p->buf);
		#if CFG_IOStat==1
			sg_mddcb.stat.phdWrCnt++;
		#endif
	}
	return TRUE;
}

void CacheFlush()
{
	I32 i;
	DS_SctCache *p;
	p= sg_mddcb.cacheAry;
	for (i=0;i<CFG_CacheUnitCnt;i++,p++)
	{
		CacheRelease(p);
	}
}

//给除了pCch之外的所有cache单元增加闲置计数的值
void CacheIncIdleCnt(DS_SctCache *pCch)
{
	I32 i;
	DS_SctCache *p=sg_mddcb.cacheAry;
	for (i=0;i<CFG_CacheUnitCnt;i++,p++)
	{
		p->idleCnt++;
	}
	pCch->idleCnt--;
}

DS_SctCache* CacheFindMaxIdle()
{
	//找出最近最久没有使用的,或者是空闲的
	IFAV i, maxIdleCnt, maxIdleIdx;
	DS_SctCache *p;
	p= sg_mddcb.cacheAry;
	maxIdleCnt=0;
	maxIdleIdx=0;
	for (i=0;i<CFG_CacheUnitCnt;i++,p++)
	{
		if (CON_MaxU32==p->sctNum)
		{
			//使用此空闲的cache单元
			return p;
		}
		if ( p->idleCnt > maxIdleCnt )
		{
			//找到了一个更久没有使用的cache单元
			maxIdleCnt= p->idleCnt;
			maxIdleIdx= i;
		}
	}
	p= sg_mddcb.cacheAry+maxIdleIdx;
	return p;
}

//从cache中找到一个单元。这个函数比较高层,它在内部可能会处理cache内容替换
//参数:	idx: 指定的cache单元,若为CON_MaxUFAV则由本函数负责分配一个cache单元
//返回一个cache单元指针
DS_SctCache* CacheAlloc(UFAV idx, U32 sctNum)
{
	DS_SctCache *p;
	p= sg_mddcb.cacheAry;
	if (idx<CFG_CacheUnitCnt)
	{
		//重新分配该cache单元
		p= sg_mddcb.cacheAry+idx;
		CacheRelease(p);
		p->sctNum=CON_MaxU32;
		return p;
	}
	//正常情况下的分配cache
	//找出最近最久没有使用的,或者是空闲的
	p=CacheFindMaxIdle();
	CacheRelease(p);
	p->isDirty=FALSE;
	p->sctNum=sctNum;
	p->idleCnt=0;
	return p;
}

//这是一个cache与上层的接口函数,把sctNum扇区的内容加载到idx指示的cache单元中。如idx为CON_MaxU32,则自行寻找合适的cache单元
DS_SctCache* CacheLoad(U32 sctNum, UFAV idx, U32 rdByteCnt)
{
	DS_SctCache *pCch=NULL;
	CacheSearch(sctNum, &pCch);
	//无论如何都让cache中保有sctNum号扇区的数据,分两种情况
	if (pCch)
	{
		//cache命中
		#if CFG_IOStat
			sg_mddcb.stat.hitCnt++;			
			//sg_mddcb.stat.cacheRdByteCnt+=rdByteCnt;
		#endif
	}
	else
	{
		//cache没有命中,强行分配一个cache空间
		pCch=CacheAlloc(idx, sctNum);
		sg_mddcb.pfnPHDRdSct(sctNum, pCch->buf);
		#if CFG_IOStat
			sg_mddcb.stat.phdRdCnt++;
		#endif
	}
	CacheIncIdleCnt(pCch);
	#if CFG_IOStat
		sg_mddcb.stat.hitRatio= 1000*sg_mddcb.stat.hitCnt / sg_mddcb.stat.ioCnt;
	#endif
	return pCch;
}

//这是带有cache的读函数
uint8_t BlkMdd_read(uint32_t offset, uint8_t* OUT buffer, uint16_t length)
{
	U32 sctNum;
	U16 sctOfs,effSize;
	DS_SctCache *pCch;
	#if CFG_IOStat
		sg_mddcb.stat.rdCnt++;
		sg_mddcb.stat.ioCnt++;
		sg_mddcb.stat.rdByteCnt+=length;
	#endif
	sctNum= offset >> CON_SectorSizeShift;
	sctOfs= (U16)(offset & (CON_SectorSize-1));
	while (length>0)
	{		
		effSize= CON_SectorSize-sctOfs;
		if (effSize>length)
		{
			effSize=length;
		}
		pCch=CacheLoad(sctNum, CON_MaxU32,effSize);
		memcpy(buffer, pCch->buf+sctOfs, effSize);
		sctNum++;
		sctOfs=0;
		buffer+=effSize;
		length-=effSize;
	}
	return 1;
}
uint8_t BlkMdd_write(uint32_t offset, const uint8_t* IN buffer, uint16_t length)
{
	U32 sctNum;
	U16 sctOfs,effSize;
	DS_SctCache *pCch;
	#if CFG_IOStat
		sg_mddcb.stat.wrCnt++;
		sg_mddcb.stat.ioCnt++;
		sg_mddcb.stat.wrByteCnt+=length;
	#endif
	sctNum= offset >> CON_SectorSizeShift;
	sctOfs= (U16)(offset & (CON_SectorSize-1));
	while (length>0)
	{		
		effSize= CON_SectorSize-sctOfs;
		if (effSize>length)
		{
			effSize=length;
		}
		pCch=CacheLoad(sctNum, CON_MaxU32,effSize);
		//把内容写到cache中
		memcpy(pCch->buf+sctOfs, buffer, effSize);
		pCch->isDirty=TRUE;
		sctNum++;
		sctOfs=0;
		buffer+=effSize;
		length-=effSize;
	}
	return 1;
}
#else
uint8_t BlkMdd_read(uint32_t offset, uint8_t* OUT buffer, uint16_t length)
{
	U32 sctNum;
	U16 sctOfs,effSize, rdSize;
	sctNum= offset >> CON_SectorSizeShift;
	sctOfs= (U16)(offset & (CON_SectorSize-1));
	rdSize=0;
#	if CFG_IOStat==1
	sg_mddcb.stat.rdCnt++;
	sg_mddcb.stat.rdByteCnt+= length;
#endif

	//无cache的情况
	if (0==sctOfs && CON_SectorSize==length)
	{
		sg_mddcb.pfnPHDRdSct(sctNum, buffer);
#if CFG_IOStat==1		
		sg_mddcb.stat.phdRdCnt++;
#endif
		return 1;
	}
	else
	{
		while(length>0)
		{
			if (sctOfs==0 && length>=CON_SectorSize)
			{
				//无需借用sg_sctBuf,直接读到buffer
				effSize=CON_SectorSize;
				sg_mddcb.pfnPHDRdSct(sctNum, buffer);
#if CFG_IOStat==1		
				sg_mddcb.stat.phdRdCnt++;
#endif
			}
			else
			{
				//先读入到sg_sctBuf
				sg_mddcb.pfnPHDRdSct(sctNum, sg_sctBuf);
#if CFG_IOStat==1		
				sg_mddcb.stat.phdRdCnt++;
#endif
				//内存拷贝
				effSize= CON_SectorSize-sctOfs;
				if (effSize>length)
				{
					effSize=length;
				}
				memcpy(buffer,sg_sctBuf+sctOfs,effSize);
			}
			//更新buffer,length的值
			buffer+=effSize;
			length-=effSize;
			sctOfs=0;
			sctNum++;
		}
	}
	return 1;	
}

uint8_t BlkMdd_write(uint32_t offset, const uint8_t* IN buffer, uint16_t length)
{
	U32 sctNum;
	U16 sctOfs,effSize, wrSize;
	sctNum= offset >> CON_SectorSizeShift;
	sctOfs= (U16)(offset & (CON_SectorSize-1));
	wrSize=0;

#if CFG_IOStat==1
	sg_mddcb.stat.wrCnt++;
	sg_mddcb.stat.wrByteCnt+= length;
#endif

	if ( 0==sctOfs && CON_SectorSize==length)
	{
		//刚好对齐到一个扇区
		sg_mddcb.pfnPHDWrSct(sctNum,buffer);
#if CFG_IOStat==1		
		sg_mddcb.stat.phdWrCnt++;
#endif
		return 1;
	}

	while(length>0)
	{
		if (sctOfs==0 && length>=CON_SectorSize)
		{
			//无需先读入部分内容,直接写
			effSize=CON_SectorSize;
			sg_mddcb.pfnPHDWrSct(sctNum, buffer);
#if CFG_IOStat==1		
			sg_mddcb.stat.phdWrCnt++;
#endif
		}
		else
		{
			//先读入扇区原来的内容
			sg_mddcb.pfnPHDRdSct(sctNum, sg_sctBuf);
#if CFG_IOStat==1		
			sg_mddcb.stat.phdRdCnt++;
#endif
			effSize= CON_SectorSize-sctOfs;
			if (effSize>length)
			{
				effSize=length;
			}
			//更改需要写入的部分
			memcpy(sg_sctBuf+sctOfs,buffer,effSize);
			//把更改后的数据写回
			sg_mddcb.pfnPHDWrSct(sctNum, sg_sctBuf);
#if CFG_IOStat==1
			sg_mddcb.stat.phdWrCnt++;
#endif
		}
		//更新buffer,length的值
		buffer+=effSize;
		length-=effSize;
		sctOfs=0;
		sctNum++;
	}
	return 1;	
}
#endif
uint8_t BlkMdd_read_interval(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, BlkMdd_read_interval_handler_t callback, void* p)
{

	if(!buffer || interval == 0 || length < interval || !callback)
		return 0;

	while(length >= interval)
	{
		/* as reading is now buffered, we directly
		* hand over the request to sd_raw_read()
		*/
		if(!BlkMdd_read(offset, buffer, interval))
			return 0;
		if(!callback(buffer, offset, p))
			break;
		offset += interval;
		length -= interval;
	}
	return 1;
}

uint8_t BlkMdd_write_interval(uint32_t offset, uint8_t* buffer, uint16_t length, BlkMdd_write_interval_handler_t callback, void* p)
{

	uint8_t endless = (length == 0);
	uint16_t bytes_to_write;
	if(!buffer || !callback)
		return 0;

	while(endless || length > 0)
	{
		bytes_to_write = callback(buffer, offset, p);
		if(!bytes_to_write)
			break;
		if(!endless && bytes_to_write > length)
			return 0;

		/* as writing is always buffered, we directly
		* hand over the request to sd_raw_write()
		*/
		if(!BlkMdd_write(offset, buffer, bytes_to_write))
			return 0;

		offset += bytes_to_write;
		length -= bytes_to_write;
	}

	return 1;
}


BOOL BlkMdd_Startup()
{
	BOOL boolRet;
	if (sg_isStarted)
	{
		return TRUE;
	}
	//先初始化物理设备
	boolRet=PHDInits();
	if (!boolRet || NULL==sg_mddcb.pfnPHDRdSct || NULL==sg_mddcb.pfnPHDWrSct)
	{
		return FALSE;
	}
#if CFG_CacheUnitCnt>=1
	CacheInit();
#endif

#if CFG_IOStat==1
	memset( &sg_mddcb.stat ,0 ,sizeof(sg_mddcb.stat));
#endif
	sg_isStarted=TRUE;
	return TRUE;
}

BOOL BlkMdd_Cleanup()
{
	if (!sg_isStarted)
	{
		return TRUE;
	}
	PHDCleanup();
	#if CFG_CacheUnitCnt>=1
		CacheFlush();
	#endif
	sg_isStarted=FALSE;
	return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -