pcsx2/plugins/cdvd/CDVDdraft/Src/cdvddraft.cpp

600 lines
19 KiB
C++

// cdvddraft.cpp : Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include "cdvddraft.h"
#include "ps2etypes.h"
#include "ps2edefs.h"
#include "cdvdmisc.h"
#include "config.h"
#include "resource.h"
#include "aboutbox.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*************************************************************************/
/* ps2emu cdvddraft history */
/*************************************************************************/
/* */
/* v0.62 Initial release */
/* v0.63 Changed CDVDgetTD for new specs */
/* */
/*************************************************************************/
/*************************************************************************/
/* ps2emu library MFC application placeholder */
/*************************************************************************/
class CCdvdDraft : public CWinApp
{
public:
CCdvdDraft();
};
CCdvdDraft::CCdvdDraft(){}
CCdvdDraft theApp;
/*************************************************************************/
/* ps2emu library versions */
/*************************************************************************/
static char *libraryName = "PCXS2 (C/DVD) Draft Driver";
const unsigned char version = PS2E_CDVD_VERSION;
const unsigned char revision = 0;
const unsigned char build = 64;
/*************************************************************************/
/* global variables start here */
/*************************************************************************/
static BOOL g_library_opened = FALSE; // open flag
static BOOL g_library_initialized = FALSE; // init flag
static int g_current_drvtype = CDVD_DRIVETYPE_CD; // drive type (cd/dvd/cdvd)
static int g_current_medtype = CDVD_MEDIATYPE_CD; // media type (cd/dvd)
static UI08 *g_current_buff = NULL; // current buffer pointer
static int g_current_buffnum = -1; // current buffer number
static TOCDATA g_current_tocdata = {0}; // current tocdata;
static DECODEDTRACKINFO g_current_trkinfo = {0}; // current trkdata;
static int g_request_offset = 0; // offset from base of buffer
CDVD_BUFFER_MODE g_current_buffmode = CDVD_BUFFER_SYNC; // current buffer mode (sync/async)
CDVD_INTERFACE_TYPE g_current_intftype = CDVD_INTF_ASPI; // interface type (aspi/ioctl)
CDVD_READ_MODE g_current_readmode = CDVD_READ_MMC; // current read mode (mmc/scsi10)
int g_current_drivenum = -1; // currently opened drive number
int g_status [CDVD_NUM_BUFFERS]; // status of read to buffer-n, (srb status, for asynchronous)
HANDLE g_handle [CDVD_NUM_BUFFERS]; // handle used to read to buffer-n, (for asynchronous)
int g_sectstart[CDVD_NUM_BUFFERS]; // start of sector read to buffer-n
BOOL g_filled [CDVD_NUM_BUFFERS]; // check if buffer-n was filled
#define CHECKLIBRARYOPENED() if(g_library_opened == FALSE) return CDVD_ERROR_FAIL;
#define SECT2MSF(sect,m,s,f){ (f) =(UI08)(sect%75);(s) =(UI08)(((sect - (f))/75)%60);(m) = (UI08)((((sect - (f))/75)-(s))/60); }
/*************************************************************************/
/* ps2emu library identifier functions */
/*************************************************************************/
unsigned int CALLBACK PS2EgetLibType()
{
return PS2E_LT_CDVD;
}
char *CALLBACK PS2EgetLibName()
{
return libraryName;
}
unsigned int CALLBACK PS2EgetLibVersion2(unsigned int type)
{
return (version<<16)|(revision<<8)|build;
}
/*************************************************************************/
/* ps2emu config/test functions */
/*************************************************************************/
// empty for now
void CALLBACK CDVDconfigure()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CConfig config;
config.DoModal();
//::MessageBox(NULL, _T("No Configuration.\n\n"), _T("Config"), MB_OK);
}
// empty for now
void CALLBACK CDVDabout()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CAboutBox about;
about.DoModal();
}
// return bogus for now
int CALLBACK CDVDtest()
{
return CDVD_ERROR_SUCCESS;
}
/*************************************************************************/
/* ps2emu library c/dvd functions */
/*************************************************************************/
// init, normally called once, setup for aspi for now?
int CALLBACK CDVDinit()
{
if(g_library_initialized)
return CDVD_ERROR_SUCCESS;
for(int i=0; i<CDVD_NUM_BUFFERS; i++)
g_handle[i] = NULL;
g_library_initialized = TRUE;
return CDVD_ERROR_SUCCESS;
}
// shutdown, normally called once?
void CALLBACK CDVDshutdown()
{
if(g_library_initialized)
{
cdvd_shutdown();
g_library_initialized = FALSE;
}
}
// open, called everytime emulation starts?
int CALLBACK CDVDopen()
{
//if(g_library_initialized == FALSE)
// return CDVD_ERROR_FAIL;
// instead, lets do the Init for lazy emus.
if(g_library_initialized == FALSE)
if(CDVDinit() != CDVD_ERROR_SUCCESS)
return CDVD_ERROR_FAIL;
// already opened
if(g_library_opened)
return CDVD_ERROR_SUCCESS;
//-----------------------------------------
// LOAD REGISTRY SETTINGS HERE!
if(load_registrysettings()
== CDVD_ERROR_SUCCESS)
{
TRACE("CDVDopen: registry loaded successfully.\n");
// override registry set values for now
// ioctl doesnt exist yet and although
// async seems to work fine, havent tested thoroughly
//g_current_buffmode = CDVD_BUFFER_ASYNC;
// set interface type
TRACE("CDVDopen: registry read_mode: %ld\n", g_current_buffmode);
g_current_intftype = CDVD_INTF_ASPI;
}
else // set some bs values
{
TRACE("CDVDopen: unable to load registry\n");
g_current_drivenum = 0;
// set to sync
g_current_buffmode = CDVD_BUFFER_SYNC;
// set interface type
g_current_intftype = CDVD_INTF_ASPI;
}
//-----------------------------------------
if(cdvd_init(g_current_intftype)
!= CDVD_ERROR_SUCCESS)
return CDVD_ERROR_FAIL;
int num_drives = cdvd_getnumdrives();
if(num_drives == 0)
return CDVD_ERROR_FAIL;
if(cdvd_opendrive(g_current_drivenum)
!= CDVD_ERROR_SUCCESS)
return CDVD_ERROR_FAIL;
if(g_current_readmode == CDVD_READ_UNKNOWN)
{
// wait for media ready
cdvd_testready();
TRACE("CDVDopen: autodetecting read-mode.\n");
if((g_current_readmode = (CDVD_READ_MODE) cdvd_detectandsetreadmode())
== CDVD_ERROR_FAIL)
{
// try setting to mmc again
if(cdvd_setreadmode(CDVD_READ_MMC, CDVD_MMC_DATAMODE_RAW)
!= CDVD_ERROR_SUCCESS)
return CDVD_ERROR_FAIL;
else
g_current_readmode = CDVD_READ_MMC;
}
}
else
{
TRACE("CDVDopen: setting read-mode: %ld\n", g_current_readmode);
int mediatype = cdvd_getmediatype();
int mmc_mode = (mediatype == CDVD_MEDIATYPE_DVD) ? CDVD_MMC_DATAMODE_USER : CDVD_MMC_DATAMODE_RAW;
if(cdvd_setreadmode(g_current_readmode, mmc_mode)
== CDVD_ERROR_FAIL)
{
return CDVD_ERROR_FAIL;
}
}
g_current_drvtype = cdvd_getdrivetype();
g_current_medtype = cdvd_getmediatype();
init_buffersandflags();
// set to first buffer
g_current_buffnum = 0;
cdvd_setcurrentbuffer(0);
g_library_opened = TRUE;
return CDVD_ERROR_SUCCESS;
}
// close, called everytime emulation stops?
void CALLBACK CDVDclose()
{
cdvd_closedrive();
shut_buffersandflags();
g_library_opened = FALSE;
}
// readtrack, called during emulation
// it's a mess right now.
int CALLBACK CDVDreadTrack(unsigned int lsn, int mode)
{
CHECKLIBRARYOPENED();
int max_loop = (g_current_buffmode == CDVD_BUFFER_ASYNC) ? CDVD_NUM_BUFFERS : 1;
int rq_sector = lsn;
BOOL rq_isinbuff = FALSE;
//------------------------------------------
// return a clean buffer when no media present in tray
// for psemupro compatibility only, since i dont
// use the pemupro return code definitions :p
if(g_current_medtype == CDVD_MEDIATYPE_UNKNOWN)
{
// lets see if user inserted/initialized a disc afterwards
if((g_current_medtype = cdvd_getmediatype())
== CDVD_MEDIATYPE_UNKNOWN)
{
g_current_buff = cdvd_getbufferaddress(0);;
g_request_offset = 0;
memset(g_current_buff, 0, CDVD_SECTOR_SIZE_CD);
return CDVD_ERROR_SUCCESS;
}
else
{
cdvd_testready();
if((g_current_readmode = (CDVD_READ_MODE) cdvd_detectandsetreadmode())
== CDVD_ERROR_FAIL)
return CDVD_ERROR_FAIL;
}
}
//------------------------------------------
for(;;)
{
rq_isinbuff = FALSE;
g_current_buffnum = -1;
for(int i=0; i < max_loop; i++)
{
if(rq_sector >= g_sectstart[i] &&
rq_sector < (g_sectstart[i] + CDVD_NUM_SECTORS_PER_BUFF)
&& g_sectstart[i] != -1)
{
rq_isinbuff = TRUE;
g_current_buffnum = i;
break;
}
}
if(rq_isinbuff == TRUE)
{
// bufffilled? else
if(g_filled[g_current_buffnum] == FALSE)
{
int ret = WaitForSingleObject(g_handle[g_current_buffnum], INFINITE); // ->> check error here!
if(g_status[g_current_buffnum] == CDVD_ERROR_FAIL ||
cdvd_getsrbstatus(g_current_buffnum) != CDVD_SRB_COMPLETED) // there was an error
{
TRACE("CDVDreadTrack: error srb not completed1 stat: %ld, srb: %ld\n", g_status[g_current_buffnum],
cdvd_getsrbstatus(g_current_buffnum));
TRACE("CDVDreadTrack: waitret: %ld, extended: %ld\n", ret, GetLastError());
//-----------------------------------------
// one last try, we might get lucky :p
cdvd_setcurrentbuffer(g_current_buffnum);
g_status[g_current_buffnum] = cdvd_readsector(rq_sector, NULL);
if(g_status[g_current_buffnum] != CDVD_ERROR_SUCCESS)
return CDVD_ERROR_FAIL;
else
return CDVD_ERROR_SUCCESS;
//-----------------------------------------
//return CDVD_ERROR_FAIL;
}
g_filled[g_current_buffnum] = TRUE;
}
int sect_in_buff = rq_sector - g_sectstart[g_current_buffnum];
// okay, just send another async read (prefetch)
// ONLY supports 2 buffers
if(g_current_buffmode == CDVD_BUFFER_ASYNC)
{
int altbuff = !g_current_buffnum;
if(g_sectstart[g_current_buffnum] > g_sectstart[altbuff])
{
TRACE("CDVDreadTrack: sending prefetch.\n");
WaitForSingleObject(g_handle[altbuff], INFINITE);
g_sectstart[altbuff] = g_sectstart[g_current_buffnum] + CDVD_NUM_SECTORS_PER_BUFF;
cdvd_setcurrentbuffer(altbuff);
_ASSERTE(g_handle[altbuff] != NULL);
g_status[altbuff] = cdvd_readsector(g_sectstart[altbuff], &g_handle[altbuff]);
g_filled[altbuff] = FALSE;
}
}
g_current_buff = cdvd_getbufferaddress(g_current_buffnum);
static const UI32 mode_pad[] = {0, 12, 24, 24};
if(g_current_medtype == CDVD_MEDIATYPE_DVD)
{
g_request_offset = sect_in_buff * CDVD_SECTOR_SIZE_DVD;
}
else
{
g_request_offset = (sect_in_buff * CDVD_SECTOR_SIZE_CD) + mode_pad[mode];
}
return CDVD_ERROR_SUCCESS;
}
else
{
for(int i=0; i < max_loop; i++)
{
// wait for any previous srb's pending
if(g_filled[i] == FALSE &&
cdvd_getsrbstatus(i) == CDVD_SRB_PENDING)
WaitForSingleObject(g_handle[i], INFINITE);
g_sectstart[i] = rq_sector + (CDVD_NUM_SECTORS_PER_BUFF * i);
cdvd_setcurrentbuffer(i);
_ASSERTE(g_handle[i] != NULL);
g_status[i] = cdvd_readsector(g_sectstart[i], &g_handle[i]);
if(g_current_buffmode == CDVD_BUFFER_SYNC)
{
WaitForSingleObject(g_handle[i], INFINITE);
if(g_status[g_current_buffnum] == CDVD_ERROR_FAIL ||
cdvd_getsrbstatus(i) != CDVD_SRB_COMPLETED)
{
TRACE("CDVDreadTrack: error srb not completed1 stat: %ld, srb: %ld\n", g_status[i],
cdvd_getsrbstatus(i));
return CDVD_ERROR_FAIL;
}
g_filled[i] = TRUE;
}
else
{
g_filled[i] = FALSE;
}
}
}
}
return CDVD_ERROR_SUCCESS;
}
// getbuffer, retrieve previously read sector buffer
unsigned char *CALLBACK CDVDgetBuffer()
{
return (g_current_buff + g_request_offset);
}
s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) {
// fake it
u8 min, sec, frm;
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;
}
// retrieve track number
int CALLBACK CDVDgetTN(cdvdTN *buffer)
{
CHECKLIBRARYOPENED();
if(cdvd_gettoc() != CDVD_ERROR_SUCCESS)
return CDVD_ERROR_FAIL;
g_current_tocdata = cdvd_gettocdata();
if(g_current_tocdata.first_track_num == 0 ||
g_current_tocdata.last_track_num == 0)
{
//fail? then lie ;P
buffer->strack = 1;
buffer->etrack = 1;
return CDVD_ERROR_SUCCESS; // TODO: or fail???
}
buffer->strack = g_current_tocdata.first_track_num;
buffer->etrack = g_current_tocdata.last_track_num;
//printf("s: %ld, e: %ld\n", buffer->strack, buffer->etrack);
return CDVD_ERROR_SUCCESS;
}
// retrives total sects OR offset of track
int CALLBACK CDVDgetTD(unsigned char track, cdvdTD *buffer)
{
CHECKLIBRARYOPENED();
if(track == 0)
{
buffer->lsn = cdvd_getnumsectors();
buffer->type = 0x00; // well, dunno if its even needed here.
return CDVD_ERROR_SUCCESS;
}
if(track > 0xAA) // max tracks per session
return CDVD_ERROR_FAIL;
if(cdvd_gettoc() != CDVD_ERROR_SUCCESS)
return CDVD_ERROR_FAIL;
g_current_trkinfo = cdvd_gettrackdetail();
// okay, not sure if you need to add a 0:2:0 lead-in for cds?
buffer->lsn = g_current_trkinfo.track_offset[track-1];
switch(g_current_medtype)
{
case CDVD_MEDIATYPE_DVD:
buffer->type = CDVD_MODE1_TRACK; // always data track
break;
case CDVD_MEDIATYPE_CD:
switch(g_current_trkinfo.track_type[track-1])
{
case 0x01: buffer->type = CDVD_MODE1_TRACK; break;
case 0x02: buffer->type = CDVD_MODE2_TRACK; break;
default: buffer->type = CDVD_AUDIO_TRACK; break; // for 0x00 and everything else
}
break;
default:
buffer->type = CDVD_AUDIO_TRACK; // lets lie.
break;
}
return CDVD_ERROR_SUCCESS; //g_current_trkinfo.track_offset[track-1];
}
s32 CALLBACK CDVDgetTOC(void* toc) {
u8 type = CDVDgetDiskType();
u8* tocBuff = (u8*)toc;
if( type == CDVD_TYPE_DVDV ||
type == CDVD_TYPE_PS2DVD)
{
// get dvd structure format
// scsi command 0x43
memset(tocBuff, 0, 2048);
// 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;
s32 i, 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);
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);
}
}
else
return -1;
return 0;
}
// return bogus data for now
int CALLBACK CDVDgetDiskType()
{
CHECKLIBRARYOPENED();
int mediatype = cdvd_getmediatype();
// TODO: need to retrieve dvd subtype here
if(mediatype == CDVD_MEDIATYPE_DVD)
return CDVD_TYPE_PS2DVD;
// TODO: need to retrieve cd subtype here
if(mediatype == CDVD_MEDIATYPE_CD)
return CDVD_TYPE_PS2CD;
return CDVD_TYPE_UNKNOWN;
}
// return bogus data for now
int CALLBACK CDVDgetTrayStatus()
{
CHECKLIBRARYOPENED();
return CDVD_TRAY_CLOSE;
}
s32 CALLBACK CDVDctrlTrayOpen() {
return 0;
}
s32 CALLBACK CDVDctrlTrayClose() {
return 0;
}