1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <asm/errno.h>
29#include <asm/io.h>
30#include <asm/uaccess.h>
31#include <linux/miscdevice.h>
32#include <linux/pci.h>
33#include <linux/delay.h>
34#include <linux/slab.h>
35#include <linux/sched.h>
36#include <linux/init.h>
37#include <linux/types.h>
38
39#include <linux/mtd/compatmac.h>
40#include <linux/mtd/mtd.h>
41#include <linux/mtd/doc2000.h>
42
43
44#undef B0
45
46#define MM 10
47#define KK (1023-4)
48#define B0 510
49#define PRIM 1
50#define NN ((1 << MM) - 1)
51
52typedef unsigned short dtype;
53
54
55static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
56
57
58
59
60
61
62
63
64typedef int gf;
65
66
67
68
69#define A0 (NN)
70
71
72
73
74static inline gf
75modnn(int x)
76{
77 while (x >= NN) {
78 x -= NN;
79 x = (x >> MM) + (x & NN);
80 }
81 return x;
82}
83
84#define CLEAR(a,n) {\
85int ci;\
86for(ci=(n)-1;ci >=0;ci--)\
87(a)[ci] = 0;\
88}
89
90#define COPY(a,b,n) {\
91int ci;\
92for(ci=(n)-1;ci >=0;ci--)\
93(a)[ci] = (b)[ci];\
94}
95
96#define COPYDOWN(a,b,n) {\
97int ci;\
98for(ci=(n)-1;ci >=0;ci--)\
99(a)[ci] = (b)[ci];\
100}
101
102#define Ldec 1
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135static void
136generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
137{
138 register int i, mask;
139
140 mask = 1;
141 Alpha_to[MM] = 0;
142 for (i = 0; i < MM; i++) {
143 Alpha_to[i] = mask;
144 Index_of[Alpha_to[i]] = i;
145
146 if (Pp[i] != 0)
147 Alpha_to[MM] ^= mask;
148 mask <<= 1;
149 }
150 Index_of[Alpha_to[MM]] = MM;
151
152
153
154
155
156 mask >>= 1;
157 for (i = MM + 1; i < NN; i++) {
158 if (Alpha_to[i - 1] >= mask)
159 Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
160 else
161 Alpha_to[i] = Alpha_to[i - 1] << 1;
162 Index_of[Alpha_to[i]] = i;
163 }
164 Index_of[0] = A0;
165 Alpha_to[NN] = 0;
166}
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189static int
190eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
191 gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK],
192 int no_eras)
193{
194 int deg_lambda, el, deg_omega;
195 int i, j, r,k;
196 gf u,q,tmp,num1,num2,den,discr_r;
197 gf lambda[NN-KK + 1], s[NN-KK + 1];
198
199 gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
200 gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
201 int syn_error, count;
202
203 syn_error = 0;
204 for(i=0;i<NN-KK;i++)
205 syn_error |= bb[i];
206
207 if (!syn_error) {
208
209
210
211 count = 0;
212 goto finish;
213 }
214
215 for(i=1;i<=NN-KK;i++){
216 s[i] = bb[0];
217 }
218 for(j=1;j<NN-KK;j++){
219 if(bb[j] == 0)
220 continue;
221 tmp = Index_of[bb[j]];
222
223 for(i=1;i<=NN-KK;i++)
224 s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
225 }
226
227
228
229
230 for(i=1;i<=NN-KK;i++) {
231 tmp = Index_of[s[i]];
232 if (tmp != A0)
233 tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
234 s[i] = tmp;
235 }
236
237 CLEAR(&lambda[1],NN-KK);
238 lambda[0] = 1;
239
240 if (no_eras > 0) {
241
242 lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
243 for (i = 1; i < no_eras; i++) {
244 u = modnn(PRIM*eras_pos[i]);
245 for (j = i+1; j > 0; j--) {
246 tmp = Index_of[lambda[j - 1]];
247 if(tmp != A0)
248 lambda[j] ^= Alpha_to[modnn(u + tmp)];
249 }
250 }
251#if DEBUG >= 1
252
253
254
255
256 for(i=1;i<=no_eras;i++)
257 reg[i] = Index_of[lambda[i]];
258 count = 0;
259 for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
260 q = 1;
261 for (j = 1; j <= no_eras; j++)
262 if (reg[j] != A0) {
263 reg[j] = modnn(reg[j] + j);
264 q ^= Alpha_to[reg[j]];
265 }
266 if (q != 0)
267 continue;
268
269 root[count] = i;
270 loc[count] = k;
271 count++;
272 }
273 if (count != no_eras) {
274 printf("\n lambda(x) is WRONG\n");
275 count = -1;
276 goto finish;
277 }
278#if DEBUG >= 2
279 printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
280 for (i = 0; i < count; i++)
281 printf("%d ", loc[i]);
282 printf("\n");
283#endif
284#endif
285 }
286 for(i=0;i<NN-KK+1;i++)
287 b[i] = Index_of[lambda[i]];
288
289
290
291
292
293 r = no_eras;
294 el = no_eras;
295 while (++r <= NN-KK) {
296
297 discr_r = 0;
298 for (i = 0; i < r; i++){
299 if ((lambda[i] != 0) && (s[r - i] != A0)) {
300 discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
301 }
302 }
303 discr_r = Index_of[discr_r];
304 if (discr_r == A0) {
305
306 COPYDOWN(&b[1],b,NN-KK);
307 b[0] = A0;
308 } else {
309
310 t[0] = lambda[0];
311 for (i = 0 ; i < NN-KK; i++) {
312 if(b[i] != A0)
313 t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
314 else
315 t[i+1] = lambda[i+1];
316 }
317 if (2 * el <= r + no_eras - 1) {
318 el = r + no_eras - el;
319
320
321
322
323 for (i = 0; i <= NN-KK; i++)
324 b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
325 } else {
326
327 COPYDOWN(&b[1],b,NN-KK);
328 b[0] = A0;
329 }
330 COPY(lambda,t,NN-KK+1);
331 }
332 }
333
334
335 deg_lambda = 0;
336 for(i=0;i<NN-KK+1;i++){
337 lambda[i] = Index_of[lambda[i]];
338 if(lambda[i] != A0)
339 deg_lambda = i;
340 }
341
342
343
344
345 COPY(®[1],&lambda[1],NN-KK);
346 count = 0;
347 for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
348 q = 1;
349 for (j = deg_lambda; j > 0; j--){
350 if (reg[j] != A0) {
351 reg[j] = modnn(reg[j] + j);
352 q ^= Alpha_to[reg[j]];
353 }
354 }
355 if (q != 0)
356 continue;
357
358 root[count] = i;
359 loc[count] = k;
360
361
362
363 if(++count == deg_lambda)
364 break;
365 }
366 if (deg_lambda != count) {
367
368
369
370
371 count = -1;
372 goto finish;
373 }
374
375
376
377
378 deg_omega = 0;
379 for (i = 0; i < NN-KK;i++){
380 tmp = 0;
381 j = (deg_lambda < i) ? deg_lambda : i;
382 for(;j >= 0; j--){
383 if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
384 tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
385 }
386 if(tmp != 0)
387 deg_omega = i;
388 omega[i] = Index_of[tmp];
389 }
390 omega[NN-KK] = A0;
391
392
393
394
395
396 for (j = count-1; j >=0; j--) {
397 num1 = 0;
398 for (i = deg_omega; i >= 0; i--) {
399 if (omega[i] != A0)
400 num1 ^= Alpha_to[modnn(omega[i] + i * root[j])];
401 }
402 num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
403 den = 0;
404
405
406 for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
407 if(lambda[i+1] != A0)
408 den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
409 }
410 if (den == 0) {
411#if DEBUG >= 1
412 printf("\n ERROR: denominator = 0\n");
413#endif
414
415 count = -1;
416 goto finish;
417 }
418
419 if (num1 != 0) {
420 eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
421 } else {
422 eras_val[j] = 0;
423 }
424 }
425 finish:
426 for(i=0;i<count;i++)
427 eras_pos[i] = loc[i];
428 return count;
429}
430
431
432
433
434#define SECTOR_SIZE 512
435
436#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
437
438
439
440
441
442
443
444int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
445{
446 int parity, i, nb_errors;
447 gf bb[NN - KK + 1];
448 gf error_val[NN-KK];
449 int error_pos[NN-KK], pos, bitpos, index, val;
450 dtype *Alpha_to, *Index_of;
451
452
453 Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
454 if (!Alpha_to)
455 return -1;
456
457 Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
458 if (!Index_of) {
459 kfree(Alpha_to);
460 return -1;
461 }
462
463 generate_gf(Alpha_to, Index_of);
464
465 parity = ecc1[1];
466
467 bb[0] = (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
468 bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
469 bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
470 bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
471
472 nb_errors = eras_dec_rs(Alpha_to, Index_of, bb,
473 error_val, error_pos, 0);
474 if (nb_errors <= 0)
475 goto the_end;
476
477
478 for(i=0;i<nb_errors;i++) {
479 pos = error_pos[i];
480 if (pos >= NB_DATA && pos < KK) {
481 nb_errors = -1;
482 goto the_end;
483 }
484 if (pos < NB_DATA) {
485
486 pos = 10 * (NB_DATA - 1 - pos) - 6;
487
488
489 index = (pos >> 3) ^ 1;
490 bitpos = pos & 7;
491 if ((index >= 0 && index < SECTOR_SIZE) ||
492 index == (SECTOR_SIZE + 1)) {
493 val = error_val[i] >> (2 + bitpos);
494 parity ^= val;
495 if (index < SECTOR_SIZE)
496 sector[index] ^= val;
497 }
498 index = ((pos >> 3) + 1) ^ 1;
499 bitpos = (bitpos + 10) & 7;
500 if (bitpos == 0)
501 bitpos = 8;
502 if ((index >= 0 && index < SECTOR_SIZE) ||
503 index == (SECTOR_SIZE + 1)) {
504 val = error_val[i] << (8 - bitpos);
505 parity ^= val;
506 if (index < SECTOR_SIZE)
507 sector[index] ^= val;
508 }
509 }
510 }
511
512
513 if ((parity & 0xff) != 0)
514 nb_errors = -1;
515
516 the_end:
517 kfree(Alpha_to);
518 kfree(Index_of);
519 return nb_errors;
520}
521
522EXPORT_SYMBOL_GPL(doc_decode_ecc);
523
524MODULE_LICENSE("GPL");
525MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>");
526MODULE_DESCRIPTION("ECC code for correcting errors detected by DiskOnChip 2000 and Millennium ECC hardware");
527