mirror of https://github.com/PCSX2/pcsx2.git
604 lines
12 KiB
C++
604 lines
12 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2014 David Quintana [gigaherz]
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "CDVD.h"
|
|
#include "resource.h"
|
|
#include "Shlwapi.h"
|
|
|
|
#include "svnrev.h"
|
|
|
|
#include <assert.h>
|
|
|
|
void (*newDiscCB)();
|
|
|
|
HANDLE hThread_keepAlive = INVALID_HANDLE_VALUE;
|
|
HANDLE hNotify_keepAlive = INVALID_HANDLE_VALUE;
|
|
DWORD pidThreadKeepAlive = 0;
|
|
|
|
#define STRFY(x) #x
|
|
#define TOSTR(x) STRFY(x)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// State Information //
|
|
|
|
int strack;
|
|
int etrack;
|
|
track tracks[100];
|
|
|
|
int curDiskType;
|
|
int curTrayStatus;
|
|
|
|
int csector;
|
|
int cmode;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Plugin Interface //
|
|
|
|
char *LibName = "cdvdGigaherz "
|
|
#ifdef PCSX2_DEBUG
|
|
" Debug "
|
|
#endif
|
|
"(" TOSTR(SVN_REV)
|
|
#if SVN_MODS
|
|
"/modded"
|
|
#endif
|
|
")";
|
|
|
|
const unsigned char version = PS2E_CDVD_VERSION;
|
|
const unsigned char revision = 0;
|
|
const unsigned char build = 9;
|
|
|
|
HINSTANCE hinst;
|
|
|
|
BOOL WINAPI DllMain(
|
|
HINSTANCE hinstDLL, // handle to DLL module
|
|
DWORD fdwReason, // reason for calling function
|
|
LPVOID lpvReserved // reserved
|
|
)
|
|
{
|
|
if(fdwReason==DLL_PROCESS_ATTACH) {
|
|
hinst=hinstDLL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
char* CALLBACK PS2EgetLibName() {
|
|
return LibName;
|
|
}
|
|
|
|
u32 CALLBACK PS2EgetLibType() {
|
|
return PS2E_LT_CDVD;
|
|
}
|
|
|
|
u32 CALLBACK PS2EgetLibVersion2(u32 type) {
|
|
return (version << 16) | (revision << 8) | build;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Utility Functions //
|
|
|
|
void SysMessage(char *fmt, ...) {
|
|
va_list list;
|
|
char tmp[512];
|
|
|
|
va_start(list,fmt);
|
|
vsprintf(tmp,fmt,list);
|
|
va_end(list);
|
|
MessageBox(0, tmp, "cdvdGigaherz Msg", 0);
|
|
}
|
|
|
|
u8 __inline dec_to_bcd(u8 dec)
|
|
{
|
|
return ((dec/10)<<4)|(dec%10);
|
|
}
|
|
|
|
void __inline lsn_to_msf(u8* minute, u8* second, u8* frame, u32 lsn)
|
|
{
|
|
*frame = dec_to_bcd(lsn%75);
|
|
lsn/=75;
|
|
*second= dec_to_bcd(lsn%60);
|
|
lsn/=60;
|
|
*minute= dec_to_bcd(lsn%100);
|
|
}
|
|
|
|
void __inline 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);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CDVD processing functions //
|
|
|
|
char csrc[20];
|
|
|
|
bool cdvd_is_open = false;
|
|
bool cdvdKeepAlive_is_open = false;
|
|
bool disc_has_changed = false;
|
|
bool weAreInNewDiskCB = false;
|
|
|
|
Source *src;
|
|
|
|
char bfr[2352];
|
|
char throwaway[2352];
|
|
extern s32 prefetch_last_lba;
|
|
extern s32 prefetch_last_mode;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// keepAliveThread throws a read event regularly to prevent drive spin down //
|
|
|
|
DWORD CALLBACK keepAliveThread(PVOID param)
|
|
{
|
|
printf(" * CDVD: KeepAlive thread started...\n");
|
|
|
|
while (cdvdKeepAlive_is_open)
|
|
{
|
|
// Sleep 30 seconds with thread abort check
|
|
if (WaitForSingleObject(hNotify_keepAlive, 30000) != WAIT_TIMEOUT) break;
|
|
if (!cdvdKeepAlive_is_open) {
|
|
break;
|
|
}
|
|
|
|
//printf(" * keepAliveThread: polling drive.\n");
|
|
//if (prefetch_last_mode == CDVD_MODE_2048)
|
|
src->ReadSectors2048(prefetch_last_lba, 1, throwaway);
|
|
//else
|
|
// src->ReadSectors2352(prefetch_last_lba, 1, throwaway);
|
|
}
|
|
|
|
printf(" * CDVD: KeepAlive thread finished.\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 StartKeepAliveThread()
|
|
{
|
|
hNotify_keepAlive = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (hNotify_keepAlive == INVALID_HANDLE_VALUE)
|
|
return -1;
|
|
|
|
cdvdKeepAlive_is_open = true;
|
|
hThread_keepAlive = CreateThread(NULL, 0, keepAliveThread, NULL, 0, &pidThreadKeepAlive);
|
|
if (hThread_keepAlive == INVALID_HANDLE_VALUE) {
|
|
cdvdKeepAlive_is_open = false;
|
|
return -1;
|
|
}
|
|
|
|
SetThreadPriority(hThread_keepAlive, THREAD_PRIORITY_NORMAL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void StopKeepAliveThread()
|
|
{
|
|
cdvdKeepAlive_is_open = false;
|
|
PulseEvent(hNotify_keepAlive);
|
|
if (WaitForSingleObject(hThread_keepAlive, 5000) == WAIT_TIMEOUT)
|
|
{
|
|
TerminateThread(hThread_keepAlive, 0);
|
|
}
|
|
CloseHandle(hThread_keepAlive);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CDVD Pluin Interface //
|
|
|
|
void CALLBACK CDVDsetSettingsDir(const char* dir)
|
|
{
|
|
CfgSetSettingsDir(dir);
|
|
}
|
|
|
|
s32 CALLBACK CDVDinit()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
s32 CALLBACK CDVDopen(const char* pTitleFilename)
|
|
{
|
|
ReadSettings();
|
|
|
|
if(source_drive=='-')
|
|
{
|
|
// MSDN : Trailing backslash is required to ensure consistent behavior across
|
|
// various versions of Windows and storage types.
|
|
char temp[]="A:\\";
|
|
|
|
for(char d='A';d<='Z';d++)
|
|
{
|
|
temp[0]=d;
|
|
if(GetDriveType(temp)==DRIVE_CDROM)
|
|
{
|
|
source_drive=d;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(source_drive=='@')
|
|
{
|
|
curDiskType=CDVD_TYPE_NODISC;
|
|
return 0;
|
|
}
|
|
|
|
if(source_drive=='$')
|
|
{
|
|
printf(" * CDVD: Opening image '%s'...\n",source_file);
|
|
|
|
//open device file
|
|
src= TryLoaders(source_file);
|
|
}
|
|
else
|
|
{
|
|
sprintf(csrc,"\\\\.\\%c:",source_drive);
|
|
|
|
printf(" * CDVD: Opening drive '%s'...\n",csrc);
|
|
|
|
//open device file
|
|
src=new IOCtlSrc(csrc);
|
|
}
|
|
|
|
if(!src->IsOK())
|
|
{
|
|
printf(" * CDVD: Error opening source.\n");
|
|
return -1;
|
|
}
|
|
|
|
//setup threading manager
|
|
cdvdStartThread();
|
|
StartKeepAliveThread();
|
|
|
|
return cdvdRefreshData();
|
|
}
|
|
|
|
void CALLBACK CDVDclose()
|
|
{
|
|
StopKeepAliveThread();
|
|
cdvdStopThread();
|
|
//close device
|
|
delete src;
|
|
src=NULL;
|
|
}
|
|
|
|
void CALLBACK CDVDshutdown()
|
|
{
|
|
//nothing to do here
|
|
}
|
|
|
|
s32 CALLBACK CDVDgetDualInfo(s32* dualType, u32* _layer1start)
|
|
{
|
|
switch(src->GetMediaType())
|
|
{
|
|
case 1:
|
|
*dualType = 1;
|
|
*_layer1start = src->GetLayerBreakAddress() + 1;
|
|
return 0;
|
|
case 2:
|
|
*dualType = 2;
|
|
*_layer1start = src->GetLayerBreakAddress() + 1;
|
|
return 0;
|
|
case 0:
|
|
*dualType = 0;
|
|
*_layer1start = 0;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int lastReadInNewDiskCB=0;
|
|
char directReadSectorBuffer[2448];
|
|
|
|
s32 CALLBACK CDVDreadSector(u8* buffer, s32 lsn, int mode)
|
|
{
|
|
return cdvdDirectReadSector(lsn,mode,(char*)buffer);
|
|
}
|
|
|
|
s32 CALLBACK CDVDreadTrack(u32 lsn, int mode)
|
|
{
|
|
csector=lsn;
|
|
cmode=mode;
|
|
|
|
if(weAreInNewDiskCB)
|
|
{
|
|
int ret = cdvdDirectReadSector(lsn,mode,directReadSectorBuffer);
|
|
if(ret==0) lastReadInNewDiskCB=1;
|
|
return ret;
|
|
}
|
|
|
|
if(lsn>tracks[0].length) // track 0 is total disc.
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return cdvdRequestSector(lsn,mode);
|
|
}
|
|
|
|
// return can be NULL (for async modes)
|
|
u8* CALLBACK CDVDgetBuffer()
|
|
{
|
|
if(lastReadInNewDiskCB)
|
|
{
|
|
lastReadInNewDiskCB=0;
|
|
return (u8*)directReadSectorBuffer;
|
|
}
|
|
|
|
u8 *s = (u8*)cdvdGetSector(csector,cmode);
|
|
|
|
return s;
|
|
}
|
|
|
|
// return can be NULL (for async modes)
|
|
int CALLBACK CDVDgetBuffer2(u8* dest)
|
|
{
|
|
int csize = 2352;
|
|
switch(cmode)
|
|
{
|
|
case CDVD_MODE_2048: csize = 2048; break;
|
|
case CDVD_MODE_2328: csize = 2328; break;
|
|
case CDVD_MODE_2340: csize = 2340; break;
|
|
}
|
|
|
|
if(lastReadInNewDiskCB)
|
|
{
|
|
lastReadInNewDiskCB=0;
|
|
|
|
memcpy(dest, directReadSectorBuffer, csize);
|
|
return 0;
|
|
}
|
|
|
|
memcpy(dest, cdvdGetSector(csector,cmode), csize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq)
|
|
{
|
|
int i;
|
|
// the formatted subq command returns: control/adr, track, index, trk min, trk sec, trk frm, 0x00, abs min, abs sec, abs frm
|
|
|
|
if(lsn>tracks[0].length) // track 0 is total disc.
|
|
return -1;
|
|
|
|
memset(subq,0,sizeof(cdvdSubQ));
|
|
|
|
lsn_to_msf(&subq->discM,&subq->discS,&subq->discF,lsn+150);
|
|
|
|
i=strack;
|
|
while(i<=etrack)
|
|
{
|
|
if(lsn<=tracks[i].length)
|
|
break;
|
|
lsn-=tracks[i].length;
|
|
i++;
|
|
}
|
|
|
|
if(i>etrack)
|
|
i=etrack;
|
|
|
|
lsn_to_msf(&subq->trackM,&subq->trackS,&subq->trackF,lsn);
|
|
|
|
subq->mode=1;
|
|
subq->ctrl=tracks[i].type;
|
|
subq->trackNum=i;
|
|
subq->trackIndex=1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 CALLBACK CDVDgetTN(cdvdTN *Buffer)
|
|
{
|
|
Buffer->strack=strack;
|
|
Buffer->etrack=etrack;
|
|
return 0;
|
|
}
|
|
|
|
s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer)
|
|
{
|
|
if(Track==0)
|
|
{
|
|
Buffer->lsn = tracks[0].length;
|
|
Buffer->type= 0;
|
|
return 0;
|
|
}
|
|
|
|
if(Track<strack) return -1;
|
|
if(Track>etrack) return -1;
|
|
|
|
Buffer->lsn = tracks[Track].start_lba;
|
|
Buffer->type= tracks[Track].type;
|
|
return 0;
|
|
}
|
|
|
|
s32 CALLBACK CDVDgetTOC(u8* tocBuff)
|
|
{
|
|
//return src->ReadTOC((char*)toc,2048);
|
|
//that didn't work too well...
|
|
|
|
if (curDiskType == CDVD_TYPE_NODISC)
|
|
return -1;
|
|
|
|
if (curDiskType == CDVD_TYPE_DETCTDVDS || curDiskType == CDVD_TYPE_DETCTDVDD)
|
|
{
|
|
memset(tocBuff, 0, 2048);
|
|
|
|
s32 mt=src->GetMediaType();
|
|
|
|
if(mt<0)
|
|
return -1;
|
|
|
|
if(mt==0) //single layer
|
|
{
|
|
// fake it
|
|
tocBuff[ 0] = 0x04;
|
|
tocBuff[ 1] = 0x02;
|
|
tocBuff[ 2] = 0xF2;
|
|
tocBuff[ 3] = 0x00;
|
|
tocBuff[ 4] = 0x86;
|
|
tocBuff[ 5] = 0x72;
|
|
|
|
tocBuff[16] = 0x00; // first sector for layer 0
|
|
tocBuff[17] = 0x03;
|
|
tocBuff[18] = 0x00;
|
|
tocBuff[19] = 0x00;
|
|
}
|
|
else if(mt==1) //PTP
|
|
{
|
|
u32 layer1start = src->GetLayerBreakAddress() + 0x30000;
|
|
|
|
// dual sided
|
|
tocBuff[ 0] = 0x24;
|
|
tocBuff[ 1] = 0x02;
|
|
tocBuff[ 2] = 0xF2;
|
|
tocBuff[ 3] = 0x00;
|
|
tocBuff[ 4] = 0x41;
|
|
tocBuff[ 5] = 0x95;
|
|
|
|
tocBuff[14] = 0x61; // PTP
|
|
|
|
tocBuff[16] = 0x00;
|
|
tocBuff[17] = 0x03;
|
|
tocBuff[18] = 0x00;
|
|
tocBuff[19] = 0x00;
|
|
|
|
tocBuff[20] = (layer1start>>24);
|
|
tocBuff[21] = (layer1start>>16)&0xff;
|
|
tocBuff[22] = (layer1start>> 8)&0xff;
|
|
tocBuff[23] = (layer1start>> 0)&0xff;
|
|
}
|
|
else //OTP
|
|
{
|
|
u32 layer1start = src->GetLayerBreakAddress() + 0x30000;
|
|
|
|
// dual sided
|
|
tocBuff[ 0] = 0x24;
|
|
tocBuff[ 1] = 0x02;
|
|
tocBuff[ 2] = 0xF2;
|
|
tocBuff[ 3] = 0x00;
|
|
tocBuff[ 4] = 0x41;
|
|
tocBuff[ 5] = 0x95;
|
|
|
|
tocBuff[14] = 0x71; // OTP
|
|
|
|
tocBuff[16] = 0x00;
|
|
tocBuff[17] = 0x03;
|
|
tocBuff[18] = 0x00;
|
|
tocBuff[19] = 0x00;
|
|
|
|
tocBuff[24] = (layer1start>>24);
|
|
tocBuff[25] = (layer1start>>16)&0xff;
|
|
tocBuff[26] = (layer1start>> 8)&0xff;
|
|
tocBuff[27] = (layer1start>> 0)&0xff;
|
|
}
|
|
}
|
|
else if (curDiskType == CDVD_TYPE_DETCTCD)
|
|
{
|
|
// 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;
|
|
|
|
#define itob(n) ((((n)/10)<<4)+((n)%10))
|
|
|
|
//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;
|
|
}
|
|
|
|
s32 CALLBACK CDVDgetDiskType()
|
|
{
|
|
return curDiskType;
|
|
}
|
|
|
|
s32 CALLBACK CDVDgetTrayStatus()
|
|
{
|
|
return curTrayStatus;
|
|
}
|
|
|
|
s32 CALLBACK CDVDctrlTrayOpen()
|
|
{
|
|
curTrayStatus=CDVD_TRAY_OPEN;
|
|
return 0;
|
|
}
|
|
|
|
s32 CALLBACK CDVDctrlTrayClose()
|
|
{
|
|
curTrayStatus=CDVD_TRAY_CLOSE;
|
|
return 0;
|
|
}
|
|
|
|
void CALLBACK CDVDnewDiskCB(void (*callback)())
|
|
{
|
|
newDiscCB=callback;
|
|
}
|
|
|
|
void configure();
|
|
void CALLBACK CDVDconfigure()
|
|
{
|
|
configure();
|
|
}
|
|
|
|
void CALLBACK CDVDabout() {
|
|
SysMessage("%s %d.%d", LibName, revision, build);
|
|
}
|
|
|
|
s32 CALLBACK CDVDtest() {
|
|
return 0;
|
|
}
|