//******************************************************************************/
//*                                                                            *
//*    tc6807af.c -                                                            *
//*                                                                            *
//*    Copyright (c) C-Cube Microsystems 1996                                  *
//*    All Rights Reserved.                                                    *
//*                                                                            *
//*    Use of C-Cube Microsystems code is governed by terms and conditions     *
//*    stated in the accompanying licensing statement.                         *
//*                                                                            *
//******************************************************************************/


//
//  TC6907AF.C  Digital Copy-Protection for DVD
//
/////////////////////////////////////////////////////////////////////
#ifdef VTOOLSD
#include <vtoolsc.h>
#include "monovxd.h"
#else
#include "Headers.h"
#pragma hdrstop
#endif

#include "cl6100.h"
#include "tc6807af.h"
#include "fpga.h"
#include "bmaster.h"
#include "boardio.h"

//-------------------------------------------------------------------
//  TC6907AF REGISTERS DECLARATION
//-------------------------------------------------------------------
#define COM         0x00
#define CNT_1       0x01
#define CNT_2       0x02
#define SD_STS      0x03
#define DEPT_1      0x04
#define DEPT_2      0x05

#define ETKG_0      0x10
#define ETKG_1      0x11
#define ETKG_2      0x12
#define ETKG_3      0x13
#define ETKG_4      0x14
#define ETKG_5      0x15

#define CHGG_0      0x30
#define CHGG_1      0x31
#define CHGG_2      0x32
#define CHGG_3      0x33
#define CHGG_4      0x34
#define CHGG_5      0x35
#define CHGG_6      0x36
#define CHGG_7      0x37
#define CHGG_8      0x38
#define CHGG_9      0x39

#define RSPG_0      0x40
#define RSPG_1      0x41
#define RSPG_2      0x42
#define RSPG_3      0x43
#define RSPG_4      0x44

// COM register bits
#define END         0x80
#define ERR         0x40

// CNT_1 register bits
#define RQ1         0x01
#define RQ2         0x02
#define ENBEND      0x04
#define ENBERR      0x08
#define CLINT       0x10

// CNT_2 register bits
#define THR         0x01
#define EB1         0x02
#define EB2         0x04
#define CDV16       0x08
#define AJSCK       0x10
#define SCR1        0x20
#define SCR2        0x40
#define SCR3        0x80

// Commands
#define NOP         0x00
#define DEC_RAND    0x12
#define DEC_DKY     0x15
#define DRV_AUTH    0x17
#define DEC_AUTH    0x18
#define DEC_DT      0x23
#define DEC_DTK     0x25

//-------------------------------------------------------------------
//  GLOBAL VARIABLES DECLARATION
//-------------------------------------------------------------------
DWORD  gdwIndex = 0;
DWORD  gdwData  = 0;

//-------------------------------------------------------------------
//  STATIC FUNCTIONS DECLARATION
//-------------------------------------------------------------------
BOOL tc6807af_GetChallengeData( BYTE * CHG );
BOOL tc6807af_SendChallengeData( BYTE * CHG );
BOOL tc6807af_GetResponseData( BYTE * RSP );
BOOL tc6807af_SendResponseData( BYTE * RSP );
BOOL tc6807af_SendDiskKeyData( BYTE * pBuffer );
BOOL tc6807af_SendTitleKeyData( BYTE * pBuffer );
BOOL tc6807af_SetDecryptionMode( BYTE * SR_FLAG );
BOOL tc6807af_NewCommand( BYTE Command );
void  tc6807af_WriteReg( BYTE byReg, BYTE byValue );
BYTE tc6807af_ReadReg( BYTE byReg );

//
//  TC6807AF_Initialize
//
/////////////////////////////////////////////////////////////////////
BOOL TC6807AF_Initialize( DWORD dwBaseAddress )
 {
  MonoOutStr( " �� TC6807AF_Initialize " );
  MonoOutHex( dwBaseAddress );

  gdwIndex = dwBaseAddress;
  gdwData  = dwBaseAddress + 1;

  //tc6807af_WriteReg( CNT_1, ENBERR | ENBEND | RQ1 | RQ2 );

  // Step 1.
  tc6807af_WriteReg( CNT_2, 0|CDV16 );

  // Step 2.
  //tc6807af_WriteReg( CNT_2, AJSCK );
  /*
  tc6807af_WriteReg( CNT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK );
  tc6807af_WriteReg( CNT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK );
  tc6807af_WriteReg( CNT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK );
  tc6807af_WriteReg( CNT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK );
  tc6807af_WriteReg( CNT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK );
  tc6807af_WriteReg( CNT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK );
  tc6807af_WriteReg( CNT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK );
  tc6807af_WriteReg( CNT_2, 0 );
  */
  // Step 3.
  tc6807af_WriteReg( CNT_1, CLINT );

  // Step 4.
  tc6807af_WriteReg( DEPT_1, 0 );
  tc6807af_WriteReg( DEPT_2, 0 );
  tc6807af_WriteReg( CNT_2, AJSCK|SCR1 );

  // Step 5.
  tc6807af_WriteReg( CNT_1, RQ1 | RQ2 );
  tc6807af_WriteReg( CNT_2, AJSCK|SCR1|EB2|EB1|THR );

  MonoOutStr( " Ķ " );
  return TRUE;
 }

//
//  TC6807AF_Reset
//
/////////////////////////////////////////////////////////////////////
BOOL TC6807AF_Reset()
 {
  return TRUE;
 }

//
//  TC6807AF_Authenticate
//
/////////////////////////////////////////////////////////////////////
BOOL TC6807AF_Authenticate( WORD wFunction, BYTE * pbyDATA )
 {
  switch ( wFunction )
  {
  case TC6807AF_GET_CHALLENGE:
    return tc6807af_GetChallengeData( pbyDATA );

  case TC6807AF_SEND_CHALLENGE:
    return tc6807af_SendChallengeData( pbyDATA );

  case TC6807AF_GET_RESPONSE:
    return tc6807af_GetResponseData( pbyDATA );

  case TC6807AF_SEND_RESPONSE:
    return tc6807af_SendResponseData( pbyDATA );

  case TC6807AF_SEND_DISK_KEY:
    return tc6807af_SendDiskKeyData( pbyDATA );

  case TC6807AF_SEND_TITLE_KEY:
    return tc6807af_SendTitleKeyData( pbyDATA );

  case TC6807AF_SET_DECRYPTION_MODE:
    return tc6807af_SetDecryptionMode( pbyDATA );
  }

  return FALSE;
 }


/******************************************************************************/
/******************* STATIC FUNCTIONS IMPLEMENTATION **************************/
/******************************************************************************/


//
//  tc6807af_GetChallengeData
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_GetChallengeData( BYTE * CHG )
 {
  MonoOutStr( " [DEC_RAND:" );

  if ( !tc6807af_NewCommand( DEC_RAND ) )
    return FALSE;


  CHG[0] = tc6807af_ReadReg( CHGG_0 );
  CHG[1] = tc6807af_ReadReg( CHGG_1 );
  CHG[2] = tc6807af_ReadReg( CHGG_2 );
  CHG[3] = tc6807af_ReadReg( CHGG_3 );
  CHG[4] = tc6807af_ReadReg( CHGG_4 );
  CHG[5] = tc6807af_ReadReg( CHGG_5 );
  CHG[6] = tc6807af_ReadReg( CHGG_6 );
  CHG[7] = tc6807af_ReadReg( CHGG_7 );
  CHG[8] = tc6807af_ReadReg( CHGG_8 );
  CHG[9] = tc6807af_ReadReg( CHGG_9 );

  MonoOutStr( "] " );
  return TRUE;
 }

//
//  tc6807af_SendChallengeData
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_SendChallengeData( BYTE * CHG )
 {
  MonoOutStr( " [DEC_AUTH:" );

  tc6807af_WriteReg( CHGG_0, CHG[0] );
  tc6807af_WriteReg( CHGG_1, CHG[1] );
  tc6807af_WriteReg( CHGG_2, CHG[2] );
  tc6807af_WriteReg( CHGG_3, CHG[3] );
  tc6807af_WriteReg( CHGG_4, CHG[4] );
  tc6807af_WriteReg( CHGG_5, CHG[5] );
  tc6807af_WriteReg( CHGG_6, CHG[6] );
  tc6807af_WriteReg( CHGG_7, CHG[7] );
  tc6807af_WriteReg( CHGG_8, CHG[8] );
  tc6807af_WriteReg( CHGG_9, CHG[9] );

  if ( !tc6807af_NewCommand( DEC_AUTH ) )
    return FALSE;

  return TRUE;
 }

//
//  tc6807af_GetResponseData
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_GetResponseData( BYTE * RSP )
 {
  MonoOutStr( " [GetResponseData" );

  RSP[0] = tc6807af_ReadReg( RSPG_0 );
  RSP[1] = tc6807af_ReadReg( RSPG_1 );
  RSP[2] = tc6807af_ReadReg( RSPG_2 );
  RSP[3] = tc6807af_ReadReg( RSPG_3 );
  RSP[4] = tc6807af_ReadReg( RSPG_4 );

  MonoOutStr( "] " );
  return TRUE;
 }

//
//  tc6807af_SendResponseData
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_SendResponseData( BYTE * RSP )
 {
  MonoOutStr( " [DRV_AUTH:" );

  tc6807af_WriteReg( RSPG_0, RSP[0] );
  tc6807af_WriteReg( RSPG_1, RSP[1] );
  tc6807af_WriteReg( RSPG_2, RSP[2] );
  tc6807af_WriteReg( RSPG_3, RSP[3] );
  tc6807af_WriteReg( RSPG_4, RSP[4] );

  if ( !tc6807af_NewCommand( DRV_AUTH ) )
    return FALSE;

  return TRUE;
 }

//
//  tc6807af_SendDiskKeyData
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_SendDiskKeyData( BYTE * pBuffer )
 {
  DWORD physAddress;
  DWORD dwTimeout = 10000;
  BYTE  byValue;
  int i;

  MonoOutStr( " [DEC_DKY:" );
  //tc6807af_WriteReg( CNT_1, ENBERR | ENBEND | RQ1 );
  tc6807af_WriteReg( CNT_1, RQ1 );
  tc6807af_WriteReg( CNT_2, SCR1 | EB2 );
  tc6807af_WriteReg( COM, DEC_DKY );
  tc6807af_WriteReg( CNT_1, RQ2|RQ1 );
  tc6807af_WriteReg( CNT_2, SCR1 | EB2|EB1 );

  MonoOutStr( "DiskKey:" );
  MonoOutULongHex( *((DWORD *)pBuffer) );
  MonoOutStr( " pBuffer:" );
  MonoOutULongHex( (DWORD)pBuffer );

  // Send one sector
#ifdef VTOOLSD
  CopyPageTable( (DWORD)pBuffer >> 12, 1, (PVOID*)&physAddress, 0 );
  physAddress = (physAddress & 0xfffff000) + (((DWORD)pBuffer) & 0xfff);
#else
  physAddress = (DWORD)pBuffer;
#endif

  FPGA_Set( FPGA_SECTOR_START );

  for ( i=0; i<32; i++ )
  {
    if ( !BMA_Send( (DWORD *) (physAddress+i*64), 64 ) )
      return FALSE;

    dwTimeout = 10000;
    while ( !BMA_Complete() )
    {
      //dvd_SetRequestEnable();

      if ( !(--dwTimeout) )
      {
        MonoOutStr( " BMA did not complete " );
        return FALSE;
      }
    }

    dvd_SetRequestEnable();
  }


  FPGA_Clear( FPGA_SECTOR_START );
  //tc6807af_WriteReg( CNT_1, CLINT );

  dwTimeout = 400000;
  while ( --dwTimeout )
  {
    byValue = tc6807af_ReadReg( COM );
    if ( byValue & END )
    {
      //tc6807af_WriteReg( CNT_1, CLINT | RQ1 );
      if ( byValue & ERR )
      {
        //tc6807af_WriteReg( CNT_1, CLINT | RQ1 );
        MonoOutStr( "ERR] " );
        return FALSE;
      }
      MonoOutStr( "End] " );
      return TRUE;
    }

  }

  //tc6807af_WriteReg( CNT_1, CLINT | RQ1 );
  MonoOutStr( "Timeout] " );
  return FALSE;
 }

//
//  tc6807af_SendTilteKeyData
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_SendTitleKeyData( BYTE * ETK )
 {
  DWORD dwTimeout = 100000;
  BYTE  byValue;

  MonoOutStr( " [DEC_DTK:" );

  tc6807af_WriteReg( ETKG_0, ETK[0] );
  tc6807af_WriteReg( ETKG_1, ETK[1] );
  tc6807af_WriteReg( ETKG_2, ETK[2] );
  tc6807af_WriteReg( ETKG_3, ETK[3] );
  tc6807af_WriteReg( ETKG_4, ETK[4] );
  tc6807af_WriteReg( ETKG_5, ETK[5] );

  tc6807af_WriteReg( COM, NOP );
  tc6807af_WriteReg( COM, DEC_DTK );

  while ( --dwTimeout )
  {
    byValue = tc6807af_ReadReg( COM );
    if ( byValue & END )
    {
      if ( byValue & ERR )
      {
        MonoOutStr( "ERR] " );
        return FALSE;
      }
      MonoOutStr( "End] " );
      return TRUE;
    }

  }

  MonoOutStr( "Timeout] " );
  return FALSE;
 }

//
//  tc6807af_SetDecryptionMode
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_SetDecryptionMode( BYTE * SR_FLAG )
 {
  DWORD dwTimeout = 100000;
  BYTE  byValue;

  MonoOutStr( " [DEC_DT:" );

  if ( *SR_FLAG )
  {
    //tc6807af_WriteReg( CNT_2, EB2 );
    tc6807af_WriteReg( COM, NOP );
    tc6807af_WriteReg( COM, DEC_DT );

    MonoOutStr( "] " );
    return TRUE;

    while ( --dwTimeout )
    {
      byValue = tc6807af_ReadReg( COM );
      if ( byValue & END )
      {
        if ( byValue & ERR )
        {
          MonoOutStr( "ERR] " );
          return FALSE;
        }
        MonoOutStr( "End] " );
        return TRUE;
      }

    }

    MonoOutStr( "Timeout] " );
    return FALSE;
  }
  else
  {
    tc6807af_WriteReg( CNT_2, SCR1 | EB2 | EB1 | THR );
    MonoOutStr( "Pass Through] " );
    return TRUE;
  }

 }


/******************************************************************************/
/******************* LOW LEVEL FUNCTIONS IMPLEMENTATION ***********************/
/******************************************************************************/

//
//  tc6807af_NewCommand
//
/////////////////////////////////////////////////////////////////////
BOOL tc6807af_NewCommand( BYTE Command )
 {
  DWORD dwTimeout = 10000;
  BYTE  byValue;

  tc6807af_WriteReg( COM, Command );

  if ( (Command == NOP) || (Command == DEC_RAND) )
    return TRUE;

  while ( --dwTimeout )
  {
    byValue = tc6807af_ReadReg( COM );
    if ( byValue & END )
    {
      if ( byValue & ERR )
      {
        MonoOutStr( "ERR] " );
        return FALSE;
      }
      MonoOutStr( "End] " );
      return TRUE;
    }
  }

  MonoOutStr( "Timeout] " );
  return FALSE;
 }


//
//  tc6807af_WriteReg
//
/////////////////////////////////////////////////////////////////////
void  tc6807af_WriteReg( BYTE byReg, BYTE byValue )
 {
  BRD_WriteByte( gdwIndex, byReg );
  BRD_WriteByte( gdwData, byValue );
 }

//
//  tc6807af_ReadReg
//
/////////////////////////////////////////////////////////////////////
BYTE tc6807af_ReadReg( BYTE byReg )
 {
  BRD_WriteByte( gdwIndex, byReg );
  return BRD_ReadByte( gdwData );
 }