#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
//#include "stdlib.h"
//#include "EUCR6SK.h"
#include "smcommon.h"
#include "smil.h"

//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//#include <dos.h>
//
//#include "EMCRIOS.h"

// CP0-CP5 code table
static BYTE ecctable[256] = {
0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00,
0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65,
0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66,
0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03,
0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69,
0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C,
0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F,
0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A,
0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A,
0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F,
0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C,
0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69,
0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03,
0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66,
0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65,
0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00
};

static void   trans_result  (BYTE,   BYTE,   BYTE *, BYTE *);

#define BIT7        0x80
#define BIT6        0x40
#define BIT5        0x20
#define BIT4        0x10
#define BIT3        0x08
#define BIT2        0x04
#define BIT1        0x02
#define BIT0        0x01
#define BIT1BIT0    0x03
#define BIT23       0x00800000L
#define MASK_CPS    0x3f
#define CORRECTABLE 0x00555554L

static void trans_result(reg2,reg3,ecc1,ecc2)
BYTE reg2; // LP14,LP12,LP10,...
BYTE reg3; // LP15,LP13,LP11,...
BYTE *ecc1; // LP15,LP14,LP13,...
BYTE *ecc2; // LP07,LP06,LP05,...
{
    BYTE a; // Working for reg2,reg3
    BYTE b; // Working for ecc1,ecc2
    BYTE i; // For counting

    a=BIT7; b=BIT7; // 80h=10000000b
    *ecc1=*ecc2=0; // Clear ecc1,ecc2
    for(i=0; i<4; ++i) {
        if ((reg3&a)!=0)
            *ecc1|=b; // LP15,13,11,9 -> ecc1
        b=b>>1; // Right shift
        if ((reg2&a)!=0)
            *ecc1|=b; // LP14,12,10,8 -> ecc1
        b=b>>1; // Right shift
        a=a>>1; // Right shift
    }

    b=BIT7; // 80h=10000000b
    for(i=0; i<4; ++i) {
        if ((reg3&a)!=0)
            *ecc2|=b; // LP7,5,3,1 -> ecc2
        b=b>>1; // Right shift
        if ((reg2&a)!=0)
            *ecc2|=b; // LP6,4,2,0 -> ecc2
        b=b>>1; // Right shift
        a=a>>1; // Right shift
    }
}

//static void calculate_ecc(table,data,ecc1,ecc2,ecc3)
void calculate_ecc(table,data,ecc1,ecc2,ecc3)
BYTE *table; // CP0-CP5 code table
BYTE *data; // DATA
BYTE *ecc1; // LP15,LP14,LP13,...
BYTE *ecc2; // LP07,LP06,LP05,...
BYTE *ecc3; // CP5,CP4,CP3,...,"1","1"
{
    DWORD  i;    // For counting
    BYTE a;    // Working for table
    BYTE reg1; // D-all,CP5,CP4,CP3,...
    BYTE reg2; // LP14,LP12,L10,...
    BYTE reg3; // LP15,LP13,L11,...

    reg1=reg2=reg3=0;   // Clear parameter
    for(i=0; i<256; ++i) {
        a=table[data[i]]; // Get CP0-CP5 code from table
        reg1^=(a&MASK_CPS); // XOR with a
        if ((a&BIT6)!=0)
        { // If D_all(all bit XOR) = 1
            reg3^=(BYTE)i; // XOR with counter
            reg2^=~((BYTE)i); // XOR with inv. of counter
        }
    }

    // Trans LP14,12,10,... & LP15,13,11,... -> LP15,14,13,... & LP7,6,5,..
    trans_result(reg2,reg3,ecc1,ecc2);
    *ecc1=~(*ecc1); *ecc2=~(*ecc2); // Inv. ecc2 & ecc3
    *ecc3=((~reg1)<<2)|BIT1BIT0; // Make TEL format
}

BYTE correct_data(data,eccdata,ecc1,ecc2,ecc3)
BYTE *data; // DATA
BYTE *eccdata; // ECC DATA
BYTE ecc1; // LP15,LP14,LP13,...
BYTE ecc2; // LP07,LP06,LP05,...
BYTE ecc3; // CP5,CP4,CP3,...,"1","1"
{
    DWORD l; // Working to check d
    DWORD d; // Result of comparison
    DWORD i; // For counting
    BYTE d1,d2,d3; // Result of comparison
    BYTE a; // Working for add
    BYTE add; // Byte address of cor. DATA
    BYTE b; // Working for bit
    BYTE bit; // Bit address of cor. DATA

    d1=ecc1^eccdata[1]; d2=ecc2^eccdata[0]; // Compare LP's
    d3=ecc3^eccdata[2]; // Comapre CP's
    d=((DWORD)d1<<16) // Result of comparison
    +((DWORD)d2<<8)
    +(DWORD)d3;

    if (d==0) return(0); // If No error, return

    if (((d^(d>>1))&CORRECTABLE)==CORRECTABLE)
    { // If correctable
        l=BIT23;
        add=0; // Clear parameter
        a=BIT7;

        for(i=0; i<8; ++i) { // Checking 8 bit
            if ((d&l)!=0) add|=a; // Make byte address from LP's
            l>>=2; a>>=1; // Right Shift
        }

        bit=0; // Clear parameter
        b=BIT2;
        for(i=0; i<3; ++i) { // Checking 3 bit
            if ((d&l)!=0) bit|=b; // Make bit address from CP's
            l>>=2; b>>=1; // Right shift
        }

        b=BIT0;
        data[add]^=(b<<bit); // Put corrected data
        return(1);
    }

    i=0; // Clear count
    d&=0x00ffffffL; // Masking

    while(d) { // If d=0 finish counting
        if (d&BIT0) ++i; // Count number of 1 bit
        d>>=1; // Right shift
    }

    if (i==1)
    { // If ECC error
        eccdata[1]=ecc1; eccdata[0]=ecc2; // Put right ECC code
        eccdata[2]=ecc3;
        return(2);
    }
    return(3); // Uncorrectable error
}

int _Correct_D_SwECC(buf,redundant_ecc,calculate_ecc)
BYTE *buf;
BYTE *redundant_ecc;
BYTE *calculate_ecc;
{
	DWORD err;

	err = correct_data(buf, redundant_ecc, *(calculate_ecc + 1),
			   *(calculate_ecc), *(calculate_ecc + 2));
	if (err == 1)
		memcpy(calculate_ecc, redundant_ecc, 3);

	if (err == 0 || err == 1 || err == 2)
		return 0;

	return -1;
}

void _Calculate_D_SwECC(buf,ecc)
BYTE *buf;
BYTE *ecc;
{
    calculate_ecc(ecctable,buf,ecc+1,ecc+0,ecc+2);
}


