📄 fsmwritetask.c
字号:
/*****************************************************************************
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 + -