diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libnandfs/correctauxilliary.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libnandfs/correctauxilliary.c')
| -rw-r--r-- | libnandfs/correctauxilliary.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/libnandfs/correctauxilliary.c b/libnandfs/correctauxilliary.c new file mode 100644 index 00000000..510aeac4 --- /dev/null +++ b/libnandfs/correctauxilliary.c @@ -0,0 +1,81 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +static int +hammingdistance(uchar a, uchar b) +{ + uchar c; + int i, k; + if (a == b) + return 0; + c = a ^ b; + for (i = 0x80, k = 0; i; i >>= 1) + if (c & i) + k++; + return k; +} + +static int +allones(uchar *data, int len) +{ + while (len-- > 0) + if (*data++ != 0xff) + return 0; + return 1; +} + +LogfsLowLevelReadResult +_nandfscorrectauxiliary(NandfsAuxiliary *hdr) +{ + /* + * correct single bit errors, detect more than 1, in + * tag, signature + * TODO: add nerase and path protection + */ + LogfsLowLevelReadResult e; + int x; + int min, minx; + + e = LogfsLowLevelReadResultOk; + + min = 8; + minx = 0; + for (x = 0; x < _nandfsvalidtagscount; x++) { + int d = hammingdistance(hdr->tag, _nandfsvalidtags[x]); + if (d < min) { + min = d; + minx = x; + if (d == 0) + break; + } + } + if (min == 1) { + hdr->tag = _nandfsvalidtags[minx]; + e = LogfsLowLevelReadResultSoftError; + } + else if (min > 1) + e = LogfsLowLevelReadResultHardError; + else { + if (hdr->tag != LogfsTnone) { + ulong tmp = getbig4(hdr->parth); + if (tmp != 0xfffffffff && _nandfshamming31_26correct(&tmp)) { + putbig4(hdr->parth, tmp); + if (e != LogfsLowLevelReadResultOk) + e = LogfsLowLevelReadResultSoftError; + } + tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw); + if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) { + putbig2(hdr->nerasemagicmsw, tmp >> 16); + putbig2(hdr->nerasemagiclsw, tmp); + if (e != LogfsLowLevelReadResultOk) + e = LogfsLowLevelReadResultSoftError; + } + } + else if (allones((uchar *)hdr, sizeof(*hdr))) + e = LogfsLowLevelReadResultAllOnes; + } + + return e; +} |
