linux/lib/reed_solomon/decode_rs.c
<<
>>
Prefs
   1/*
   2 * lib/reed_solomon/decode_rs.c
   3 *
   4 * Overview:
   5 *   Generic Reed Solomon encoder / decoder library
   6 *
   7 * Copyright 2002, Phil Karn, KA9Q
   8 * May be used under the terms of the GNU General Public License (GPL)
   9 *
  10 * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
  11 *
  12 * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $
  13 *
  14 */
  15
  16/* Generic data width independent code which is included by the
  17 * wrappers.
  18 */
  19{
  20        int deg_lambda, el, deg_omega;
  21        int i, j, r, k, pad;
  22        int nn = rs->nn;
  23        int nroots = rs->nroots;
  24        int fcr = rs->fcr;
  25        int prim = rs->prim;
  26        int iprim = rs->iprim;
  27        uint16_t *alpha_to = rs->alpha_to;
  28        uint16_t *index_of = rs->index_of;
  29        uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
  30        /* Err+Eras Locator poly and syndrome poly The maximum value
  31         * of nroots is 8. So the necessary stack size will be about
  32         * 220 bytes max.
  33         */
  34        uint16_t lambda[nroots + 1], syn[nroots];
  35        uint16_t b[nroots + 1], t[nroots + 1], omega[nroots + 1];
  36        uint16_t root[nroots], reg[nroots + 1], loc[nroots];
  37        int count = 0;
  38        uint16_t msk = (uint16_t) rs->nn;
  39
  40        /* Check length parameter for validity */
  41        pad = nn - nroots - len;
  42        BUG_ON(pad < 0 || pad >= nn);
  43
  44        /* Does the caller provide the syndrome ? */
  45        if (s != NULL)
  46                goto decode;
  47
  48        /* form the syndromes; i.e., evaluate data(x) at roots of
  49         * g(x) */
  50        for (i = 0; i < nroots; i++)
  51                syn[i] = (((uint16_t) data[0]) ^ invmsk) & msk;
  52
  53        for (j = 1; j < len; j++) {
  54                for (i = 0; i < nroots; i++) {
  55                        if (syn[i] == 0) {
  56                                syn[i] = (((uint16_t) data[j]) ^
  57                                          invmsk) & msk;
  58                        } else {
  59                                syn[i] = ((((uint16_t) data[j]) ^
  60                                           invmsk) & msk) ^
  61                                        alpha_to[rs_modnn(rs, index_of[syn[i]] +
  62                                                       (fcr + i) * prim)];
  63                        }
  64                }
  65        }
  66
  67        for (j = 0; j < nroots; j++) {
  68                for (i = 0; i < nroots; i++) {
  69                        if (syn[i] == 0) {
  70                                syn[i] = ((uint16_t) par[j]) & msk;
  71                        } else {
  72                                syn[i] = (((uint16_t) par[j]) & msk) ^
  73                                        alpha_to[rs_modnn(rs, index_of[syn[i]] +
  74                                                       (fcr+i)*prim)];
  75                        }
  76                }
  77        }
  78        s = syn;
  79
  80        /* Convert syndromes to index form, checking for nonzero condition */
  81        syn_error = 0;
  82        for (i = 0; i < nroots; i++) {
  83                syn_error |= s[i];
  84                s[i] = index_of[s[i]];
  85        }
  86
  87        if (!syn_error) {
  88                /* if syndrome is zero, data[] is a codeword and there are no
  89                 * errors to correct. So return data[] unmodified
  90                 */
  91                count = 0;
  92                goto finish;
  93        }
  94
  95 decode:
  96        memset(&lambda[1], 0, nroots * sizeof(lambda[0]));
  97        lambda[0] = 1;
  98
  99        if (no_eras > 0) {
 100                /* Init lambda to be the erasure locator polynomial */
 101                lambda[1] = alpha_to[rs_modnn(rs,
 102                                              prim * (nn - 1 - eras_pos[0]))];
 103                for (i = 1; i < no_eras; i++) {
 104                        u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
 105                        for (j = i + 1; j > 0; j--) {
 106                                tmp = index_of[lambda[j - 1]];
 107                                if (tmp != nn) {
 108                                        lambda[j] ^=
 109                                                alpha_to[rs_modnn(rs, u + tmp)];
 110                                }
 111                        }
 112                }
 113        }
 114
 115        for (i = 0; i < nroots + 1; i++)
 116                b[i] = index_of[lambda[i]];
 117
 118        /*
 119         * Begin Berlekamp-Massey algorithm to determine error+erasure
 120         * locator polynomial
 121         */
 122        r = no_eras;
 123        el = no_eras;
 124        while (++r <= nroots) { /* r is the step number */
 125                /* Compute discrepancy at the r-th step in poly-form */
 126                discr_r = 0;
 127                for (i = 0; i < r; i++) {
 128                        if ((lambda[i] != 0) && (s[r - i - 1] != nn)) {
 129                                discr_r ^=
 130                                        alpha_to[rs_modnn(rs,
 131                                                          index_of[lambda[i]] +
 132                                                          s[r - i - 1])];
 133                        }
 134                }
 135                discr_r = index_of[discr_r];    /* Index form */
 136                if (discr_r == nn) {
 137                        /* 2 lines below: B(x) <-- x*B(x) */
 138                        memmove (&b[1], b, nroots * sizeof (b[0]));
 139                        b[0] = nn;
 140                } else {
 141                        /* 7 lines below: T(x) <-- lambda(x)-discr_r*x*b(x) */
 142                        t[0] = lambda[0];
 143                        for (i = 0; i < nroots; i++) {
 144                                if (b[i] != nn) {
 145                                        t[i + 1] = lambda[i + 1] ^
 146                                                alpha_to[rs_modnn(rs, discr_r +
 147                                                                  b[i])];
 148                                } else
 149                                        t[i + 1] = lambda[i + 1];
 150                        }
 151                        if (2 * el <= r + no_eras - 1) {
 152                                el = r + no_eras - el;
 153                                /*
 154                                 * 2 lines below: B(x) <-- inv(discr_r) *
 155                                 * lambda(x)
 156                                 */
 157                                for (i = 0; i <= nroots; i++) {
 158                                        b[i] = (lambda[i] == 0) ? nn :
 159                                                rs_modnn(rs, index_of[lambda[i]]
 160                                                         - discr_r + nn);
 161                                }
 162                        } else {
 163                                /* 2 lines below: B(x) <-- x*B(x) */
 164                                memmove(&b[1], b, nroots * sizeof(b[0]));
 165                                b[0] = nn;
 166                        }
 167                        memcpy(lambda, t, (nroots + 1) * sizeof(t[0]));
 168                }
 169        }
 170
 171        /* Convert lambda to index form and compute deg(lambda(x)) */
 172        deg_lambda = 0;
 173        for (i = 0; i < nroots + 1; i++) {
 174                lambda[i] = index_of[lambda[i]];
 175                if (lambda[i] != nn)
 176                        deg_lambda = i;
 177        }
 178        /* Find roots of error+erasure locator polynomial by Chien search */
 179        memcpy(&reg[1], &lambda[1], nroots * sizeof(reg[0]));
 180        count = 0;              /* Number of roots of lambda(x) */
 181        for (i = 1, k = iprim - 1; i <= nn; i++, k = rs_modnn(rs, k + iprim)) {
 182                q = 1;          /* lambda[0] is always 0 */
 183                for (j = deg_lambda; j > 0; j--) {
 184                        if (reg[j] != nn) {
 185                                reg[j] = rs_modnn(rs, reg[j] + j);
 186                                q ^= alpha_to[reg[j]];
 187                        }
 188                }
 189                if (q != 0)
 190                        continue;       /* Not a root */
 191                /* store root (index-form) and error location number */
 192                root[count] = i;
 193                loc[count] = k;
 194                /* If we've already found max possible roots,
 195                 * abort the search to save time
 196                 */
 197                if (++count == deg_lambda)
 198                        break;
 199        }
 200        if (deg_lambda != count) {
 201                /*
 202                 * deg(lambda) unequal to number of roots => uncorrectable
 203                 * error detected
 204                 */
 205                count = -EBADMSG;
 206                goto finish;
 207        }
 208        /*
 209         * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
 210         * x**nroots). in index form. Also find deg(omega).
 211         */
 212        deg_omega = deg_lambda - 1;
 213        for (i = 0; i <= deg_omega; i++) {
 214                tmp = 0;
 215                for (j = i; j >= 0; j--) {
 216                        if ((s[i - j] != nn) && (lambda[j] != nn))
 217                                tmp ^=
 218                                    alpha_to[rs_modnn(rs, s[i - j] + lambda[j])];
 219                }
 220                omega[i] = index_of[tmp];
 221        }
 222
 223        /*
 224         * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
 225         * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
 226         */
 227        for (j = count - 1; j >= 0; j--) {
 228                num1 = 0;
 229                for (i = deg_omega; i >= 0; i--) {
 230                        if (omega[i] != nn)
 231                                num1 ^= alpha_to[rs_modnn(rs, omega[i] +
 232                                                        i * root[j])];
 233                }
 234                num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
 235                den = 0;
 236
 237                /* lambda[i+1] for i even is the formal derivative
 238                 * lambda_pr of lambda[i] */
 239                for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) {
 240                        if (lambda[i + 1] != nn) {
 241                                den ^= alpha_to[rs_modnn(rs, lambda[i + 1] +
 242                                                       i * root[j])];
 243                        }
 244                }
 245                /* Apply error to data */
 246                if (num1 != 0 && loc[j] >= pad) {
 247                        uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
 248                                                       index_of[num2] +
 249                                                       nn - index_of[den])];
 250                        /* Store the error correction pattern, if a
 251                         * correction buffer is available */
 252                        if (corr) {
 253                                corr[j] = cor;
 254                        } else {
 255                                /* If a data buffer is given and the
 256                                 * error is inside the message,
 257                                 * correct it */
 258                                if (data && (loc[j] < (nn - nroots)))
 259                                        data[loc[j] - pad] ^= cor;
 260                        }
 261                }
 262        }
 263
 264finish:
 265        if (eras_pos != NULL) {
 266                for (i = 0; i < count; i++)
 267                        eras_pos[i] = loc[i] - pad;
 268        }
 269        return count;
 270
 271}
 272