summaryrefslogtreecommitdiff
path: root/libnandfs/ecc.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libnandfs/ecc.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libnandfs/ecc.c')
-rw-r--r--libnandfs/ecc.c98
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;
+}
+