📄 ssfdc.c
字号:
/* We know there is an error, Check if it is fixable (one bit error in *//* 256 bytes of data is fixable). *//* *//* Parameters: *//* diff : The difference between the read and *//* calculated ECC. *//* *//* Returns: *//* TRUE if the error is fixable, otherwise FALSE. *//* *//*----------------------------------------------------------------------*/static FLBoolean isFixable (unsigned char FAR0 *diff){ int i, j; unsigned char mask; /* data is fixable if for each pair of bits one is 0 and one is 1 */ for (i = 0; i < 3; i++) for (j = 0, mask = 1; j < 4; j++, mask <<= 2) { if ((i == 2) && (j == 0)) continue; /* the two lowest bits in the 3rd byte are always 1 */ /* xor two neighbouring bits */ if (!(((diff[i] & mask) >> (2 * j)) ^ ((diff[i] & (mask << 1)) >> (2 * j + 1)))) return FALSE; } return TRUE;}/*----------------------------------------------------------------------*//* c h e c k A n d F i x *//* *//* Compare the calculated ECC and the one read from the device. *//* If there is a difference, try to fix the error. If both codes *//* are the same, data is correct. *//* *//* Parameters: *//* ecc1 : Calculated ECC. *//* ecc2 : Read ECC. *//* sectorToFix : The data to fix. *//* *//* Returns: *//* TRUE if data is correct or error fixed, otherwise FALSE. *//* *//*----------------------------------------------------------------------*/static FLBoolean checkAndFix(unsigned char FAR0 *ecc1, unsigned char FAR0 *ecc2, unsigned char FAR0 *sectorToFix){ if((ecc1[0] != ecc2[0]) || (ecc1[1] != ecc2[1]) || (ecc1[2] != ecc2[2])) { /* ECC error, try to fix */ unsigned char diff[3]; int i; for (i = 0; i < 3; i++) diff[i] = ecc1[i] ^ ecc2[i]; if (isFixable(diff)) { unsigned char line = 0, column = 0, mask; /* push the lower bits to the right */ for (i = 0, mask = 2; i < 4; i++, mask <<= 2) line |= (diff[0] & mask) >> (i + 1); /* push the upper bits to the left */ for (i = 0, mask = 0x80; i < 4; i++, mask >>= 2) line |= (diff[1] & mask) << i; /* push to the right */ for (i = 0, mask = 8; i < 3; i++, mask <<= 2) column |= (diff[2] & mask) >> (i + 3); sectorToFix[line] ^= 1 << column; /* fix */ return TRUE; } else { #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: ECC error in SSFDC.\n"); #endif return FALSE; } } else return TRUE;}/*----------------------------------------------------------------------*//* e c c O n R e a d *//* *//* Use ECC\EDC for a sector of data. Do each half seperately. *//* If there is a fixable error, fix it. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* sectorAddress : Physical address of the sector to check. *//* *//* Returns: *//* FALSE if there is an error that can't be fixed, otherwise *//* return TRUE. *//* *//*----------------------------------------------------------------------*/static FLBoolean eccOnRead(SSFDC vol, CardAddress sectorAddress){ unsigned char calcEcc[3], readEcc[3]; unsigned char FAR0 *sectorToFix = (unsigned char FAR0 *)vol.mappedSector; createEcc(sectorToFix, calcEcc); vol.flash.read(&vol.flash, sectorAddress + ECC1, readEcc, sizeof readEcc, EXTRA); if (checkAndFix(calcEcc, readEcc, sectorToFix)) { /* success in the first half go for the second half */ createEcc(sectorToFix + SECTOR_SIZE / 2, calcEcc); vol.flash.read(&vol.flash, sectorAddress + ECC2, readEcc, sizeof readEcc, EXTRA); if (checkAndFix(calcEcc, readEcc, sectorToFix + SECTOR_SIZE / 2)) return TRUE; } return FALSE;}#endif /* ECC_ON_READ *//******************* end of ECC\EDC part ********************************//*----------------------------------------------------------------------*//* u n i t B a s e A d d r e s s *//* *//* Returns the physical address of a unit. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* unitNo : Physical unit number *//* *//* Returns: *//* physical address of unitNo *//*----------------------------------------------------------------------*/static CardAddress unitBaseAddress(SSFDC vol, UnitNo unitNo){ return (CardAddress)unitNo << vol.unitSizeBits;}/*----------------------------------------------------------------------*//* v i r t u a l 2 P h y s i c a l *//* *//* Translate virtual sector number to physical address. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* sectorNo : Virtual sector number *//* *//* Returns: *//* physical address of sectorNo *//*----------------------------------------------------------------------*/static CardAddress virtual2Physical(SSFDC vol, SectorNo sectorNo){ unsigned unitOffset = (sectorNo % vol.sectorsPerUnit) << SECTOR_SIZE_BITS; UnitNo unitNo = vol.virtualUnits[sectorNo / vol.sectorsPerUnit]; StatusArea statusArea; /* no physical unit is assigned to this virtual sector number */ if (unitNo == NO_UNIT) return UNASSIGNED_ADDRESS; /* check if this sector was replaced */ vol.flash.read(&vol.flash, unitBaseAddress(&vol, unitNo) + unitOffset + STATUS_AREA_OFFSET, &statusArea, sizeof statusArea, EXTRA); if (statusArea.sectorStatus != 0xff) { if (vol.replacedUnit == unitNo) if (vol.replacementSectors[sectorNo % vol.sectorsPerUnit] == SECTOR_REPLACED) return unitBaseAddress(&vol, vol.transferUnit) + unitOffset; /* this sector was replaced */ return UNASSIGNED_ADDRESS; /* this sector is bad or deleted */ } return unitBaseAddress(&vol, unitNo) + unitOffset;}/*----------------------------------------------------------------------*//* p h y s i c a l 2 V i r t u a l *//* *//* Translate physical unit number to virtual unit number. Read virtual *//* unit number from first or second address area according to the *//* parameter addressAreaNo. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* unitNo : Physical unit number *//* addressAreaNo : Specify which address area to use *//* *//* Returns: *//* Virtual unit number of unitNo. *//*----------------------------------------------------------------------*/static UnitNo physical2Virtual(SSFDC vol, UnitNo unitNo, int addressAreaNo){ unsigned char addressArea[2]; UnitNo virtualUnitNo; int offset; offset = (addressAreaNo == OFFSET1 ? BLOCK_ADDRESS_OFFSET1 : BLOCK_ADDRESS_OFFSET2); /* get virtual unit no. from address area */ vol.flash.read(&vol.flash, unitBaseAddress(&vol, unitNo) + offset, addressArea, sizeof addressArea, EXTRA); /* trade places of byte 0 and byte 1 */ virtualUnitNo = ((UnitNo)addressArea[0] << 8) | addressArea[1]; /* virtual address is in bits 1 through 11 */ virtualUnitNo <<= 4; virtualUnitNo >>= 5; return virtualUnitNo;}/*----------------------------------------------------------------------*//* s e c t o r s I n V o l u m e *//* *//* Gets the total number of sectors in the volume *//* *//* Parameters: *//* vol : Pointer identifying drive *//* *//* Returns: *//* Number of sectors in the volume *//*----------------------------------------------------------------------*/static SectorNo sectorsInVolume(SSFDC vol){ return vol.virtualSectors;}/*----------------------------------------------------------------------*//* I d e n t i f y F o r m a t *//* *//* There are two different formats for nand devices, this function *//* tries to identify one of them by reading its ID string. If format is *//* identified, bootBlock holds the number of the unit where the boot *//* sector is. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* bootBlock : Receives the number of the block where the *//* boot sector is. *//* *//* Returns: *//* The type of the format idetified (SSFDC, NFTL, unknown) *//*----------------------------------------------------------------------*/static FormatType identifyFormat(SSFDC vol, UnitNo *bootBlock){ int i; unsigned char bootRecordId[10], invalidDataFlag; unsigned char formatPattern[10] = {FORMAT_PATTERN}; for (*bootBlock = 0; *bootBlock < vol.noOfUnits; (*bootBlock)++) { vol.flash.read(&vol.flash, unitBaseAddress(&vol, *bootBlock), bootRecordId, sizeof bootRecordId, 0); if (tffscmp(bootRecordId, "ANAND", 6) == 0) return ANAND_FORMAT; for (i = 0; (unsigned)i < vol.sectorsPerUnit; i++) { vol.flash.read(&vol.flash, unitBaseAddress(&vol, *bootBlock) + (i << SECTOR_SIZE_BITS), bootRecordId, sizeof bootRecordId, 0); if (tffscmp(bootRecordId, formatPattern, sizeof formatPattern) == 0) { /* check that the data is valid */ vol.flash.read(&vol.flash, unitBaseAddress(&vol, *bootBlock) + (i << SECTOR_SIZE_BITS) + CIS_DATA_OFFSET, &invalidDataFlag, sizeof invalidDataFlag, EXTRA); if (invalidDataFlag == 0xff) return SSFDC_FORMAT; } } } return BAD_FORMAT;}/*----------------------------------------------------------------------*//* i s E r a s e d s e c t o r *//* *//* Check if a sector is erased. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* unitNo : The sector to check is in this unit. *//* offset : Offset of the sector in the unit. *//* *//* Returns: *//* TRUE if the sector is erased, otherwise FALSE *//*----------------------------------------------------------------------*/static FLBoolean isErasedSector(SSFDC vol, UnitNo unitNo, unsigned offset){ unsigned char *buf; StatusArea statusArea; int i; buf = (unsigned char *)vol.flash.map(&vol.flash, unitBaseAddress(&vol, unitNo) + offset, SECTOR_SIZE); /* check data area */ for (i = 0; i < SECTOR_SIZE; i++) if (buf[i] != 0xff) return FALSE; /* check status area */ vol.flash.read(&vol.flash, unitBaseAddress(&vol, unitNo) + offset + STATUS_AREA_OFFSET, &statusArea, sizeof statusArea, EXTRA); if (statusArea.sectorStatus != 0xff) return FALSE; return TRUE;}/*----------------------------------------------------------------------*//* w r i t e A n d C h e c k *//* *//* Write one sector. If eccMode is TRUE, calculate and write ECC. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* address : Physical address of the sector to write to *//* fromAddress : Buffer of data to write *//* eccMode : If TRUE, calculate and write ECC *//* *//* Returns: *//* FLStatus : 0 on success, failed otherwise. *//*----------------------------------------------------------------------*/static FLStatus writeAndCheck(SSFDC vol, CardAddress address, void FAR1 *fromAddress, int eccMode){ int sectorInUnit; FLStatus status = vol.flash.write(&vol.flash,address,fromAddress,SECTOR_SIZE,0); if (eccMode) { /* calculate and write ECC */ unsigned char ecc[3]; createEcc((unsigned char FAR1 *)fromAddress, ecc); status = vol.flash.write(&vol.flash, address + ECC1, ecc, sizeof ecc, EXTRA); createEcc((unsigned char FAR1 *)fromAddress + SECTOR_SIZE / 2, ecc); status = vol.flash.write(&vol.flash, address + ECC2, ecc, sizeof ecc, EXTRA); } if (status == flWriteFault) { /* write failed, sector doesn't hold valid data. */ StatusArea statusArea = {0, 0xff}; vol.flash.write(&vol.flash, address + STATUS_AREA_OFFSET, &statusArea, sizeof statusArea,EXTRA); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -