1 /*  dvdisaster: Additional error correction for optical media.
2  *  Copyright (C) 2004-2007 Carsten Gnoerlich.
3  *  Project home page: http://www.dvdisaster.com
4  *  Email: carsten@dvdisaster.com  -or-  cgnoerlich@fsfe.org
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,
19  *  or direct your browser at http://www.gnu.org.
20  */
21 
22 #include <stdint.h>
23 #include <string.h>
24 #include "recover-raw.h"
25 #include "l-ec.h"
26 #include "edc_crc32.h"
27 #include "galois.h"
28 
29 static GaloisTables *gt = NULL;		/* for L-EC Reed-Solomon */
30 static ReedSolomonTables *rt = NULL;
31 
Init_LEC_Correct(void)32 bool Init_LEC_Correct(void)
33 {
34    gt = CreateGaloisTables(0x11d);
35    rt = CreateReedSolomonTables(gt, 0, 1, 10);
36 
37    return(1);
38 }
39 
Kill_LEC_Correct(void)40 void Kill_LEC_Correct(void)
41 {
42    FreeGaloisTables(gt);
43    FreeReedSolomonTables(rt);
44 }
45 
46 /***
47  *** CD level CRC calculation
48  ***/
49 
50 /*
51  * Test raw sector against its 32bit CRC.
52  * Returns TRUE if frame is good.
53  */
54 
CheckEDC(const unsigned char * cd_frame,bool xa_mode)55 int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
56 {
57    unsigned int expected_crc, real_crc;
58    unsigned int crc_base = xa_mode ? 2072 : 2064;
59 
60    expected_crc = cd_frame[crc_base + 0] << 0;
61    expected_crc |= cd_frame[crc_base + 1] << 8;
62    expected_crc |= cd_frame[crc_base + 2] << 16;
63    expected_crc |= cd_frame[crc_base + 3] << 24;
64 
65    if(xa_mode)
66       real_crc = EDCCrc32(cd_frame+16, 2056);
67    else
68       real_crc = EDCCrc32(cd_frame, 2064);
69 
70    if(expected_crc == real_crc)
71       return(1);
72 
73    //printf("Bad EDC CRC:  Calculated:  %08x,  Recorded:  %08x\n", real_crc, expected_crc);
74    return(0);
75 }
76 
77 /***
78  *** A very simple L-EC error correction.
79  ***
80  * Perform just one pass over the Q and P vectors to see if everything
81  * is okay respectively correct minor errors. This is pretty much the
82  * same stuff the drive is supposed to do in the final L-EC stage.
83  */
84 
simple_lec(unsigned char * frame)85 static int simple_lec(unsigned char *frame)
86 {
87    unsigned char byte_state[2352];
88    unsigned char p_vector[P_VECTOR_SIZE];
89    unsigned char q_vector[Q_VECTOR_SIZE];
90    unsigned char p_state[P_VECTOR_SIZE];
91    int erasures[Q_VECTOR_SIZE], erasure_count;
92    int ignore[2];
93    int p_failures, q_failures;
94    int p_corrected, q_corrected;
95    int p,q;
96 
97    /* Setup */
98 
99    memset(byte_state, 0, 2352);
100 
101    p_failures = q_failures = 0;
102    p_corrected = q_corrected = 0;
103 
104    /* Perform Q-Parity error correction */
105 
106    for(q=0; q<N_Q_VECTORS; q++)
107    {
108       int err;
109 
110       /* We have no erasure information for Q vectors */
111 
112       GetQVector(frame, q_vector, q);
113       err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
114 
115       /* See what we've got */
116 
117       if(err < 0)  /* Uncorrectable. Mark bytes are erasure. */
118       {  q_failures++;
119          FillQVector(byte_state, 1, q);
120       }
121       else         /* Correctable */
122       {
123          if(err == 1 || err == 2) /* Store back corrected vector */
124          {
125             SetQVector(frame, q_vector, q);
126             q_corrected++;
127          }
128       }
129    }
130 
131    /* Perform P-Parity error correction */
132    for(p=0; p<N_P_VECTORS; p++)
133    {
134       int err,i;
135 
136       /* Try error correction without erasure information */
137 
138       GetPVector(frame, p_vector, p);
139       err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
140 
141       /* If unsuccessful, try again using erasures.
142          Erasure information is uncertain, so try this last. */
143 
144       if(err < 0 || err > 2)
145       {
146          GetPVector(byte_state, p_state, p);
147          erasure_count = 0;
148 
149          for(i=0; i<P_VECTOR_SIZE; i++)
150             if(p_state[i])
151                erasures[erasure_count++] = i;
152 
153          if(erasure_count > 0 && erasure_count <= 2)
154          {
155             GetPVector(frame, p_vector, p);
156             err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
157          }
158       }
159 
160       /* See what we've got */
161 
162       if(err < 0)  /* Uncorrectable. */
163          p_failures++;
164       else         /* Correctable. */
165       {
166          if(err == 1 || err == 2) /* Store back corrected vector */
167          {  SetPVector(frame, p_vector, p);
168             p_corrected++;
169          }
170       }
171    }
172 
173    /* Sum up */
174 
175    if(q_failures || p_failures || q_corrected || p_corrected)
176       return 1;
177 
178    return 0;
179 }
180 
181 /***
182  *** Validate CD raw sector
183  ***/
184 
ValidateRawSector(unsigned char * frame,bool xaMode)185 int ValidateRawSector(unsigned char *frame, bool xaMode)
186 {
187    int lec_did_sth = false;
188 
189    // Silence GCC warning
190    (void)lec_did_sth;
191 
192    /* Do simple L-EC.
193       It seems that drives stop their internal L-EC as soon as the
194       EDC is okay, so we may see uncorrected errors in the parity bytes.
195       Since we are also interested in the user data only and doing the
196       L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
197 
198    if(!CheckEDC(frame, xaMode))
199       lec_did_sth = simple_lec(frame);
200    /* Test internal sector checksum again */
201 
202    /* EDC failure in RAW sector */
203    if(!CheckEDC(frame, xaMode))
204       return false;
205 
206    return true;
207 }
208