/***************************************************************************
                            cdr.c  -  description
                             -------------------
    begin                : Sun Nov 16 2003
    copyright            : (C) 2003 by Pete Bernert
    email                : BlackDove@addcom.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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. See also the license.txt file for *
 *   additional informations.                                              *
 *                                                                         *
 ***************************************************************************/

//*************************************************************************//
// History of changes:
//
// 2004/12/25 - Pete
// - added an hack in CDVDgetTD for big dvds
//
// 2003/11/16 - Pete
// - generic cleanup for the Peops cdvd release
//
//*************************************************************************//

/////////////////////////////////////////////////////////

#include "stdafx.h"
#include <time.h>
#include "resource.h"
#define _IN_CDR
#include "externals.h"
#define CDVDdefs
#include "PS2Etypes.h"
#include "PS2Edefs.h"
#include "libiso.h"

#ifdef DBGOUT
#define SMALLDEBUG 1
#include <dbgout.h>
#endif

/////////////////////////////////////////////////////////
// PCSX2 CDVD interface:

EXPORT_GCC char *          CALLBACK PS2EgetLibName();
EXPORT_GCC unsigned long   CALLBACK PS2EgetLibType();
EXPORT_GCC unsigned long   CALLBACK PS2EgetLibVersion2(unsigned long type);
EXPORT_GCC long            CALLBACK CDVDinit();
EXPORT_GCC void            CALLBACK CDVDshutdown();
EXPORT_GCC long            CALLBACK CDVDopen(const char* pTitle);
EXPORT_GCC void            CALLBACK CDVDclose();
EXPORT_GCC long            CALLBACK CDVDtest();
EXPORT_GCC long            CALLBACK CDVDreadTrack(unsigned long lsn, int mode);
EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer();
EXPORT_GCC long            CALLBACK CDVDgetTN(cdvdTN *Buffer);
EXPORT_GCC long            CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer);
EXPORT_GCC long            CALLBACK CDVDgetDiskType();
EXPORT_GCC long            CALLBACK CDVDgetTrayStatus();

/////////////////////////////////////////////////////////

const unsigned char version  =  PS2E_CDVD_VERSION;
const unsigned char revision =  1;
const unsigned char build    =  3;

#ifdef _DEBUG
char *libraryName            =  "P.E.Op.S. CDVD (Debug, CDDA mod)";
#else
char *libraryName            =  "P.E.Op.S. CDVD (CDDA mod)";
#endif

/////////////////////////////////////////////////////////

BOOL bIsOpen=FALSE;                                    // flag: open called once
BOOL bCDDAPlay=FALSE;                                  // flag: audio is playing
int  iCDROK=0;                                         // !=0: cd is ok
int  iCDType=CDVD_TYPE_UNKNOWN;                        // CD/DVD
int  iCheckTrayStatus=0;                               // if 0 : report tray as closed, else try a real check
void *fdump;

/////////////////////////////////////////////////////////
// usual info funcs

EXPORT_GCC char * CALLBACK PS2EgetLibName()
{
 return libraryName;
}

EXPORT_GCC unsigned long CALLBACK PS2EgetLibType()
{
 return PS2E_LT_CDVD;
}

EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type)
{
 return version<<16|revision<<8|build;
}
/*
EXPORT_GCC unsigned long CALLBACK PS2EgetCpuPlatform(void)
{
 return PS2E_X86;
// return PS2E_X86_64;
}*/

s32 msf_to_lba(u8 m, u8 s, u8 f) {
	u32 lsn;
	lsn = f;
	lsn+=(s - 2) * 75;
	lsn+= m * 75 * 60;
	return lsn;
}

void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) {
	lba += 150;
	*m = (u8)(lba / (60*75));
	*s = (u8)((lba / 75) % 60);
	*f = (u8)(lba % 75);
}

/////////////////////////////////////////////////////////
// init: called once at library load

EXPORT_GCC long CALLBACK CDVDinit()
{
 szSUBF[0]=0;                                          // just init the filename buffers
 szPPF[0] =0;
 return 0;
}

/////////////////////////////////////////////////////////
// shutdown: called once at final exit

EXPORT_GCC void CALLBACK CDVDshutdown()
{
}

/////////////////////////////////////////////////////////
// open: called, when games starts/cd has been changed

int CheckDiskType(int baseType);

EXPORT_GCC long CALLBACK CDVDopen(const char* pTitle)
{
	int i,audioTracks,dataTracks;
	cdvdTD T;
 if(bIsOpen)                                           // double-open check (if the main emu coder doesn't know what he is doing ;)
  {
   if(iCDROK<=0) return -1;
   else          return 0;
  }

 bIsOpen=TRUE;                                         // ok, open func called once

 ReadConfig();                                         // read user config

 BuildPPFCache();                                      // build ppf cache

 BuildSUBCache();                                      // build sub cache

 CreateREADBufs();                                     // setup generic read buffers

 CreateGenEvent();                                     // create read event

 iCDROK=OpenGenCD(iCD_AD,iCD_TA,iCD_LU);               // generic open, setup read func

 if(iCDROK<=0) {iCDROK=0;return -1;}

 ReadTOC();                                            // read the toc

 SetGenCDSpeed(0);                                     // try to change the reading speed (if wanted)

 iCDType=CDVD_TYPE_UNKNOWN;                            // let's look after the disc type
                                                       // (funny stuff taken from Xobro's/Florin's bin plugin)
 if(CDVDreadTrack(16,CDVD_MODE_2048)==0)
  {
   struct cdVolDesc *volDesc;
   volDesc=(struct cdVolDesc *)CDVDgetBuffer();
   if(volDesc)
    {

//todo: CDVD_TYPE_CDDA

     if(volDesc->rootToc.tocSize==2048)
          iCDType = CDVD_TYPE_DETCTCD;
     else iCDType = CDVD_TYPE_DETCTDVDS;
    }
  }

  fprintf(stderr," * CDVD Disk Open: %d tracks (%d to %d):\n",sTOC.cLastTrack-sTOC.cFirstTrack+1,sTOC.cFirstTrack,sTOC.cLastTrack);

  audioTracks=dataTracks=0;
  for(i=sTOC.cFirstTrack;i<=sTOC.cLastTrack;i++)
  {
      CDVDgetTD(i,&T);
	  if(T.type==CDVD_AUDIO_TRACK) {
		  audioTracks++;
		  fprintf(stderr," * * Track %d: Audio (%d sectors)\n",i,T.lsn);
	  }
	  else {
		  dataTracks++;
		  fprintf(stderr," * * Track %d: Data (Mode %d) (%d sectors)\n",i,((T.type==CDVD_MODE1_TRACK)?1:2),T.lsn);
	  }
  }
  if((dataTracks==0)&&(audioTracks>0))
	iCDType=CDVD_TYPE_CDDA;
  else if(dataTracks>0)
	  iCDType=CheckDiskType(iCDType);

  if((iCDType==CDVD_TYPE_ILLEGAL)&&(audioTracks>0))
	  iCDType=CDVD_TYPE_CDDA;
  else if((iCDType==CDVD_TYPE_PS2CD)&&(audioTracks>0))
	  iCDType=CDVD_TYPE_PS2CDDA;
  else if((iCDType==CDVD_TYPE_PSCD)&&(audioTracks>0))
	  iCDType=CDVD_TYPE_PSCDDA;

  switch(iCDType) {
	case CDVD_TYPE_ILLEGAL: // Illegal Disc
		fprintf(stderr," * Disk Type: Illegal Disk.\n");break;
	case CDVD_TYPE_DVDV: // DVD Video
		fprintf(stderr," * Disk Type: DVD Video.\n");break;
	case CDVD_TYPE_CDDA: // Audio CD
		fprintf(stderr," * Disk Type: CDDA.\n");break;
	case CDVD_TYPE_PS2DVD: // PS2 DVD
		fprintf(stderr," * Disk Type: PS2 DVD.\n");break;
	case CDVD_TYPE_PS2CDDA: // PS2 CD (with audio)
		fprintf(stderr," * Disk Type: PS2 CD+Audio.\n");break;
	case CDVD_TYPE_PS2CD: // PS2 CD
		fprintf(stderr," * Disk Type: PS2 CD.\n");break;
	case CDVD_TYPE_PSCDDA: // PS CD (with audio)
		fprintf(stderr," * Disk Type: PS1 CD+Audio.\n");break;
	case CDVD_TYPE_PSCD: // PS CD
		fprintf(stderr," * Disk Type: PS1 CD.\n");break;
	case CDVD_TYPE_UNKNOWN: // Unknown
		fprintf(stderr," * Disk Type: Unknown.\n");break;
	case CDVD_TYPE_NODISC: // No Disc
		fprintf(stderr," * Disk Type: No Disc.\n");break;
  }

/*	if (iBlockDump)*/ {
//		fdump = isoCreate("block.dump", ISOFLAGS_BLOCKDUMP);
		fdump = NULL;
		if (fdump) {
			cdvdTD buf;
			CDVDgetTD(0, &buf);
			isoSetFormat(fdump, 0, 2352, buf.lsn);
		}
	} /*else {
		fdump = NULL;
	}*/


 return 0;                                             // ok, done
}

/////////////////////////////////////////////////////////
// close: called when emulation stops

EXPORT_GCC void CALLBACK CDVDclose()
{
 if(!bIsOpen) return;                                  // no open? no close...

	if (fdump != NULL) {
		isoClose(fdump);
	}
 bIsOpen=FALSE;                                        // no more open

 LockGenCDAccess();                                    // make sure that no more reading is happening

 if(iCDROK)                                            // cd was ok?
  {
   if(bCDDAPlay) {DoCDDAPlay(0);bCDDAPlay=FALSE;}      // -> cdda playing? stop it
   SetGenCDSpeed(1);                                   // -> repair speed
   CloseGenCD();                                       // -> cd not used anymore
  }

 UnlockGenCDAccess();

 FreeREADBufs();                                       // free read bufs
 FreeGenEvent();                                       // free event
 FreePPFCache();                                       // free ppf cache
 FreeSUBCache();                                       // free sub cache
}

/////////////////////////////////////////////////////////
// test: ah, well, always fine

EXPORT_GCC long CALLBACK CDVDtest()
{
 return 0;
}

/////////////////////////////////////////////////////////
// readSubQ: read subq from disc (only cds have subq data)
EXPORT_GCC long CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq)
{
	u8 min, sec, frm;

	if(!bIsOpen)   CDVDopen("DVD");                            // usual checks
	if(!iCDROK)    return -1;

	// fake it
	subq->ctrl		= 4;
	subq->mode		= 1;
	subq->trackNum	= itob(1);
	subq->trackIndex= itob(1);

	lba_to_msf(lsn, &min, &sec, &frm);
	subq->trackM	= itob(min);
	subq->trackS	= itob(sec);
	subq->trackF	= itob(frm);

	subq->pad		= 0;

	lba_to_msf(lsn + (2*75), &min, &sec, &frm);
	subq->discM		= itob(min);
	subq->discS		= itob(sec);
	subq->discF		= itob(frm);
	return 0;
}

/////////////////////////////////////////////////////////
// gettoc: ps2 style TOC
static int layer1start = -1;
EXPORT_GCC long CALLBACK CDVDgetTOC(void* toc)
{
	u32 type;
	u8* tocBuff = (u8*)toc;

	if(!bIsOpen)  CDVDopen("DVD");                             // not open? funny emu...

 if(!iCDROK) return -1;                                  // cd not ok?

  type = CDVDgetDiskType();

	if(	type == CDVD_TYPE_DVDV ||
		type == CDVD_TYPE_PS2DVD)
	{
        u32 lastaddr;

        // get dvd structure format
		// scsi command 0x43
		memset(tocBuff, 0, 2048);

        lastaddr = GetLastTrack1Addr();
        if(layer1start > 0 || (layer1start != -2 && lastaddr > 0x280000) ) {
            int off = 0;
            FRAMEBUF* f = (FRAMEBUF*)malloc(sizeof(FRAMEBUF));

            f->dwBufLen = iUsedBlockSize;
            f->dwFrameCnt = 1;


            // dual sided
            tocBuff[ 0] = 0x24;
		    tocBuff[ 1] = 0x02;
		    tocBuff[ 2] = 0xF2;
		    tocBuff[ 3] = 0x00;
		    tocBuff[ 4] = 0x41;
		    tocBuff[ 5] = 0x95;

            tocBuff[14] = 0x60; // dual sided, ptp

		    tocBuff[16] = 0x00;
		    tocBuff[17] = 0x03;
		    tocBuff[18] = 0x00;
		    tocBuff[19] = 0x00;

            if( layer1start == -1 ) {
                // search for it
                printf("PeopsCDVD: searching for layer1... ");
                for(layer1start = (lastaddr/2-0x10)&~0xf; layer1start < 0x200010; layer1start += 16) {
                    f->dwFrame = layer1start;
                    if( pReadFunc(TRUE,f) != SS_COMP ) {
                        layer1start = 0x200010;
                        break;
                    }
                    // CD001
                    if( f->BufData[off+1] == 0x43 && f->BufData[off+2] == 0x44 && f->BufData[off+3] == 0x30 && f->BufData[off+4] == 0x30 && f->BufData[off+5] == 0x31 ) {
                        break;
                    }
                }

                if( layer1start >= 0x200010 ) {
                    printf("Couldn't find second layer on dual layer... ignoring\n");
                    // fake it
		            tocBuff[ 0] = 0x04;
		            tocBuff[ 1] = 0x02;
		            tocBuff[ 2] = 0xF2;
		            tocBuff[ 3] = 0x00;
		            tocBuff[ 4] = 0x86;
		            tocBuff[ 5] = 0x72;

		            tocBuff[16] = 0x00;
		            tocBuff[17] = 0x03;
		            tocBuff[18] = 0x00;
		            tocBuff[19] = 0x00;
                    layer1start = -2;
                    return 0;
                }

                printf("found at 0x%8.8x\n", layer1start);
                layer1start = layer1start+0x30000-1;
            }

            tocBuff[20] = layer1start>>24;
		    tocBuff[21] = (layer1start>>16)&0xff;
		    tocBuff[22] = (layer1start>>8)&0xff;
		    tocBuff[23] = (layer1start>>0)&0xff;

            free(f);
        }
        else {
		    // fake it
		    tocBuff[ 0] = 0x04;
		    tocBuff[ 1] = 0x02;
		    tocBuff[ 2] = 0xF2;
		    tocBuff[ 3] = 0x00;
		    tocBuff[ 4] = 0x86;
		    tocBuff[ 5] = 0x72;

		    tocBuff[16] = 0x00;
		    tocBuff[17] = 0x03;
		    tocBuff[18] = 0x00;
		    tocBuff[19] = 0x00;
        }
	}
	else if(type == CDVD_TYPE_CDDA ||
			type == CDVD_TYPE_PS2CDDA ||
			type == CDVD_TYPE_PS2CD ||
			type == CDVD_TYPE_PSCDDA ||
			type == CDVD_TYPE_PSCD)
	{
		// cd toc
		// (could be replaced by 1 command that reads the full toc)
		u8 min, sec, frm,i;
		s32 err;
		cdvdTN diskInfo;
		cdvdTD trackInfo;
		memset(tocBuff, 0, 1024);
		if (CDVDgetTN(&diskInfo) == -1)	{ diskInfo.etrack = 0;diskInfo.strack = 1; }
		if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0;

		tocBuff[0] = 0x41;
		tocBuff[1] = 0x00;

		//Number of FirstTrack
		tocBuff[2] = 0xA0;
		tocBuff[7] = itob(diskInfo.strack);

		//Number of LastTrack
		tocBuff[12] = 0xA1;
		tocBuff[17] = itob(diskInfo.etrack);

		//DiskLength
		lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
		tocBuff[22] = 0xA2;
		tocBuff[27] = itob(min);
		tocBuff[28] = itob(sec);
		tocBuff[29] = itob(frm);

		fprintf(stderr,"Track 0: %d mins %d secs %d frames\n",min,sec,frm);

		for (i=diskInfo.strack; i<=diskInfo.etrack; i++)
		{
			err = CDVDgetTD(i, &trackInfo);
			lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
			tocBuff[i*10+30] = trackInfo.type;
			tocBuff[i*10+32] = err == -1 ? 0 : itob(i);	  //number
			tocBuff[i*10+37] = itob(min);
			tocBuff[i*10+38] = itob(sec);
			tocBuff[i*10+39] = itob(frm);
			fprintf(stderr,"Track %d: %d mins %d secs %d frames\n",i,min,sec,frm);
		}
	}
	else
		return -1;

	return 0;
}

/////////////////////////////////////////////////////////
// gettn: first/last track num

EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer)
{
 if(!bIsOpen)  CDVDopen("DVD");                             // not open? funny emu...

 if(!iCDROK)                                           // cd not ok?
  {
   Buffer->strack=1;
   Buffer->etrack=1;
   return -1;
  }

 ReadTOC();                                            // read the TOC

 Buffer->strack=sTOC.cFirstTrack;                      // get the infos
 Buffer->etrack=sTOC.cLastTrack;

 return 0;
}

/////////////////////////////////////////////////////////
// gettd: track addr

EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer)
{
 unsigned long lu,i;
 unsigned char buffer[2352];
 unsigned char *buf;
 u8 t1;

 if(!bIsOpen) CDVDopen("DVD");                              // not open? funny emu...

 if(!iCDROK)  return -1;                               // cd not ok? bye

 ReadTOC();                                            // read toc

/*
// PSEmu style:
 if(track==0)                                          // 0 = last track
  {
   lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr);
   addr2time(lu,buffer);
  }
 else                                                  // others: track n
  {
   lu=reOrder(sTOC.tracks[track-1].lAddr);
   addr2time(lu,buffer);
  }

 Buffer->minute = buffer[1];
 Buffer->second = buffer[2];
 Buffer->frame  = buffer[3];
 Buffer->type   = iCDType;
#ifdef DBGOUT
 auxprintf("Read Toc %d: %u\n",track,lu);
#endif
*/

 lu=0;
 if(track==0)
	lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr);
 else
	lu=reOrder(sTOC.tracks[track].lAddr);
 //addr2time(lu,buffer);

 Buffer->lsn=lu;

 if(track==0)
      Buffer->type   = iCDType;
 else
 {
	lu=0;
	for(i=sTOC.cFirstTrack;i<track;i++)
		lu+=sTOC.tracks[i].lAddr;

		CDVDreadTrack(lu+16,CDVD_MODE_2352);
		buf=CDVDgetBuffer();

		if(buf!=NULL) memcpy(buffer,buf,2352);
		else		  memset(buffer,0,2352);

		if( (buffer[16]==01)
		&&(buffer[17]=='C')
		&&(buffer[18]=='D')
		)
			t1   = CDVD_MODE1_TRACK;
		else if( (buffer[24]==01)
			&&(buffer[25]=='C')
			&&(buffer[26]=='D')
			)
			t1   = CDVD_MODE2_TRACK;
		else t1   = CDVD_AUDIO_TRACK;

		Buffer->type=t1;
 }

 return 0;
}

/////////////////////////////////////////////////////////
// readtrack: start reading at given address

EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode)
{
 if(!bIsOpen)   CDVDopen("DVD");                            // usual checks
 if(!iCDROK)    return -1;
 if(bCDDAPlay)  bCDDAPlay=FALSE;

#ifdef DBGOUT
 auxprintf("Read Track %u: %d\n",lsn,mode);
#endif

 lLastAccessedAddr=lsn;                                // store read track values (for getbuffer)
 iLastAccessedMode=mode;

 if(!pReadTrackFunc(lLastAccessedAddr))                // start reading
  return -1;

 return 0;
}

/////////////////////////////////////////////////////////
// getbuffer: will be called after readtrack, to get ptr
//            to data

// small helper buffer to get bigger block sizes
unsigned char cDataAndSub[2368];

EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer()
{
 unsigned char * pbuffer;

 if(!bIsOpen) CDVDopen("DVD");

 if(pGetPtrFunc) pGetPtrFunc();                        // get ptr on thread modes

 pbuffer=pCurrReadBuf;                                 // init buffer pointer
	if (fdump != NULL) {
		isoWriteBlock(fdump, pbuffer, lLastAccessedAddr);
	}

 if(iLastAccessedMode!=iUsedMode)
  {
   switch(iLastAccessedMode)                           // what does the emu want?
    {//------------------------------------------------//
     case CDVD_MODE_2048:
      {
       if(iUsedBlockSize==2352) pbuffer+=24;
      }break;
     //------------------------------------------------//
     case CDVD_MODE_2352:
      {
       if(iUsedBlockSize==2048)
        {
         memset(cDataAndSub,0,2368);
         memcpy(cDataAndSub+24,pbuffer,2048);
         pbuffer=cDataAndSub;
        }
      }break;
     //------------------------------------------------//
     case CDVD_MODE_2340:
      {
       if(iUsedBlockSize==2048)
        {
         memset(cDataAndSub,0,2368);
         memcpy(cDataAndSub+12,pbuffer,2048);
         pbuffer=cDataAndSub;
        }
       else pbuffer+=12;
      }break;
     //------------------------------------------------//
     case CDVD_MODE_2328:
      {
       if(iUsedBlockSize==2048)
        {
         memset(cDataAndSub,0,2368);
         memcpy(cDataAndSub+0,pbuffer,2048);
         pbuffer=cDataAndSub;
        }
       else pbuffer+=24;
      }break;
     //------------------------------------------------//
     case CDVD_MODE_2368:
      {
       if(iUsedBlockSize==2048)
        {
         memset(cDataAndSub,0,2368);
         memcpy(cDataAndSub+24,pbuffer,2048);
         pbuffer=cDataAndSub;

/*
// NO SUBCHANNEL SUPPORT RIGHT NOW!!!
    {
     if(subHead)                                           // some sub file?
      CheckSUBCache(lLastAccessedAddr);                    // -> get cached subs
     else
     if(iUseSubReading!=1 && pCurrSubBuf)                  // no direct cd sub read?
      FakeSubData(lLastAccessedAddr);                      // -> fake the data
     memcpy(cDataAndSub,pCurrReadBuf,2352);
     if(pCurrSubBuf)
      memcpy(cDataAndSub+2352,pCurrSubBuf+12,16);
     pbuffer=cDataAndSub;
    }
*/

        }
      }break;
     //------------------------------------------------//
    }
  }

#ifdef DBGOUT
 auxprintf("get buf %d\n",iLastAccessedMode);

/*
{
 int k;
 for(k=0;k<2352;k++)
  auxprintf("%02x ",*(pbuffer+k));
 auxprintf("\n\n");
}
*/
#endif

 return pbuffer;
}

/////////////////////////////////////////////////////////

EXPORT_GCC long CALLBACK CDVDgetDiskType()
{
 return iCDType;
}

/////////////////////////////////////////////////////////
// CDVDgetTrayStatus

EXPORT_GCC long CALLBACK CDVDgetTrayStatus()
{
 static time_t to=0;
 static long lLastTrayState=CDVD_TRAY_CLOSE;

 if(to==time(NULL)) return lLastTrayState;               // we only check once per second
 to = time(NULL);

 lLastTrayState=CDVD_TRAY_CLOSE;                         // init state with "closed"

 if(iCheckTrayStatus)                                    // user really want a tray check
  {
   int iStatus;

   LockGenCDAccess();                                    // make sure that no more reading is happening
   iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU);          // get device status
   UnlockGenCDAccess();

   if(iStatus==SS_ERR)
    lLastTrayState=CDVD_TRAY_OPEN;
  }

#ifdef DBGOUT
auxprintf("check %d -> %d\n",to,lLastTrayState);
#endif


 return lLastTrayState;
}

EXPORT_GCC s32  CALLBACK CDVDctrlTrayOpen() {
	return 0;
}

EXPORT_GCC s32  CALLBACK CDVDctrlTrayClose() {
	return 0;
}



/////////////////////////////////////////////////////////
// configure: shows config window

EXPORT_GCC void CALLBACK CDVDconfigure()
{
 if(iCDROK)                                            // mmm... someone has already called Open? bad
  {MessageBeep((UINT)-1);return;}

 CreateGenEvent();                                     // we need an event handle

 DialogBox(hInst,MAKEINTRESOURCE(IDD_CONFIG),          // call dialog
           GetActiveWindow(),(DLGPROC)CDRDlgProc);

 FreeGenEvent();                                       // free event handle
}

/////////////////////////////////////////////////////////
// about: shows about window

EXPORT_GCC void CALLBACK CDVDabout()
{
 DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT),
           GetActiveWindow(),(DLGPROC)AboutDlgProc);
}

/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////

/*
// CURRENTLY UNUSED OLD STUFF FROM PSX CD PLUGIN:

/////////////////////////////////////////////////////////
// audioplay: PLAYSECTOR is NOT BCD coded !!!

EXPORT_GCC long CALLBACK CDRplay(unsigned char * sector)
{
 if(!bIsOpen)   CDVDopen();
 if(!iCDROK)    return PSE_ERR_FATAL;

 if(!DoCDDAPlay(time2addr(sector)))                    // start playing
  return PSE_CDR_ERR_NOREAD;

 bCDDAPlay=TRUE;                                       // raise flag: we are playing

 return PSE_CDR_ERR_SUCCESS;
}

/////////////////////////////////////////////////////////
// audiostop: stops cdda playing

EXPORT_GCC long CALLBACK CDRstop(void)
{
 if(!bCDDAPlay) return PSE_ERR_FATAL;

 DoCDDAPlay(0);                                        // stop cdda

 bCDDAPlay=FALSE;                                      // reset flag: no more playing

 return PSE_CDR_ERR_SUCCESS;
}

/////////////////////////////////////////////////////////
// getdriveletter

EXPORT_GCC char CALLBACK CDRgetDriveLetter(void)
{
 if(!iCDROK) return 0;                                 // not open? no way to get the letter

 if(iInterfaceMode==2 || iInterfaceMode==3)            // w2k/xp: easy
  {
   return MapIOCTLDriveLetter(iCD_AD,iCD_TA,iCD_LU);
  }
 else                                                  // but with aspi???
  {                                                    // -> no idea yet (maybe registry read...pfff)
  }

 return 0;
}

/////////////////////////////////////////////////////////
// getstatus: pcsx func... poorly supported here
//            problem is: func will be called often, which
//            would block all of my cdr reading if I would use
//            lotsa scsi commands

struct CdrStat
{
 unsigned long Type;
 unsigned long Status;
 unsigned char Time[3]; // current playing time
};

struct CdrStat ostat;

// reads cdr status
// type:
// 0x00 - unknown
// 0x01 - data
// 0x02 - audio
// 0xff - no cdrom
// status:
// 0x00 - unknown
// 0x02 - error
// 0x08 - seek error
// 0x10 - shell open
// 0x20 - reading
// 0x40 - seeking
// 0x80 - playing
// time:
// byte 0 - minute
// byte 1 - second
// byte 2 - frame


EXPORT_GCC long CALLBACK CDRgetStatus(struct CdrStat *stat)
{
 int iStatus;
 static time_t to;

 if(!bCDDAPlay)  // if not playing update stat only once in a second
  {
   if(to<time(NULL))
    {
     to = time(NULL);
    }
   else
    {
     memcpy(stat, &ostat, sizeof(struct CdrStat));
     return 0;
    }
  }

 memset(stat, 0, sizeof(struct CdrStat));

 if(!iCDROK) return -1;                                // not opened? bye

 if(bCDDAPlay)                                         // cdda is playing?
  {
   unsigned char * pB=GetCDDAPlayPosition();           // -> get pos
   stat->Type = 0x02;                                  // -> audio
   if(pB)
    {
     stat->Status|=0x80;                               // --> playing flag
     stat->Time[0]=pB[18];                             // --> and curr play time
     stat->Time[1]=pB[19];
     stat->Time[2]=pB[20];
    }
  }
 else                                                  // cdda not playing?
  {
   stat->Type = 0x01;                                  // -> data
  }

 LockGenCDAccess();                                    // make sure that no more reading is happening
 iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU);          // get device status
 UnlockGenCDAccess();

 if(iStatus==SS_ERR)
  {                                                    // no cdrom?
   stat->Type = 0xff;
   stat->Status|= 0x10;
  }

 memcpy(&ostat, stat, sizeof(struct CdrStat));

 return 0;
}

/////////////////////////////////////////////////////////
*/