365 lines
11 KiB
C
365 lines
11 KiB
C
|
/* @(#)edc.h 1.3 12/12/02 Copyright 1998-2001 Heiko Eissfeldt */
|
||
|
|
||
|
/*
|
||
|
* This file contains protected intellectual property.
|
||
|
*
|
||
|
* Compact disc reed-solomon routines.
|
||
|
* Copyright (c) 1998-2001 by Heiko Eissfeldt, heiko@hexco.de
|
||
|
* Copyright (c) 2006-2012 by Joerg Schilling
|
||
|
*/
|
||
|
/*
|
||
|
* The contents of this file are subject to the terms of the
|
||
|
* Common Development and Distribution License, Version 1.0 only
|
||
|
* (the "License"). You may not use this file except in compliance
|
||
|
* with the License.
|
||
|
*
|
||
|
* See the file CDDL.Schily.txt in this distribution for details.
|
||
|
*
|
||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||
|
* file and include the License file CDDL.Schily.txt from this distribution.
|
||
|
*/
|
||
|
|
||
|
#ifdef EDC_DECODER_HACK
|
||
|
|
||
|
#ifndef min
|
||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||
|
#endif
|
||
|
|
||
|
#define DO2(a) a\
|
||
|
a
|
||
|
|
||
|
#define DO4(a) DO2(a)\
|
||
|
DO2(a)
|
||
|
|
||
|
#define DO8(a) DO4(a)\
|
||
|
DO4(a)
|
||
|
|
||
|
#if defined EDC_LAYER1 || defined EDC_LAYER2
|
||
|
#define RS_L12_BITS 8
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* known sector types
|
||
|
*/
|
||
|
#define EDC_MODE_0 0
|
||
|
#define EDC_MODE_1 1
|
||
|
#define EDC_MODE_2 2
|
||
|
#define EDC_MODE_2_FORM_1 3
|
||
|
#define EDC_MODE_2_FORM_2 4
|
||
|
#define EDC_AUDIO 5
|
||
|
#define EDC_UNKNOWN 6
|
||
|
|
||
|
|
||
|
typedef struct bcdmsf {
|
||
|
unsigned char bcdmsf_min; /* the minute in bcd format */
|
||
|
unsigned char bcdmsf_sec; /* the second in bcd format */
|
||
|
unsigned char bcdmsf_frame; /* the frame in bcd format */
|
||
|
} bcdmsf_t;
|
||
|
|
||
|
|
||
|
#ifdef EDC_LAYER2
|
||
|
/*
|
||
|
* data sector definitions for RSPC
|
||
|
* user data bytes per frame
|
||
|
*/
|
||
|
#define L2_RAW (1024*2)
|
||
|
|
||
|
#define L12_MODUL 255
|
||
|
#define L12_P_ERRORS 1
|
||
|
#define L12_Q_ERRORS 1
|
||
|
#define L12_P_LENGTH 43
|
||
|
#define L12_Q_LENGTH 26
|
||
|
#define L12_P_SKIPPED (L12_MODUL-L12_Q_LENGTH)
|
||
|
#define L12_Q_SKIPPED (L12_MODUL-L12_P_LENGTH-2*L12_Q_ERRORS)
|
||
|
|
||
|
/*
|
||
|
* parity bytes for 16 bit units
|
||
|
*/
|
||
|
#define L2_Q (L12_Q_LENGTH*2*L12_Q_ERRORS*2)
|
||
|
#define L2_P (L12_P_LENGTH*2*L12_P_ERRORS*2)
|
||
|
|
||
|
/*
|
||
|
* sector access macros
|
||
|
*
|
||
|
* col = column address of P layer
|
||
|
* dia = diagonal address of Q layer
|
||
|
* p = position in column or diagonal
|
||
|
*
|
||
|
* SECxyz calculate the position in the sector from offset 12, where
|
||
|
* x is B for byte access and W for word access
|
||
|
* y is P for the P parity layer and Q for the Q parity layer
|
||
|
* z is L for the least significant and M for the most significant byte
|
||
|
*/
|
||
|
/* word macros */
|
||
|
#define SECWP(col, p) (L12_P_LENGTH*(p)+(col))
|
||
|
/* byte macros */
|
||
|
#define SECBPL(col, p) (SECWP(col, p) << 1)
|
||
|
#define SECBPM(col, p) (SECBPL(col, p)+1)
|
||
|
|
||
|
#if defined USE_ARRAY
|
||
|
/* word macros */
|
||
|
#define SECWQ(dia, p) (qacc[dia][p] >> 1)
|
||
|
#define SECWQLO(dia, p) (qacc[dia][p] >> 1)
|
||
|
#define SECWQHI(dia, p) (qacc[dia][p] >> 1)
|
||
|
/* byte macros */
|
||
|
#define SECBQLLO(dia, p) (qacc[dia][p])
|
||
|
#define SECBQLHI(dia, p) (qacc[dia][p])
|
||
|
#define SECBQL(dia, p) (qacc[dia][p])
|
||
|
#define SECBQMLO(dia, p) (SECBQLLO(dia, p)+1)
|
||
|
#define SECBQMHI(dia, p) (SECBQLHI(dia, p)+1)
|
||
|
#define SECBQM(dia, p) (SECBQL(dia, p)+1)
|
||
|
#else
|
||
|
#define SECWQ(dia, p) (SECWQC(dia, p))
|
||
|
#define SECWQLO(dia, p) (SECWQLOC(dia, p))
|
||
|
#define SECWQHI(dia, p) (SECWQHIC(dia, p))
|
||
|
#define SECBQLLO(dia, p) (SECBQLLOC(dia, p))
|
||
|
#define SECBQLHI(dia, p) (SECBQLHIC(dia, p))
|
||
|
#define SECBQL(dia, p) (SECBQLC(dia, p))
|
||
|
#define SECBQMLO(dia, p) (SECBQMLOC(dia, p))
|
||
|
#define SECBQMHI(dia, p) (SECBQMHIC(dia, p))
|
||
|
#define SECBQM(dia, p) (SECBQMC(dia, p))
|
||
|
#endif
|
||
|
/* word macros */
|
||
|
#define SECWQLOC(dia, p) ((unsigned short)(L12_P_LENGTH*((p)+(dia))+(p)) % (unsigned short) (L12_P_LENGTH*L12_Q_LENGTH))
|
||
|
#define SECWQHIC(dia, p) (L12_Q_LENGTH*(p)+(dia))
|
||
|
#define SECWQC(dia, p) ((p) < L12_P_LENGTH ? SECWQLOC(dia, p) : SECWQHIC(dia, p))
|
||
|
/* byte macros */
|
||
|
#define SECBQLLOC(dia, p) (SECWQLOC(dia, p) << 1)
|
||
|
#define SECBQLHIC(dia, p) (SECWQHIC(dia, p) << 1)
|
||
|
#define SECBQLC(dia, p) ((p) < L12_P_LENGTH ? SECBQLLOC(dia, p) : SECBQLHIC(dia, p))
|
||
|
#define SECBQMLOC(dia, p) (SECBQLLOC(dia, p)+1)
|
||
|
#define SECBQMHIC(dia, p) (SECBQLHIC(dia, p)+1)
|
||
|
#define SECBQMC(dia, p) (SECBQLC(dia, p)+1)
|
||
|
|
||
|
|
||
|
/*
|
||
|
* conversion macros
|
||
|
*
|
||
|
* Calculate layer coordinates from a (12-byte based) sector offset in words
|
||
|
*
|
||
|
* POSP calculates the position in the column in the P parity layer
|
||
|
* COL calculates the column from the offset
|
||
|
*
|
||
|
* POSQ calculates the position in the diagonal in the Q parity layer
|
||
|
* DIA calculates the diagonal
|
||
|
*/
|
||
|
/* p parity macros */
|
||
|
#define POSP(off) (unsigned)((unsigned short)(off) / (unsigned short)L12_P_LENGTH)
|
||
|
#define COL(off) (unsigned)((unsigned short)(off) % (unsigned short)L12_P_LENGTH)
|
||
|
|
||
|
/* q parity macros */
|
||
|
#define POSQLO(off) COL(off)
|
||
|
#define POSQHI(off) (unsigned)((unsigned short)(off) / (unsigned short)L12_Q_LENGTH)
|
||
|
#define POSQ(off) ((unsigned short)(off) < (unsigned short)(L12_P_LENGTH*L12_Q_LENGTH) ? POSQLO(off) : POSQHI(off))
|
||
|
#define DIALO(off) (unsigned)((unsigned short)(POSP(off)-COL(off)+2*L12_Q_LENGTH)%(unsigned short)L12_Q_LENGTH)
|
||
|
#define DIAHI(off) (unsigned)((unsigned short)(off) % (unsigned short)L12_Q_LENGTH)
|
||
|
#define DIA(off) ((unsigned short)(off) < (unsigned short)(L12_P_LENGTH*L12_Q_LENGTH) ? DIALO(off) : DIAHI(off))
|
||
|
|
||
|
#ifdef EDC_ENCODER
|
||
|
/*
|
||
|
* data sector layer 2 Reed-Solomon Product Code encoder
|
||
|
*
|
||
|
* encode the given data portion depending on sector type (see
|
||
|
* get/set_sector_type() functions). Use the given address for the header.
|
||
|
* The returned data is __unscrambled__ and not in F2-frame format (for that
|
||
|
* see function scramble_L2()).
|
||
|
*
|
||
|
* Input parameter:
|
||
|
* sectortype
|
||
|
* EDC_MODE_0: a 12-byte sync field, a header and 2336 zeros are returned.
|
||
|
* EDC_MODE_1: the user data portion (2048 bytes) has to be given
|
||
|
* at offset 16 in the inout array.
|
||
|
* Sync-, header-, edc-, spare-, p- and q- fields will be added.
|
||
|
* EDC_MODE_2: the user data portion (2336 bytes) has to be given
|
||
|
* at offset 16 in the inout array.
|
||
|
* Sync- and header- fields will be added.
|
||
|
* EDC_MODE_2_FORM_1: the user data portion (8 bytes subheader followed
|
||
|
* by 2048 bytes data) has to be given at offset 16
|
||
|
* in the inout array.
|
||
|
* Sync-, header-, edc-, p- and q- fields will be added.
|
||
|
* EDC_MODE_2_FORM_2: the user data portion (8 bytes subheader followed
|
||
|
* by 2324 bytes data) has to be given at offset 16
|
||
|
* in the inout array.
|
||
|
* Sync-, header- and edc- fields will be added.
|
||
|
*
|
||
|
* inout is an array of 2352 or more bytes.
|
||
|
* address is a pointer to a bcdmsf_t struct
|
||
|
* holding bcd values for minute/second/frame address parts.
|
||
|
*
|
||
|
*/
|
||
|
int do_encode_L2 __PR((unsigned char *inout, int sectortype, bcdmsf_t *address));
|
||
|
#endif
|
||
|
|
||
|
#ifdef EDC_DECODER
|
||
|
|
||
|
#define NO_ERRORS 1
|
||
|
#define FULLY_CORRECTED 0
|
||
|
#define UNCORRECTABLE -1
|
||
|
#define WRONG_TYPE -2
|
||
|
/*
|
||
|
* data sector decoder for MODE 1 and MODE 2 FORM 1 sector types.
|
||
|
* Input parameters:
|
||
|
* inout:
|
||
|
* have_erasures: indicates error positions when > 0
|
||
|
* erasures: a value > 0 indicates an error at the corresponding
|
||
|
* position in the inout array.
|
||
|
*
|
||
|
* On output: inout has error corrected data, if correctable.
|
||
|
* return values:
|
||
|
* -1 uncorrectable
|
||
|
* 0 corrected
|
||
|
* 1 uncorrected (no correction needed)
|
||
|
*/
|
||
|
int do_decode_L2 __PR((unsigned char inout[(L2_RAW + L2_Q + L2_P)],
|
||
|
int sectortype, int have_erasures,
|
||
|
unsigned char erasures[(L2_RAW + L2_Q + L2_P)]));
|
||
|
|
||
|
/*
|
||
|
* calculate the crc checksum depending on the sector type.
|
||
|
*
|
||
|
* parameters:
|
||
|
* input:
|
||
|
* inout is the data sector as a byte array at offset 0
|
||
|
* type is the sector type (MODE_1, MODE_2_FORM_1 or MODE_2_FORM_2)
|
||
|
*
|
||
|
* return value: 1, if cyclic redundancy checksum is 0 (no errors)
|
||
|
* 0, if errors are present.
|
||
|
*
|
||
|
*/
|
||
|
int crc_check __PR((unsigned char inout[(L2_RAW + L2_Q + L2_P)], int type));
|
||
|
|
||
|
|
||
|
|
||
|
int encode_L2_P __PR((unsigned char *inout));
|
||
|
int encode_L2_Q __PR((unsigned char *inout));
|
||
|
#endif
|
||
|
|
||
|
extern const unsigned short qacc[26][64];
|
||
|
|
||
|
/*
|
||
|
* calculates checksum for data sectors
|
||
|
*/
|
||
|
unsigned int build_edc __PR((unsigned char inout[], unsigned from, unsigned upto));
|
||
|
|
||
|
/*
|
||
|
* generates f2 frames from otherwise fully formatted sectors (generated by
|
||
|
* do_encode_L2()).
|
||
|
*/
|
||
|
int scramble_L2 __PR((unsigned char *inout));
|
||
|
#endif
|
||
|
|
||
|
#ifdef EDC_SUBCHANNEL
|
||
|
/*
|
||
|
* r-w sub channel definitions
|
||
|
*/
|
||
|
#define RS_SUB_RW_BITS 6
|
||
|
|
||
|
#define PACKETS_PER_SUBCHANNELFRAME 4
|
||
|
#define LSUB_RAW 18
|
||
|
#define LSUB_QRAW 2
|
||
|
|
||
|
/*
|
||
|
* 6 bit entities
|
||
|
*/
|
||
|
#define LSUB_Q 2
|
||
|
#define LSUB_P 4
|
||
|
|
||
|
typedef struct del *edc_sub_delp;
|
||
|
|
||
|
/*
|
||
|
* Create an initialized instance of the subchannel delay line.
|
||
|
*
|
||
|
* Return a pointer to the initialized delay line object.
|
||
|
*/
|
||
|
edc_sub_delp create_edc_sub_del __PR((void));
|
||
|
|
||
|
#ifdef EDC_ENCODER
|
||
|
|
||
|
/*
|
||
|
* R-W subchannel encoder
|
||
|
* input: inout has 96 bytes data, four frames with 24 bytes each.
|
||
|
* output: four frames with 2 bytes user data, 2 bytes added Q parity,
|
||
|
* 16 bytes user data, 4 bytes added P parity.
|
||
|
*
|
||
|
* This routine fills the q and p parity fields.
|
||
|
* No interleaving is done here.
|
||
|
*/
|
||
|
int do_encode_sub __PR((
|
||
|
unsigned char inout[(LSUB_RAW + LSUB_Q + LSUB_P) * PACKETS_PER_SUBCHANNELFRAME]));
|
||
|
|
||
|
|
||
|
/*
|
||
|
* R-W subchannel interleaver
|
||
|
*
|
||
|
* Apply after parity code generation.
|
||
|
*
|
||
|
* input: inout has 96 bytes user data, four frames with 24 bytes each.
|
||
|
* output: as above but swapped and interleaved.
|
||
|
*
|
||
|
* Parameter:
|
||
|
* swap : if true, perform low level permutations (swaps)
|
||
|
* delay: if true, use low level delay line
|
||
|
* delp: pointer to a edc_sub_del struct
|
||
|
* (holding the state of the delay line)
|
||
|
* this pointer is dereferenced only, if parameter delay is true.
|
||
|
*/
|
||
|
int
|
||
|
packed_to_raw __PR((unsigned char inout[(LSUB_RAW + LSUB_Q + LSUB_P) * PACKETS_PER_SUBCHANNELFRAME],
|
||
|
int swap, int delay, edc_sub_delp delp));
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef EDC_DECODER
|
||
|
/*
|
||
|
* R-W subchannel deinterleaver
|
||
|
*
|
||
|
* Apply before correction.
|
||
|
*
|
||
|
* input: inout has 96 bytes user data, four frames with 24 bytes each.
|
||
|
* output: as above but swapped and interleaved (delayed).
|
||
|
*
|
||
|
* Parameter:
|
||
|
* swap : if true, perform permutations (swaps)
|
||
|
* delay: if true, use delay line
|
||
|
* delp: pointer to a edc_sub_delp struct
|
||
|
* (holding the state of the delay line)
|
||
|
* this pointer is dereferenced only, if parameter delay is true.
|
||
|
*/
|
||
|
int
|
||
|
raw_to_packed __PR((unsigned char inout[(LSUB_RAW + LSUB_Q + LSUB_P) * PACKETS_PER_SUBCHANNELFRAME],
|
||
|
int swap, int delay, edc_sub_delp delp));
|
||
|
|
||
|
/*
|
||
|
* R-W subchannel decoder
|
||
|
* On input: inout: 96 bytes packed user data, four frames with each 24 bytes.
|
||
|
* have_erasures: indicates error positions when > 0
|
||
|
* erasures: a value > 0 indicates an error at the corresponding
|
||
|
* position in the inout array.
|
||
|
*
|
||
|
* On output: inout has error corrected data, if correctable.
|
||
|
* return values:
|
||
|
* -1 uncorrectable
|
||
|
* 0 corrected
|
||
|
* 1 uncorrected (not needed)
|
||
|
*/
|
||
|
int do_decode_sub __PR((
|
||
|
unsigned char inout[(LSUB_RAW + LSUB_Q + LSUB_P) * PACKETS_PER_SUBCHANNELFRAME],
|
||
|
int have_erasures,
|
||
|
unsigned char erasures[(LSUB_RAW + LSUB_Q+LSUB_P) *PACKETS_PER_SUBCHANNELFRAME],
|
||
|
int results[PACKETS_PER_SUBCHANNELFRAME]));
|
||
|
|
||
|
int check_sub __PR((unsigned char input[]));
|
||
|
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#endif /* EDC_DECODER_HACK */
|
||
|
/*
|
||
|
* XXX Remove this if EDC_DECODER_HACK is removed
|
||
|
*/
|
||
|
int do_decode_L2 __PR((unsigned char inout[(L2_RAW + L2_Q + L2_P)],
|
||
|
int sectortype, int have_erasures,
|
||
|
unsigned char erasures[(L2_RAW + L2_Q + L2_P)]));
|
||
|
int crc_check __PR((unsigned char inout[(L2_RAW + L2_Q + L2_P)], int type));
|