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

📄 fsmwritetask.c

📁 norflash的文件系统。 用于中低端手机开发的参考
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************
 
  FILE NAME: FsmWriteTask.c

  DESCRIPTION:

    Implement a background task to sevice the write requests
	buffered in the queue.

 Copyright (c) 2002, VIA Technologies, Inc.
*****************************************************************************/


#include "fsmdefs.h"
#include "FsmDfs.h"
#include "FsmFlash.h"
#include "FsmQueue.h"



extern FsmDevObjHdrT *				FsmDataItemDevObjP;
extern FsmDfsFileDescriptorT		FsmDfsFds[];



/********************************************************************
*	GetFreeLsn
*     Find a free Logical Sector Number.
*
*	Input:
*
*	Output:
*
*	return:
*		success:	ERR_NONE.
*		failure:	ERR_FULL.
*********************************************************************/

static uint32 GetFreeLsn(FsmDevObjHdrT * DevP, uint32 * NewLsnP)
{
	uint32 				LsnNum, MaxLsn;
	FsmFlashMediaT *	MediaObjP;

	MediaObjP = (FsmFlashMediaT * )DevP->MediaObjP;
	MaxLsn = MediaObjP->MaxPsn;

	/*
	 * Write-Task need not obtain the Map-Table Lock when read
	 * map information, because only the Write-Task will update 
	 * Lsn2Psn map table, all other tasks are just to read that
	 * table.
	 */
	for (LsnNum = 0; LsnNum < MaxLsn; LsnNum++)
	{
		if (MediaObjP->Lsn2PsnP[LsnNum] == INVALID_PSN)
		{
			if (FsmGetMtxSem(MediaObjP->MapTblLock) != ERR_NONE)
			{
				return ERR_SYSTEM;
			}

			/* With the PENDING_PSN flag, all comments about this 
			 * function have been invalid. There is no limitation 
			 * now when call to this function. The consecutive 
			 * calls to this function will return right value.
			 */
			MediaObjP->Lsn2PsnP[LsnNum] = PENDING_PSN;

			if (FsmReleaseMtxSem(MediaObjP->MapTblLock) != ERR_NONE)
			{
				return ERR_SYSTEM;
			}

			*NewLsnP = LsnNum;

			return ERR_NONE;
		}
	}

	/************************* !! NOTE !! ******************************
	 *
	 * After a LSN is allocated, we haven't marked this LSN until 
	 * the PSN is mapped to this LSN. so, two successive call this
	 * funtion will return the same LSN.
	 *******************************************************************/

	return ERR_FULL;
}


/********************************************************************
*	GetFreePsn
*     Allocte a free Sector.
*
*	Input:
*
*	Output:
*			The Physical Sector Number on success.
*	return:
*		success:	ERR_NONE.
*		failure:	ERR_FULL or ERR_SYSTEM.
*********************************************************************/

static uint32 GetFreePsn(FsmDevObjHdrT * DevP, uint32 * NewPsnP)
{
	uint32				i;
	uint32				blk_num = (uint32)(-1);
	uint32				min_cnt = (uint32)(-1);
	uint32				PsnNum;
	FsmFlashMediaT *	MediaObjP;

	MediaObjP = (FsmFlashMediaT *)DevP->MediaObjP;

	for (i = 0; i < ((FsmFlashDevT *)DevP)->Blocks; i++)
	{
		if ((i == MediaObjP->SpareBlk) ||
			(MediaObjP->BlockInfoP[i].FreeSectors == 0))
		{
			continue;
		}

		if (min_cnt > MediaObjP->BlockInfoP[i].EraseCount)
		{
			blk_num = i;
			min_cnt = MediaObjP->BlockInfoP[i].EraseCount;
		}
	}

	if (blk_num != (uint32)(-1))
	{
		PsnNum = (blk_num + 1) * MediaObjP->SectorsPerBlock 
			- MediaObjP->BlockInfoP[blk_num].FreeSectors;

		if (FsmGetMtxSem(MediaObjP->InfoLock) != ERR_NONE)
		{
			return ERR_SYSTEM;
		}

		MediaObjP->BlockInfoP[blk_num].FreeSectors--;
		MediaObjP->BlockInfoP[blk_num].UsedSectors++;

		if (FsmReleaseMtxSem(MediaObjP->InfoLock) != ERR_NONE)
		{
			return ERR_SYSTEM;
		}

		*NewPsnP = PsnNum;

		return ERR_NONE;
	}
	else
	{
		return ERR_FULL;
	}
}


/********************************************************************
*	DirModify
*     Find a free Directory Entry. This function will reclaim 
*     the dirtiest sector.
*
*	Input:
*
*	Output:
*			The address of the free directory entry.
*	return:
*		success:	ERR_NONE.
*		failure:	error code.
*********************************************************************/

static uint32 DirModify(
	FsmDevObjHdrT * DevP,
	uint32 PrntLsn, 
	uint32 * AddrP, 
	uint8 type,
	uint32	DirtiestLsn
	)
{
	uint32				i;

	uint16				EntryStatus;
	FsmFlashSectorHdrT	SectorHdr;
	uint32				ret;

	uint16				EntrySize;
	uint16				EntriesPerSector;
	uint16				BlkNum;

	uint32				offset;
	uint32				size;

	uint32				OldEntryAddr;
	uint32				NewEntryAddr;

	uint32				OldSectorAddr;
	uint32				NewSectorAddr;
	uint32				OldPsn;
	uint32				NewPsn;

	FsmFlashMediaT *	MediaObjP;

	DEV_COPY_FUNCPTR	DevCopy = DevP->DevDrvP->FsmDevCopy;
	DEV_WRITE_FUNCPTR	DevWrite = DevP->DevDrvP->FsmDevWrite;
	DEV_READ_FUNCPTR	DevRead = DevP->DevDrvP->FsmDevRead;

	MediaObjP = (FsmFlashMediaT * )DevP->MediaObjP;

	if (type == QUEUE_FILE_DIR)
	{
		EntrySize = sizeof(FsmFileDirEntryT);
		offset    = FIELD_OFFSET(FsmFileDirEntryT, Status);
		size      = FIELD_SIZE(  FsmFileDirEntryT, Status);
	}
	else
	{
		EntrySize = sizeof(FsmItemDirEntryT);
		offset    = FIELD_OFFSET(FsmItemDirEntryT, Status);
		size      = FIELD_SIZE(  FsmItemDirEntryT, Status);
	}

	EntriesPerSector = (uint16)(MediaObjP->SectorSize / EntrySize);

	ret = GetFreePsn(DevP, &NewPsn);

	if (ret != ERR_NONE)
	{
		return ret;
	}

	NewSectorAddr = DfsPsn2Addr(MediaObjP, NewPsn);

	OldPsn = DfsLsn2Psn(MediaObjP, DirtiestLsn);
	OldSectorAddr = DfsPsn2Addr(MediaObjP, OldPsn);

	/* Read Old sector information. */
	ret = DevRead( DevP,
				   (uint8 *)&SectorHdr,
				   OldSectorAddr,
				   sizeof(FsmFlashSectorHdrT)
				   );

	if(ret != ERR_NONE)
		return ret;

	/* new sector state to writing */
	SectorHdr.Status = SECTOR_WRITING;
	ret = DevWrite( DevP,
					(uint8 *)&SectorHdr.Status,
					NewSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status),
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);

	if(ret != ERR_NONE)
		return ret;

	/* Write the whole header. */
	ret = DevWrite(DevP, (uint8 *)&SectorHdr, NewSectorAddr, sizeof(FsmFlashSectorHdrT));

	if(ret != ERR_NONE)
		return ret;

	NewEntryAddr = NewSectorAddr + sizeof(FsmFlashSectorHdrT);
	OldEntryAddr = OldSectorAddr + sizeof(FsmFlashSectorHdrT);

	for ( i = 0; i < EntriesPerSector; i++, OldEntryAddr += EntrySize)
	{
		EntryStatus = 0;

		ret =  DevRead( DevP, 
						(uint8 *)&EntryStatus, 
						 /* OldSectorAddr+ sizeof(FsmFlashSectorHdrT) + i * EntrySize + offset, */
						 OldEntryAddr + offset,
						 size
						 );

		if(ret != ERR_NONE)	
			return ret;

		if (EntryStatus != ENTRY_VALID)
		{
			/* All Sectors and entries that are needed for new command are pre-allcated,
			so, there is no mid-state sector or entry existed when this routine is called. */
			continue;
		}

		ret =  DevCopy( DevP, 
						NewEntryAddr,
						OldEntryAddr,
						EntrySize
						);

		if(ret != ERR_NONE)
			return ret;

		NewEntryAddr += EntrySize;
	}

	*AddrP = NewEntryAddr;

	if (FsmGetMtxSem(MediaObjP->MapTblLock) != ERR_NONE)
	{
		return ERR_SYSTEM;
	}

	MediaObjP->Lsn2PsnP[DirtiestLsn] = NewPsn;

	if (FsmReleaseMtxSem(MediaObjP->MapTblLock) != ERR_NONE)
	{
		return ERR_SYSTEM;
	}

	/* new sector state to updating */
	SectorHdr.Status = SECTOR_UPDATING;
	ret = DevWrite( DevP, 
					(uint8*)&SectorHdr.Status, 
					NewSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status), 
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);

	if(ret != ERR_NONE)
		return ret;

	/* old sector state to deleting */
	SectorHdr.Status = SECTOR_DELETING;
	ret = DevWrite( DevP, 
					(uint8*)&SectorHdr.Status, 
					OldSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status),
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);	

	if(ret != ERR_NONE)
		return ret;

	/* new sector state to valid */
	SectorHdr.Status = SECTOR_VALID;
	ret = DevWrite( DevP,
					(uint8*)&SectorHdr.Status, 
					NewSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status),
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);

	if(ret != ERR_NONE)
		return ret;

	/* old sector state to invalid */
	SectorHdr.Status = SECTOR_INVALID;
	ret = DevWrite( DevP, 
					(uint8*)&SectorHdr.Status, 
					OldSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status),
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);	

	if(ret != ERR_NONE)
		return ret;

	BlkNum = (uint16)(OldPsn / MediaObjP->SectorsPerBlock);

	if (FsmGetMtxSem(MediaObjP->InfoLock) != ERR_NONE)
	{
		return ERR_SYSTEM;
	}

	MediaObjP->BlockInfoP[BlkNum].DirtySectors += 1;
	MediaObjP->BlockInfoP[BlkNum].UsedSectors -= 1;

	if (FsmReleaseMtxSem(MediaObjP->InfoLock) != ERR_NONE)
	{
		return ERR_SYSTEM;
	}

	return ERR_NONE;
}


/********************************************************************
*	DirAppend
*     Append a new sector to the directory entry sector list, 
*     and return the address of the first free directory entry.
*     
*
*	Input:
*
*	Output:
*			The address of the free directory entry.
*	return:
*		success:	ERR_NONE.
*		failure:	error code.
*********************************************************************/

static uint32 DirAppend(
	FsmDevObjHdrT * DevP,
	uint32 PrntLsn, 
	uint32 * AddrP, 
	uint8 type)
{
	uint32				tempLsn;
	uint32				ret;
	uint16				SectorStatus;
	uint16				BlkNum;

	FsmFlashSectorHdrT	SectorHdr;

	uint32				OldPsn, OldSectorAddr;
	uint32				LastLsn, NewPsn;
	uint32				AppendLsn, AppendPsn;

	uint32				NewSectorAddr, AppendSectorAddr;

	FsmFlashMediaT *	MediaObjP;

	DEV_COPY_FUNCPTR	DevCopy = DevP->DevDrvP->FsmDevCopy;
	DEV_WRITE_FUNCPTR	DevWrite = DevP->DevDrvP->FsmDevWrite;
	DEV_READ_FUNCPTR	DevRead = DevP->DevDrvP->FsmDevRead;

	MediaObjP = (FsmFlashMediaT * )DevP->MediaObjP;

	LastLsn = PrntLsn;

	/* located the link end sector. */
	while(TRUE)
	{
		OldPsn = DfsLsn2Psn(MediaObjP, LastLsn);
		OldSectorAddr = DfsPsn2Addr(MediaObjP, OldPsn);

		ret = DevRead( DevP, 
					   (uint8 *)&tempLsn,
					   OldSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, NextLsn), 
					   FIELD_SIZE(FsmFlashSectorHdrT, NextLsn)
					   );

		if(ret != ERR_NONE)
			return ret;

		if (tempLsn == (uint32)(-1))
		{
			break;
		}

		LastLsn = tempLsn;
	}

	OldPsn = DfsLsn2Psn(MediaObjP, LastLsn);
	OldSectorAddr = DfsPsn2Addr(MediaObjP, OldPsn);

	ret = GetFreePsn(DevP, &NewPsn);

	if (ret != ERR_NONE)
	{
		return ret;
	}

	NewSectorAddr = DfsPsn2Addr(MediaObjP, NewPsn);

	ret = GetFreeLsn(DevP, &AppendLsn);

	if (ret != ERR_NONE)
	{
		return ret;
	}

	ret = GetFreePsn(DevP, &AppendPsn);

	if (ret != ERR_NONE)
	{
		return ret;
	}

	AppendSectorAddr = DfsPsn2Addr(MediaObjP, AppendPsn);

	*AddrP = AppendSectorAddr + sizeof(FsmFlashSectorHdrT);

	/* read sector header from old sector. */
	ret = DevRead( DevP,
				   (uint8 *)&SectorHdr, 
				   OldSectorAddr,
				   sizeof(FsmFlashSectorHdrT)
				   );

	if(ret != ERR_NONE)
		return ret;

	/* new sector state to writing state. */
	SectorHdr.Status = SECTOR_WRITING;
	ret = DevWrite( DevP,
					(uint8 *)&SectorHdr.Status,
					NewSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status),
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);

	if(ret != ERR_NONE)
		return ret;

	SectorHdr.NextLsn = AppendLsn;
	ret = DevWrite(DevP, (uint8 *)&SectorHdr, NewSectorAddr, sizeof(FsmFlashSectorHdrT));		

	if(ret != ERR_NONE)
		return ret;

	/* appended sector state to writing state. */
	ret = DevWrite( DevP,
					(uint8 *)&SectorHdr.Status,
					AppendSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status),
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);

	if(ret != ERR_NONE)
		return ret;

	SectorHdr.Lsn = AppendLsn;
	SectorHdr.NextLsn = (uint32)(-1);
	ret = DevWrite(DevP, (uint8 *)&SectorHdr, AppendSectorAddr, sizeof(FsmFlashSectorHdrT));

	if(ret != ERR_NONE)
		return ret;

	ret = DevCopy(  DevP,
					NewSectorAddr + sizeof(FsmFlashSectorHdrT), 
					OldSectorAddr + sizeof(FsmFlashSectorHdrT), 
					MediaObjP->SectorSize
					);

	if(ret != ERR_NONE)
		return ret;

	if (FsmGetMtxSem(MediaObjP->MapTblLock) != ERR_NONE)
	{
		return ERR_SYSTEM;
	}
	MediaObjP->Lsn2PsnP[LastLsn] = NewPsn;
	MediaObjP->Lsn2PsnP[AppendLsn] = AppendPsn;
	if (FsmReleaseMtxSem(MediaObjP->MapTblLock) != ERR_NONE)
	{
		return ERR_SYSTEM;
	}

	/* appended sector state to allocated */
	SectorStatus = SECTOR_ALLOCATED;
	ret = DevWrite( DevP, 
					(uint8 *)&SectorStatus,
					AppendSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status),
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);

	if(ret != ERR_NONE)
		return ret;

	/* new sector state to appending */
	SectorStatus = SECTOR_APPENDING;
	ret = DevWrite( DevP, 
					(uint8 *)&SectorStatus, 
					NewSectorAddr + FIELD_OFFSET(FsmFlashSectorHdrT, Status), 
					FIELD_SIZE(FsmFlashSectorHdrT, Status)
					);

	if(ret != ERR_NONE)
		return ret;

	/* old sector to deleting */
	SectorStatus = SECTOR_DELETING;
	ret = DevWrite( DevP, 

⌨️ 快捷键说明

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