2 * lib/reed_solomon/decode_rs.c
5 * Generic Reed Solomon encoder / decoder library
7 * Copyright 2002, Phil Karn, KA9Q
8 * May be used under the terms of the GNU General Public License (GPL)
10 * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
12 * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $
16 /* Generic data width independent code which is included by the
20 int deg_lambda
, el
, deg_omega
;
23 int nroots
= rs
->nroots
;
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
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
];
38 uint16_t msk
= (uint16_t) rs
->nn
;
40 /* Check length parameter for validity */
41 pad
= nn
- nroots
- len
;
42 BUG_ON(pad
< 0 || pad
>= nn
);
44 /* Does the caller provide the syndrome ? */
46 for (i
= 0; i
< nroots
; i
++) {
47 /* The syndrome is in index form,
48 * so nn represents zero
54 /* syndrome is zero, no errors to correct */
58 /* form the syndromes; i.e., evaluate data(x) at roots of
60 for (i
= 0; i
< nroots
; i
++)
61 syn
[i
] = (((uint16_t) data
[0]) ^ invmsk
) & msk
;
63 for (j
= 1; j
< len
; j
++) {
64 for (i
= 0; i
< nroots
; i
++) {
66 syn
[i
] = (((uint16_t) data
[j
]) ^
69 syn
[i
] = ((((uint16_t) data
[j
]) ^
71 alpha_to
[rs_modnn(rs
, index_of
[syn
[i
]] +
77 for (j
= 0; j
< nroots
; j
++) {
78 for (i
= 0; i
< nroots
; i
++) {
80 syn
[i
] = ((uint16_t) par
[j
]) & msk
;
82 syn
[i
] = (((uint16_t) par
[j
]) & msk
) ^
83 alpha_to
[rs_modnn(rs
, index_of
[syn
[i
]] +
90 /* Convert syndromes to index form, checking for nonzero condition */
92 for (i
= 0; i
< nroots
; i
++) {
94 s
[i
] = index_of
[s
[i
]];
98 /* if syndrome is zero, data[] is a codeword and there are no
99 * errors to correct. So return data[] unmodified
106 memset(&lambda
[1], 0, nroots
* sizeof(lambda
[0]));
110 /* Init lambda to be the erasure locator polynomial */
111 lambda
[1] = alpha_to
[rs_modnn(rs
,
112 prim
* (nn
- 1 - (eras_pos
[0] + pad
)))];
113 for (i
= 1; i
< no_eras
; i
++) {
114 u
= rs_modnn(rs
, prim
* (nn
- 1 - (eras_pos
[i
] + pad
)));
115 for (j
= i
+ 1; j
> 0; j
--) {
116 tmp
= index_of
[lambda
[j
- 1]];
119 alpha_to
[rs_modnn(rs
, u
+ tmp
)];
125 for (i
= 0; i
< nroots
+ 1; i
++)
126 b
[i
] = index_of
[lambda
[i
]];
129 * Begin Berlekamp-Massey algorithm to determine error+erasure
134 while (++r
<= nroots
) { /* r is the step number */
135 /* Compute discrepancy at the r-th step in poly-form */
137 for (i
= 0; i
< r
; i
++) {
138 if ((lambda
[i
] != 0) && (s
[r
- i
- 1] != nn
)) {
140 alpha_to
[rs_modnn(rs
,
141 index_of
[lambda
[i
]] +
145 discr_r
= index_of
[discr_r
]; /* Index form */
147 /* 2 lines below: B(x) <-- x*B(x) */
148 memmove (&b
[1], b
, nroots
* sizeof (b
[0]));
151 /* 7 lines below: T(x) <-- lambda(x)-discr_r*x*b(x) */
153 for (i
= 0; i
< nroots
; i
++) {
155 t
[i
+ 1] = lambda
[i
+ 1] ^
156 alpha_to
[rs_modnn(rs
, discr_r
+
159 t
[i
+ 1] = lambda
[i
+ 1];
161 if (2 * el
<= r
+ no_eras
- 1) {
162 el
= r
+ no_eras
- el
;
164 * 2 lines below: B(x) <-- inv(discr_r) *
167 for (i
= 0; i
<= nroots
; i
++) {
168 b
[i
] = (lambda
[i
] == 0) ? nn
:
169 rs_modnn(rs
, index_of
[lambda
[i
]]
173 /* 2 lines below: B(x) <-- x*B(x) */
174 memmove(&b
[1], b
, nroots
* sizeof(b
[0]));
177 memcpy(lambda
, t
, (nroots
+ 1) * sizeof(t
[0]));
181 /* Convert lambda to index form and compute deg(lambda(x)) */
183 for (i
= 0; i
< nroots
+ 1; i
++) {
184 lambda
[i
] = index_of
[lambda
[i
]];
188 /* Find roots of error+erasure locator polynomial by Chien search */
189 memcpy(®
[1], &lambda
[1], nroots
* sizeof(reg
[0]));
190 count
= 0; /* Number of roots of lambda(x) */
191 for (i
= 1, k
= iprim
- 1; i
<= nn
; i
++, k
= rs_modnn(rs
, k
+ iprim
)) {
192 q
= 1; /* lambda[0] is always 0 */
193 for (j
= deg_lambda
; j
> 0; j
--) {
195 reg
[j
] = rs_modnn(rs
, reg
[j
] + j
);
196 q
^= alpha_to
[reg
[j
]];
200 continue; /* Not a root */
201 /* store root (index-form) and error location number */
204 /* If we've already found max possible roots,
205 * abort the search to save time
207 if (++count
== deg_lambda
)
210 if (deg_lambda
!= count
) {
212 * deg(lambda) unequal to number of roots => uncorrectable
219 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
220 * x**nroots). in index form. Also find deg(omega).
222 deg_omega
= deg_lambda
- 1;
223 for (i
= 0; i
<= deg_omega
; i
++) {
225 for (j
= i
; j
>= 0; j
--) {
226 if ((s
[i
- j
] != nn
) && (lambda
[j
] != nn
))
228 alpha_to
[rs_modnn(rs
, s
[i
- j
] + lambda
[j
])];
230 omega
[i
] = index_of
[tmp
];
234 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
235 * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
237 for (j
= count
- 1; j
>= 0; j
--) {
239 for (i
= deg_omega
; i
>= 0; i
--) {
241 num1
^= alpha_to
[rs_modnn(rs
, omega
[i
] +
244 num2
= alpha_to
[rs_modnn(rs
, root
[j
] * (fcr
- 1) + nn
)];
247 /* lambda[i+1] for i even is the formal derivative
248 * lambda_pr of lambda[i] */
249 for (i
= min(deg_lambda
, nroots
- 1) & ~1; i
>= 0; i
-= 2) {
250 if (lambda
[i
+ 1] != nn
) {
251 den
^= alpha_to
[rs_modnn(rs
, lambda
[i
+ 1] +
255 /* Apply error to data */
256 if (num1
!= 0 && loc
[j
] >= pad
) {
257 uint16_t cor
= alpha_to
[rs_modnn(rs
,index_of
[num1
] +
259 nn
- index_of
[den
])];
260 /* Store the error correction pattern, if a
261 * correction buffer is available */
265 /* If a data buffer is given and the
266 * error is inside the message,
268 if (data
&& (loc
[j
] < (nn
- nroots
)))
269 data
[loc
[j
] - pad
] ^= cor
;
275 if (eras_pos
!= NULL
) {
276 for (i
= 0; i
< count
; i
++)
277 eras_pos
[i
] = loc
[i
] - pad
;