/*- * Copyright (C) 2009 Semihalf, Grzegorz Bernacki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #define BIT0(x) ((x) & 0x1) #define BIT1(x) (BIT0(x >> 1)) #define BIT2(x) (BIT0(x >> 2)) #define BIT3(x) (BIT0(x >> 3)) #define BIT4(x) (BIT0(x >> 4)) #define BIT5(x) (BIT0(x >> 5)) #define BIT6(x) (BIT0(x >> 6)) #define BIT7(x) (BIT0(x >> 7)) void calculate_ecc(const uint8_t *buf, uint8_t *ecc) { uint8_t p8, byte; int i; memset(ecc, 0, 3); for (i = 0; i < 256; i++) { byte = buf[i]; ecc[0] ^= (BIT0(byte) ^ BIT2(byte) ^ BIT4(byte) ^ BIT6(byte)) << 2; ecc[0] ^= (BIT1(byte) ^ BIT3(byte) ^ BIT5(byte) ^ BIT7(byte)) << 3; ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT4(byte) ^ BIT5(byte)) << 4; ecc[0] ^= (BIT2(byte) ^ BIT3(byte) ^ BIT6(byte) ^ BIT7(byte)) << 5; ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ BIT3(byte)) << 6; ecc[0] ^= (BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ BIT7(byte)) << 7; p8 = BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ BIT3(byte) ^ BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ BIT7(byte); if (p8) { ecc[2] ^= (0x1 << BIT0(i)); ecc[2] ^= (0x4 << BIT1(i)); ecc[2] ^= (0x10 << BIT2(i)); ecc[2] ^= (0x40 << BIT3(i)); ecc[1] ^= (0x1 << BIT4(i)); ecc[1] ^= (0x4 << BIT5(i)); ecc[1] ^= (0x10 << BIT6(i)); ecc[1] ^= (0x40 << BIT7(i)); } } ecc[0] = ~ecc[0]; ecc[1] = ~ecc[1]; ecc[2] = ~ecc[2]; ecc[0] |= 3; } int correct_ecc(uint8_t *buf, uint8_t *calc_ecc, uint8_t *read_ecc) { uint8_t ecc0, ecc1, ecc2, onesnum, bit, byte; uint16_t addr = 0; ecc0 = calc_ecc[0] ^ read_ecc[0]; ecc1 = calc_ecc[1] ^ read_ecc[1]; ecc2 = calc_ecc[2] ^ read_ecc[2]; if (!ecc0 && !ecc1 && !ecc2) return (ECC_OK); addr = BIT3(ecc0) | (BIT5(ecc0) << 1) | (BIT7(ecc0) << 2); addr |= (BIT1(ecc2) << 3) | (BIT3(ecc2) << 4) | (BIT5(ecc2) << 5) | (BIT7(ecc2) << 6); addr |= (BIT1(ecc1) << 7) | (BIT3(ecc1) << 8) | (BIT5(ecc1) << 9) | (BIT7(ecc1) << 10); onesnum = 0; while (ecc0 || ecc1 || ecc2) { if (ecc0 & 1) onesnum++; if (ecc1 & 1) onesnum++; if (ecc2 & 1) onesnum++; ecc0 >>= 1; ecc1 >>= 1; ecc2 >>= 1; } if (onesnum == 11) { /* correctable error */ bit = addr & 7; byte = addr >> 3; buf[byte] ^= (1 << bit); return (ECC_CORRECTABLE); } else if (onesnum == 1) { /* ecc error */ return (ECC_ERROR_ECC); } else { /* uncorrectable error */ return (ECC_UNCORRECTABLE); } return (0); }