📄 mmcmng.c
字号:
*
* This function reads or writes data from and to the FLASH Disk
* based on the 'reading' parameter.
*
* AUTHOR
*
* Victor Li
*
* INPUTS
*
* driveno The number assigned to the
* FLASH Disk (not used)
* dwLogicalPage The page number to read or
* write
* buffer Pointer to the data to be
* placed from a read or
* stored on a write
* uPages Number of bytes to be read
* or written
* reading Indicates whether or not we
* are reading or writing
*
* OUTPUTS
*
* YES Successful Completion.
* NO Block number is out of range.
*
* Note
*
* victor modify for quick R/W 2003/06/22
*
*************************************************************************/
INT __MmcIo(UINT16 driveno, UINT32 dwLogicalPage, VOID *buffer, UINT16 uPages, INT reading)
{
UINT32 dwPhysicalPage;
INT offset;
UINT8 *pB;
UINT32 dwTotalLen, dwReturnLen;
/* We don't use drive no. You could have multiple drives if wanted */
driveno = driveno;
pB = buffer;
dwTotalLen = 0;
while (uPages)
{
dwPhysicalPage = __MmcGetPhysicalPage(dwLogicalPage);
if(dwPhysicalPage == 0)
return 0;
offset = __MmcReadPhyEraseUnit(dwPhysicalPage, dwLogicalPage);
if(offset < 0)
return 0;
if (reading)
{
dwReturnLen = __MmcReadBytesBuf(offset, pB, FLASH_PAGE_SIZE);
if(dwReturnLen != FLASH_PAGE_SIZE)
return dwTotalLen;
}
else
{
UINT8 bModify;
// UINT32 dwEcc;
//读取Spare区Write标志
bModify = __MmcReadModifyFlag(dwPhysicalPage);
if(bModify == FLASH_FLAG_MODIFY)
{
//做要擦除标记
g_MmcDirty = 1; // set modify flash
}
else if(bModify == FLASH_FLAG_FREE)
{
//做临时修改标记
__MmcWriteModifyFlag(dwPhysicalPage, FLASH_FLAG_MODIFY_TEMP);
}
// else if(bModify == FLASH_FLAG_MODIFY_TEMP)
//已经做了临时修改标记,不处理
dwReturnLen = __MmcWriteBytesBuf(offset, pB, FLASH_PAGE_SIZE);
if(dwReturnLen != FLASH_PAGE_SIZE)
return dwTotalLen;
#ifdef FLASH_ECC_CHECK
dwEcc = __MmcEccCalc(pB);
__MmcWriteEccFlag(dwPhysicalPage, dwEcc);
#endif
}
uPages--;
dwLogicalPage++;
pB += FLASH_PAGE_SIZE;
dwTotalLen += dwReturnLen;
}
return dwTotalLen;
}
INT CardIo(UINT16 driveno, UINT32 dwLogicalPage, VOID *buffer, UINT16 uPages, INT reading)
{
INT nRet;
/* OPTION preempt_status;
preempt_status = NU_Change_Preemption(NU_NO_PREEMPT);*/
nRet = __MmcIo(driveno, dwLogicalPage, buffer, uPages, reading);
// NU_Change_Preemption(preempt_status);
return nRet;
}
BOOL __MmcWriteBlock(UINT32 dwOffset)
{
UINT16 i;
//写Data
if(__MmcWriteBytes(dwOffset, g_MmcReadBuf, g_MmcParam.uBlockSize, TRUE) != g_MmcParam.uBlockSize)
return FALSE;
//整理Spare区
for(i = 0; i < g_MmcParam.uBlockSize / g_MmcParam.uDataSize; i ++)
{
//将临时修改标记,改为真正的修改标志
if(__MmcReadModifyFlag(i) == FLASH_FLAG_MODIFY_TEMP)
__MmcWriteModifyFlag(i, FLASH_FLAG_MODIFY);
}
//写Spare区
if(__MmcWriteSpareBytes(dwOffset, g_MmcSpareBuf,
g_MmcParam.uBlockSize / g_MmcParam.uDataSize * g_MmcParam.uSpareSize, TRUE) !=
g_MmcParam.uBlockSize / g_MmcParam.uDataSize * g_MmcParam.uSpareSize)
return FALSE;
return TRUE;
}
BOOL __MmcUpdateBlock(BOOL bCurBlockGood)
{
UINT32 dwOffset;
UINT16 wTemp;
while(g_uMmcBlockPrepare)
{
//擦除备用块
dwOffset = (UINT32)g_MmcTablePrepare[0] * g_MmcParam.uBlockSize;
if(__MmcEraseBlock(dwOffset, TRUE) == TRUE)
{
#ifdef FLASH_ERASE_COUNTER
if(__MmcSetEraseCounter() != TRUE)
return FALSE;
#endif
if(__MmcWriteBlock(dwOffset) == TRUE)
break;
}
__MmcBadRegister(FLASH_STATUS_BAD_USER, g_MmcTablePrepare[0]);
memcpy(&g_MmcTablePrepare[0], &g_MmcTablePrepare[1], g_uMmcBlockPrepare * sizeof(UINT16));
g_uMmcBlockPrepare --;
g_uMmcBlockBadUser ++;
}
if(g_uMmcBlockPrepare == 0)
return FALSE;
//更新表
*(UINT16 *)(g_MmcTableLog2Phy + g_MmcLogicNum * sizeof(UINT16)) = g_MmcTablePrepare[0];
wTemp = g_MmcPhyNum;
g_MmcPhyNum = g_MmcTablePrepare[0];
g_MmcTablePrepare[0] = wTemp;
if(bCurBlockGood == FALSE)
{
__MmcBadRegister(FLASH_STATUS_BAD_USER, g_MmcTablePrepare[0]);
memcpy(&g_MmcTablePrepare[0], &g_MmcTablePrepare[1], g_uMmcBlockPrepare * sizeof(UINT16));
g_uMmcBlockPrepare --;
g_uMmcBlockBadUser ++;
}
return TRUE;
}
BOOL __MmcUpdate()
{
UINT32 dwOffset;
if(g_MmcModify)
{ // content has been modified
// xiaoming must modify it for backup block
if(g_MmcDirty)
{
//Replace标志加1
g_MmcSpareBuf[FLASH_REPLACE_OFFSET] ++;
g_MmcSpareBuf[FLASH_REPLACE_OFFSET] %= FLASH_REPLACE_MAXVALUE;
if(__MmcUpdateBlock(TRUE) == FALSE)
return FALSE; // there have some error
}
else
{
dwOffset = g_MmcPhyNum * g_MmcParam.uBlockSize;
if(__MmcWriteBlock(dwOffset) == FALSE)
{
if(__MmcUpdateBlock(FALSE) == FALSE)
return FALSE; // there have some error
}
}
}
return TRUE;
}
BOOL MmcUpdate()
{
BOOL bRet;
/* OPTION preempt_status;
preempt_status = NU_Change_Preemption(NU_NO_PREEMPT);*/
bRet = __MmcUpdate();
g_MmcPhyNum = -1;
g_MmcModify = 0;
g_MmcDirty = 0; // xiaoming must modify it
// NU_Change_Preemption(preempt_status);
return bRet;
}
INT __MmcReadPhyEraseUnit(INT dwPhysicalPage, INT dwLogicPage)
{
INT curEraseNum, dwOffset;
// get erase unit number which contains "dwPhysicalPage"
curEraseNum = dwPhysicalPage * g_MmcParam.uDataSize / g_MmcParam.uBlockSize;
if(curEraseNum != g_MmcPhyNum)
{ // if the erase unit has been in buffer, don't read it
if(__MmcUpdate() == FALSE)
{
g_MmcPhyNum = -1;
g_MmcModify = 0;
return -1; // there have some error
}
g_MmcPhyNum = curEraseNum;
g_MmcLogicNum = dwLogicPage * g_MmcParam.uDataSize / g_MmcParam.uBlockSize;
dwOffset = g_MmcPhyNum * g_MmcParam.uBlockSize;
//读取数据区
if(__MmcReadBytes(dwOffset, g_MmcReadBuf, g_MmcParam.uBlockSize) != g_MmcParam.uBlockSize)
{
g_MmcPhyNum = -1;
g_MmcModify = 0;
return -1; // there have some error
}
//读取Spare区
if(__MmcReadSpareBytes(dwOffset, g_MmcSpareBuf, g_MmcParam.uBlockSize / g_MmcParam.uDataSize * g_MmcParam.uSpareSize) != g_MmcParam.uBlockSize / g_MmcParam.uDataSize * g_MmcParam.uSpareSize)
{
g_MmcPhyNum = -1;
g_MmcModify = 0;
return -1; // there have some error
}
#ifdef FLASH_ECC_CHECK
//Compare ECC
if(__MmcCheckEcc() != TRUE)
{
g_MmcPhyNum = -1;
g_MmcModify = 0;
return -1; // there have some error
}
#endif
g_MmcModify = 0;
g_MmcDirty = 0; // xiaoming must modify it
}
return dwPhysicalPage * g_MmcParam.uDataSize - curEraseNum * g_MmcParam.uBlockSize;
}
INT __MmcReadBytesBuf(INT offset, UINT8 *pB, INT size)
{
memmove(pB, &g_MmcReadBuf[0] + offset, size);
/*#ifdef __PC__
memmove(pB, &g_MmcReadBuf[0] + offset, size);
#else
if ( (*((unsigned char *)TIMER_CONTROL_REG) & 0x01) == 0x01)
memmove(pB, &g_MmcReadBuf[0] + offset, size);
else
IDMA_MemCpy(pB, (UINT8*)&g_MmcReadBuf[0] + offset, size / 2, FLAG_IDMA_16BIT | FLAG_IDMA_TGTINC | FLAG_IDMA_SRCINC);
#endif*/
/* INT i;
for(i = 0; i < size; i++){
pB[i] = ~g_MmcReadBuf[offset + i];
}
*/ return size;
}
INT __MmcWriteBytesBuf(INT offset, UINT8 *pB, INT size)
{
memmove(&g_MmcReadBuf[0] + offset, pB, size);
/*#ifdef __PC__
memmove(&g_MmcReadBuf[0] + offset, pB, size);
#else
if ( (*((unsigned char *)TIMER_CONTROL_REG) & 0x01) == 0x01)
memmove(&g_MmcReadBuf[0] + offset, pB, size);
else
IDMA_MemCpy((UINT8*)&g_MmcReadBuf[0] + offset, pB, size / 2, FLAG_IDMA_16BIT | FLAG_IDMA_TGTINC | FLAG_IDMA_SRCINC);
#endif*/
/* INT i;
for(i = 0; i < size; i++){
g_MmcReadBuf[offset + i] = ~pB[i];
}
*/
g_MmcModify = 1; // set modify flash
return size;
}
UINT8 __MmcReadModifyFlag(UINT32 dwPage)
{
UINT32 wPage;
UINT32 wOffset;
wPage = dwPage % (g_MmcParam.uBlockSize / g_MmcParam.uDataSize);
wOffset = wPage * g_MmcParam.uSpareSize + (FLASH_MODIFY_OFFSET);
return g_MmcSpareBuf[wOffset];
}
UINT8 __MmcWriteModifyFlag(UINT32 dwPage, UINT8 byErase)
{
UINT32 wPage;
UINT32 wOffset;
wPage = dwPage % (g_MmcParam.uBlockSize / g_MmcParam.uDataSize);
wOffset = wPage * g_MmcParam.uSpareSize + (FLASH_MODIFY_OFFSET);
g_MmcSpareBuf[wOffset] = byErase;
return byErase;
}
#ifdef FLASH_ECC_CHECK
UINT32 __MmcEccCalc(UINT8* pBuf)
{
UINT32 dwEcc;
dwEcc = make_ecc_512Byte((pBuf));
dwEcc &= 0xFFFFFF;
return dwEcc;
}
UINT8 __MmcWriteEccFlag(UINT32 dwPage, UINT32 dwEcc)
{
UINT32 wPage;
UINT32 wOffset;
wPage = dwPage % (g_MmcParam.uBlockSize / g_MmcParam.uDataSize);
wOffset = wPage * g_MmcParam.uSpareSize + (FLASH_ECC_OFFSET - FLASH_PAGE_SIZE);
memcpy(&g_MmcSpareBuf[wOffset], &dwEcc, FLASH_ECC_LENGTH);
return 0;
}
BOOL __MmcCheckEcc()
{
UINT32 i;
UINT32 dwEccOffset;
UINT32 dwErrOffset;
UINT32 dwEccCalc, dwEccSave;
UINT32 dwCompare;
for(i = 0; i < g_MmcParam.uBlockSize / g_MmcParam.uDataSize; i ++)
{
dwEccCalc = __MmcEccCalc(&g_MmcReadBuf[i * FLASH_PAGE_SIZE]);
dwEccOffset = i * g_MmcParam.uSpareSize + (FLASH_ECC_OFFSET - FLASH_PAGE_SIZE);
memcpy(&dwEccSave, &g_MmcSpareBuf[dwEccOffset], FLASH_ECC_LENGTH);
dwCompare = compare_ecc(&dwEccCalc, &dwEccSave, &g_MmcReadBuf[i * FLASH_PAGE_SIZE], &dwErrOffset, g_MmcEccBuf);
if(dwCompare == 0) //ECC_NO_ERROR
continue;
else if(dwCompare == 1) //ECC_CORRECTABLE_ERROR
{
memcpy(&g_MmcReadBuf[i * FLASH_PAGE_SIZE], g_MmcEccBuf, FLASH_PAGE_SIZE);
continue;
}
else
return FALSE;
}
return TRUE;
}
#endif
INT CardCheck(UINT16 driveno)
{
extern BOOL IsCardExist(void);
if (IsCardExist())
{
return(NU_SUCCESS);
}
return (~NU_SUCCESS);
}
#ifdef FLASH_ERASE_COUNTER
#define ERASE_COUNT_UNIT 10
BOOL __MmcGetEraseCounter()
{
UINT32 i, j;
g_MmcEraseCounterBuf = (UINT8 *)MemAlloc(g_MmcParam.uBlockSize);
if(g_MmcEraseCounterBuf == NULL)
return FALSE;
//读出第一块数据
if(__MmcReadBytes(0, g_MmcEraseCounterBuf, g_MmcParam.uBlockSize) != g_MmcParam.uBlockSize)
return FALSE;
for(i = 0; i < g_MmcParam.uBlockSize; i ++)
{
if(g_MmcEraseCounterBuf[i] != 0)
{
for(j = 0; j < 8; j ++)
{
if(((g_MmcEraseCounterBuf[i] >> j) & 1) != 0)
break;
}
break;
}
}
g_dwMmcEraseCounter = (i * 8 + j) * ERASE_COUNT_UNIT;
i ++;
for(; i < g_MmcParam.uBlockSize; i ++)
{
//发现数据不合理,重新擦除
if(g_MmcEraseCounterBuf[i] != 0xFF)
{
if(SysGetLowVoltageStatus() == SYSTEM_FLASH_LOWVOL)
{
if(__MmcEraseBlock(0, FALSE) != TRUE)
return FALSE;
}
g_dwMmcEraseCounter = 0;
memset(g_MmcEraseCounterBuf, 0, g_MmcParam.uBlockSize);
break;
}
}
return TRUE;
}
BOOL __MmcSetEraseCounter()
{
UINT32 i, j;
g_dwMmcEraseCounter ++;
if((g_dwMmcEraseCounter % ERASE_COUNT_UNIT) == 0)
{
i = (g_dwMmcEraseCounter / ERASE_COUNT_UNIT - 1) / 8;
j = (g_dwMmcEraseCounter / ERASE_COUNT_UNIT - 1) % 8;
g_MmcEraseCounterBuf[i] &= (~(1 << j));
if(SysGetLowVoltageStatus() == SYSTEM_FLASH_LOWVOL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -