diff options
Diffstat (limited to 'libnandfs/ecc.c')
| -rw-r--r-- | libnandfs/ecc.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/libnandfs/ecc.c b/libnandfs/ecc.c new file mode 100644 index 00000000..1cd86d20 --- /dev/null +++ b/libnandfs/ecc.c @@ -0,0 +1,98 @@ +#include "lib9.h" +#include "nandecc.h" + +static uchar ecctab[] = { + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, +}; + +ulong +nandecc(uchar *buf) +{ + int cp, zeros, ones, im; + int lp, om; + int i; + + cp = 0xff; + zeros = 0xff; + ones = 0xff; + for (i = 0; i < 256; i++) { + int tabent = ecctab[buf[i]]; + cp ^= tabent; + if (tabent & 1) { + zeros ^= ~i; + ones ^= i; + } + } + lp = 0; + for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) { + if (ones & im) + lp |= om; + om >>= 1; + if (zeros & im) + lp |= om; + } + return (((cp & 0xff) | 3) << 16) | lp; +} + +#define CORRECTABLEMASK 0x545555 + +NandEccError +nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad) +{ + ulong xorecc; + ulong mask; + int k; + + if (calcecc == *storedecc) + return NandEccErrorGood; + if (reportbad) + print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n", calcecc, *storedecc); + xorecc = calcecc ^ *storedecc; + if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) { + ulong imask; + ushort out; + ushort omask; + int line, col; + + for (imask = 0x800000, omask = 0x800, out = 0; imask; imask >>= 2, omask >>= 1) { + if (xorecc & imask) + out |= omask; + } + line = out & 0xff; + col = out >> 9; + if (reportbad) + print("nandecccorrect: single bit error line %d col %d\n", line, col); + buf[line] ^= (1 << col); + *storedecc = calcecc; + return NandEccErrorOneBit; + } + for (mask = 0x800000, k = 0; mask; mask >>= 1) + if (mask & xorecc) + k++; + if (k == 1) { + if (reportbad) + print("nandecccorrect: single bit error in ecc\n"); + // assume the stored ecc was wrong + *storedecc = calcecc; + return NandEccErrorOneBitInEcc; + } + if (reportbad) + print("nandecccorrect: 2 bit error\n"); + return NandEccErrorBad; +} + |
