mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2024-11-30 11:30:51 +00:00
214 lines
5.2 KiB
C++
214 lines
5.2 KiB
C++
/* dvdisaster: Additional error correction for optical media.
|
|
* Copyright (C) 2004-2007 Carsten Gnoerlich.
|
|
* Project home page: http://www.dvdisaster.com
|
|
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
|
|
* or direct your browser at http://www.gnu.org.
|
|
*/
|
|
|
|
#include <boolean.h>
|
|
#include "dvdisaster.h"
|
|
|
|
static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
|
|
static ReedSolomonTables *rt = NULL;
|
|
|
|
bool Init_LEC_Correct(void)
|
|
{
|
|
gt = CreateGaloisTables(0x11d);
|
|
rt = CreateReedSolomonTables(gt, 0, 1, 10);
|
|
|
|
return(1);
|
|
}
|
|
|
|
void Kill_LEC_Correct(void)
|
|
{
|
|
FreeGaloisTables(gt);
|
|
FreeReedSolomonTables(rt);
|
|
}
|
|
|
|
/***
|
|
*** CD level CRC calculation
|
|
***/
|
|
|
|
/*
|
|
* Test raw sector against its 32bit CRC.
|
|
* Returns true if frame is good.
|
|
*/
|
|
|
|
int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
|
|
{
|
|
unsigned int expected_crc, real_crc;
|
|
unsigned int crc_base = xa_mode ? 2072 : 2064;
|
|
|
|
expected_crc = cd_frame[crc_base + 0] << 0;
|
|
expected_crc |= cd_frame[crc_base + 1] << 8;
|
|
expected_crc |= cd_frame[crc_base + 2] << 16;
|
|
expected_crc |= cd_frame[crc_base + 3] << 24;
|
|
|
|
if(xa_mode)
|
|
real_crc = EDCCrc32(cd_frame+16, 2056);
|
|
else
|
|
real_crc = EDCCrc32(cd_frame, 2064);
|
|
|
|
if(expected_crc == real_crc)
|
|
return(1);
|
|
else
|
|
{
|
|
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/***
|
|
*** A very simple L-EC error correction.
|
|
***
|
|
* Perform just one pass over the Q and P vectors to see if everything
|
|
* is okay respectively correct minor errors. This is pretty much the
|
|
* same stuff the drive is supposed to do in the final L-EC stage.
|
|
*/
|
|
|
|
static int simple_lec(unsigned char *frame)
|
|
{
|
|
unsigned char byte_state[2352];
|
|
unsigned char p_vector[P_VECTOR_SIZE];
|
|
unsigned char q_vector[Q_VECTOR_SIZE];
|
|
unsigned char p_state[P_VECTOR_SIZE];
|
|
int erasures[Q_VECTOR_SIZE], erasure_count;
|
|
int ignore[2];
|
|
int p_failures, q_failures;
|
|
int p_corrected, q_corrected;
|
|
int p,q;
|
|
|
|
/* Setup */
|
|
|
|
memset(byte_state, 0, 2352);
|
|
|
|
p_failures = q_failures = 0;
|
|
p_corrected = q_corrected = 0;
|
|
|
|
/* Perform Q-Parity error correction */
|
|
|
|
for(q=0; q<N_Q_VECTORS; q++)
|
|
{ int err;
|
|
|
|
/* We have no erasure information for Q vectors */
|
|
|
|
GetQVector(frame, q_vector, q);
|
|
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
|
|
|
|
/* See what we've got */
|
|
|
|
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
|
|
{ q_failures++;
|
|
FillQVector(byte_state, 1, q);
|
|
}
|
|
else /* Correctable */
|
|
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
|
{ SetQVector(frame, q_vector, q);
|
|
q_corrected++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Perform P-Parity error correction */
|
|
|
|
for(p=0; p<N_P_VECTORS; p++)
|
|
{ int err,i;
|
|
|
|
/* Try error correction without erasure information */
|
|
|
|
GetPVector(frame, p_vector, p);
|
|
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
|
|
|
|
/* If unsuccessful, try again using erasures.
|
|
Erasure information is uncertain, so try this last. */
|
|
|
|
if(err < 0 || err > 2)
|
|
{ GetPVector(byte_state, p_state, p);
|
|
erasure_count = 0;
|
|
|
|
for(i=0; i<P_VECTOR_SIZE; i++)
|
|
if(p_state[i])
|
|
erasures[erasure_count++] = i;
|
|
|
|
if(erasure_count > 0 && erasure_count <= 2)
|
|
{ GetPVector(frame, p_vector, p);
|
|
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
|
|
}
|
|
}
|
|
|
|
/* See what we've got */
|
|
|
|
if(err < 0) /* Uncorrectable. */
|
|
{ p_failures++;
|
|
}
|
|
else /* Correctable. */
|
|
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
|
{ SetPVector(frame, p_vector, p);
|
|
p_corrected++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Sum up */
|
|
|
|
if(q_failures || p_failures || q_corrected || p_corrected)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***
|
|
*** Validate CD raw sector
|
|
***/
|
|
|
|
int ValidateRawSector(unsigned char *frame, bool xaMode)
|
|
{
|
|
int lec_did_sth = false;
|
|
|
|
/* Do simple L-EC.
|
|
It seems that drives stop their internal L-EC as soon as the
|
|
EDC is okay, so we may see uncorrected errors in the parity bytes.
|
|
Since we are also interested in the user data only and doing the
|
|
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
|
|
|
|
if(!CheckEDC(frame, xaMode))
|
|
{
|
|
unsigned char header[4];
|
|
|
|
if(xaMode)
|
|
{
|
|
memcpy(header, frame + 12, 4);
|
|
memset(frame + 12, 0, 4);
|
|
}
|
|
|
|
lec_did_sth = simple_lec(frame);
|
|
|
|
if(xaMode)
|
|
memcpy(frame + 12, header, 4);
|
|
}
|
|
|
|
/* Test internal sector checksum again */
|
|
if(!CheckEDC(frame, xaMode))
|
|
/* EDC failure in RAW sector */
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|