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 <boolean.h>
23 #include "dvdisaster.h"
24
25 static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
26 static ReedSolomonTables *rt = NULL;
27
Init_LEC_Correct(void)28 bool Init_LEC_Correct(void)
29 {
30 gt = CreateGaloisTables(0x11d);
31 rt = CreateReedSolomonTables(gt, 0, 1, 10);
32
33 return(1);
34 }
35
Kill_LEC_Correct(void)36 void Kill_LEC_Correct(void)
37 {
38 FreeGaloisTables(gt);
39 FreeReedSolomonTables(rt);
40 }
41
42 /***
43 *** CD level CRC calculation
44 ***/
45
46 /*
47 * Test raw sector against its 32bit CRC.
48 * Returns true if frame is good.
49 */
50
CheckEDC(const unsigned char * cd_frame,bool xa_mode)51 int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
52 {
53 unsigned int expected_crc, real_crc;
54 unsigned int crc_base = xa_mode ? 2072 : 2064;
55
56 expected_crc = cd_frame[crc_base + 0] << 0;
57 expected_crc |= cd_frame[crc_base + 1] << 8;
58 expected_crc |= cd_frame[crc_base + 2] << 16;
59 expected_crc |= cd_frame[crc_base + 3] << 24;
60
61 if(xa_mode)
62 real_crc = EDCCrc32(cd_frame+16, 2056);
63 else
64 real_crc = EDCCrc32(cd_frame, 2064);
65
66 if(expected_crc == real_crc)
67 return(1);
68 else
69 {
70 //printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
71 return(0);
72 }
73 }
74
75 /***
76 *** A very simple L-EC error correction.
77 ***
78 * Perform just one pass over the Q and P vectors to see if everything
79 * is okay respectively correct minor errors. This is pretty much the
80 * same stuff the drive is supposed to do in the final L-EC stage.
81 */
82
simple_lec(unsigned char * frame)83 static int simple_lec(unsigned char *frame)
84 {
85 unsigned char byte_state[2352];
86 unsigned char p_vector[P_VECTOR_SIZE];
87 unsigned char q_vector[Q_VECTOR_SIZE];
88 unsigned char p_state[P_VECTOR_SIZE];
89 int erasures[Q_VECTOR_SIZE], erasure_count;
90 int ignore[2];
91 int p_failures, q_failures;
92 int p_corrected, q_corrected;
93 int p,q;
94
95 /* Setup */
96
97 memset(byte_state, 0, 2352);
98
99 p_failures = q_failures = 0;
100 p_corrected = q_corrected = 0;
101
102 /* Perform Q-Parity error correction */
103
104 for(q=0; q<N_Q_VECTORS; q++)
105 { int err;
106
107 /* We have no erasure information for Q vectors */
108
109 GetQVector(frame, q_vector, q);
110 err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
111
112 /* See what we've got */
113
114 if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
115 { q_failures++;
116 FillQVector(byte_state, 1, q);
117 }
118 else /* Correctable */
119 { if(err == 1 || err == 2) /* Store back corrected vector */
120 { SetQVector(frame, q_vector, q);
121 q_corrected++;
122 }
123 }
124 }
125
126 /* Perform P-Parity error correction */
127
128 for(p=0; p<N_P_VECTORS; p++)
129 { int err,i;
130
131 /* Try error correction without erasure information */
132
133 GetPVector(frame, p_vector, p);
134 err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
135
136 /* If unsuccessful, try again using erasures.
137 Erasure information is uncertain, so try this last. */
138
139 if(err < 0 || err > 2)
140 { GetPVector(byte_state, p_state, p);
141 erasure_count = 0;
142
143 for(i=0; i<P_VECTOR_SIZE; i++)
144 if(p_state[i])
145 erasures[erasure_count++] = i;
146
147 if(erasure_count > 0 && erasure_count <= 2)
148 { GetPVector(frame, p_vector, p);
149 err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
150 }
151 }
152
153 /* See what we've got */
154
155 if(err < 0) /* Uncorrectable. */
156 { p_failures++;
157 }
158 else /* Correctable. */
159 { if(err == 1 || err == 2) /* Store back corrected vector */
160 { SetPVector(frame, p_vector, p);
161 p_corrected++;
162 }
163 }
164 }
165
166 /* Sum up */
167
168 if(q_failures || p_failures || q_corrected || p_corrected)
169 {
170 return 1;
171 }
172
173 return 0;
174 }
175
176 /***
177 *** Validate CD raw sector
178 ***/
179
ValidateRawSector(unsigned char * frame,bool xaMode)180 int ValidateRawSector(unsigned char *frame, bool xaMode)
181 {
182 int lec_did_sth = false;
183
184 /* Do simple L-EC.
185 It seems that drives stop their internal L-EC as soon as the
186 EDC is okay, so we may see uncorrected errors in the parity bytes.
187 Since we are also interested in the user data only and doing the
188 L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
189
190 if(!CheckEDC(frame, xaMode))
191 {
192 unsigned char header[4];
193
194 if(xaMode)
195 {
196 memcpy(header, frame + 12, 4);
197 memset(frame + 12, 0, 4);
198 }
199
200 lec_did_sth = simple_lec(frame);
201
202 if(xaMode)
203 memcpy(frame + 12, header, 4);
204 }
205
206 /* Test internal sector checksum again */
207 if(!CheckEDC(frame, xaMode))
208 /* EDC failure in RAW sector */
209 return false;
210
211 return true;
212 }
213
214