334 lines
6.9 KiB
C++
334 lines
6.9 KiB
C++
#include "common.h"
|
|
|
|
Disc* chd_parse(const char* file);
|
|
Disc* gdi_parse(const char* file);
|
|
Disc* cdi_parse(const char* file);
|
|
Disc* cue_parse(const char* file);
|
|
#ifdef _WIN32
|
|
Disc* ioctl_parse(const char* file);
|
|
#endif
|
|
|
|
u32 NullDriveDiscType;
|
|
Disc* disc;
|
|
|
|
Disc*(*drivers[])(const char* path)=
|
|
{
|
|
chd_parse,
|
|
gdi_parse,
|
|
cdi_parse,
|
|
cue_parse,
|
|
#ifdef _WIN32
|
|
ioctl_parse,
|
|
#endif
|
|
0
|
|
};
|
|
|
|
u8 q_subchannel[96];
|
|
|
|
static void PatchRegion_0(u8* sector, int size)
|
|
{
|
|
if (!settings.imgread.PatchRegion)
|
|
return;
|
|
|
|
u8* usersect=sector;
|
|
|
|
if (size!=2048)
|
|
{
|
|
INFO_LOG(GDROM, "PatchRegion_0 -> sector size %d , skipping patch", size);
|
|
}
|
|
|
|
//patch meta info
|
|
u8* p_area_symbol=&usersect[0x30];
|
|
memcpy(p_area_symbol,"JUE ",8);
|
|
}
|
|
|
|
static void PatchRegion_6(u8* sector, int size)
|
|
{
|
|
if (!settings.imgread.PatchRegion)
|
|
return;
|
|
|
|
u8* usersect=sector;
|
|
|
|
if (size!=2048)
|
|
{
|
|
INFO_LOG(GDROM, "PatchRegion_6 -> sector size %d , skipping patch", size);
|
|
}
|
|
|
|
//patch area symbols
|
|
u8* p_area_text=&usersect[0x700];
|
|
memcpy(&p_area_text[4],"For JAPAN,TAIWAN,PHILIPINES.",28);
|
|
memcpy(&p_area_text[4 + 32],"For USA and CANADA. ",28);
|
|
memcpy(&p_area_text[4 + 32 + 32],"For EUROPE. ",28);
|
|
}
|
|
bool ConvertSector(u8* in_buff , u8* out_buff , int from , int to,int sector)
|
|
{
|
|
//get subchannel data, if any
|
|
if (from == 2448)
|
|
{
|
|
memcpy(q_subchannel, in_buff + 2352, 96);
|
|
from -= 96;
|
|
}
|
|
//if no conversion
|
|
if (to == from)
|
|
{
|
|
memcpy(out_buff, in_buff, to);
|
|
return true;
|
|
}
|
|
switch (to)
|
|
{
|
|
case 2340:
|
|
verify(from == 2352);
|
|
memcpy(out_buff, &in_buff[12], 2340);
|
|
break;
|
|
case 2328:
|
|
verify(from == 2352);
|
|
memcpy(out_buff, &in_buff[24], 2328);
|
|
break;
|
|
case 2336:
|
|
verify(from == 2352);
|
|
memcpy(out_buff, &in_buff[0x10], 2336);
|
|
break;
|
|
case 2048:
|
|
verify(from == 2448 || from == 2352 || from == 2336);
|
|
if (from == 2352 || from == 2448)
|
|
{
|
|
if (in_buff[15] == 1)
|
|
memcpy(out_buff, &in_buff[0x10], 2048); //0x10 -> mode1
|
|
else
|
|
memcpy(out_buff, &in_buff[0x18], 2048); //0x18 -> mode2 (all forms ?)
|
|
}
|
|
else
|
|
memcpy(out_buff, &in_buff[0x8], 2048); //hmm only possible on mode2.Skip the mode2 header
|
|
break;
|
|
case 2352:
|
|
//if (from >= 2352)
|
|
memcpy(out_buff, &in_buff[0], 2352);
|
|
break;
|
|
default :
|
|
INFO_LOG(GDROM, "Sector conversion from %d to %d not supported \n", from , to);
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Disc* OpenDisc(const char* fn)
|
|
{
|
|
Disc* rv = NULL;
|
|
|
|
for (unat i=0; drivers[i] && !rv; i++) { // ;drivers[i] && !(rv=drivers[i](fn));
|
|
rv = drivers[i](fn);
|
|
|
|
if (rv && cdi_parse == drivers[i]) {
|
|
const char warn_str[] = "Warning: CDI Image Loaded! Many CDI images are known to be defective, GDI, CUE or CHD format is preferred. "
|
|
"Please only file bug reports when using images known to be good (GDI, CUE or CHD).";
|
|
WARN_LOG(GDROM, "%s", warn_str);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
bool InitDrive_(char* fn)
|
|
{
|
|
TermDrive();
|
|
|
|
//try all drivers
|
|
disc = OpenDisc(fn);
|
|
|
|
if (disc != NULL)
|
|
{
|
|
INFO_LOG(GDROM, "gdrom: Opened image \"%s\"", fn);
|
|
NullDriveDiscType = Busy;
|
|
}
|
|
else
|
|
{
|
|
INFO_LOG(GDROM, "gdrom: Failed to open image \"%s\"", fn);
|
|
NullDriveDiscType = NoDisk; //no disc :)
|
|
}
|
|
libCore_gdrom_disc_change();
|
|
|
|
return disc != NULL;
|
|
}
|
|
|
|
bool InitDrive()
|
|
{
|
|
bool rc = DiscSwap();
|
|
// not needed at startup and confuses some games
|
|
sns_asc = 0;
|
|
sns_ascq = 0;
|
|
sns_key = 0;
|
|
|
|
return rc;
|
|
}
|
|
|
|
void DiscOpenLid()
|
|
{
|
|
TermDrive();
|
|
NullDriveDiscType = Open;
|
|
gd_setdisc();
|
|
sns_asc = 0x29;
|
|
sns_ascq = 0x00;
|
|
sns_key = 0x6;
|
|
}
|
|
|
|
bool DiscSwap()
|
|
{
|
|
// These Additional Sense Codes mean "The lid was closed"
|
|
sns_asc = 0x28;
|
|
sns_ascq = 0x00;
|
|
sns_key = 0x6;
|
|
|
|
if (settings.imgread.ImagePath[0] == '\0')
|
|
{
|
|
NullDriveDiscType = NoDisk;
|
|
gd_setdisc();
|
|
return true;
|
|
}
|
|
|
|
if (InitDrive_(settings.imgread.ImagePath))
|
|
return true;
|
|
|
|
NullDriveDiscType = NoDisk;
|
|
gd_setdisc();
|
|
|
|
return false;
|
|
}
|
|
|
|
void TermDrive()
|
|
{
|
|
delete disc;
|
|
disc = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
//convert our nice toc struct to dc's native one :)
|
|
|
|
static u32 CreateTrackInfo(u32 ctrl, u32 addr, u32 fad)
|
|
{
|
|
u8 p[4];
|
|
p[0]=(ctrl<<4)|(addr<<0);
|
|
p[1]=fad>>16;
|
|
p[2]=fad>>8;
|
|
p[3]=fad>>0;
|
|
|
|
return *(u32*)p;
|
|
}
|
|
|
|
static u32 CreateTrackInfo_se(u32 ctrl, u32 addr, u32 tracknum)
|
|
{
|
|
u8 p[4];
|
|
p[0]=(ctrl<<4)|(addr<<0);
|
|
p[1]=tracknum;
|
|
p[2]=0;
|
|
p[3]=0;
|
|
return *(u32*)p;
|
|
}
|
|
|
|
|
|
void GetDriveSector(u8 * buff,u32 StartSector,u32 SectorCount,u32 secsz)
|
|
{
|
|
//printf("GD: read %08X, %d\n",StartSector,SectorCount);
|
|
if (disc)
|
|
{
|
|
disc->ReadSectors(StartSector,SectorCount,buff,secsz);
|
|
if (disc->type == GdRom && StartSector==45150 && SectorCount==7)
|
|
{
|
|
PatchRegion_0(buff,secsz);
|
|
PatchRegion_6(buff+2048*6,secsz);
|
|
}
|
|
}
|
|
}
|
|
void GetDriveToc(u32* to,DiskArea area)
|
|
{
|
|
if (!disc)
|
|
return;
|
|
memset(to, 0xFF, 102 * 4);
|
|
|
|
//can't get toc on the second area on discs that don't have it
|
|
verify(area != DoubleDensity || disc->type == GdRom);
|
|
|
|
//normal CDs: 1 .. tc
|
|
//GDROM: area0 is 1 .. 2, area1 is 3 ... tc
|
|
|
|
u32 first_track=1;
|
|
u32 last_track=disc->tracks.size();
|
|
if (area==DoubleDensity)
|
|
first_track=3;
|
|
else if (disc->type==GdRom)
|
|
last_track=2;
|
|
|
|
//Generate the TOC info
|
|
|
|
//-1 for 1..99 0 ..98
|
|
to[99]=CreateTrackInfo_se(disc->tracks[first_track-1].CTRL,disc->tracks[first_track-1].ADDR,first_track);
|
|
to[100]=CreateTrackInfo_se(disc->tracks[last_track-1].CTRL,disc->tracks[last_track-1].ADDR,last_track);
|
|
|
|
if (disc->type==GdRom)
|
|
{
|
|
//use smaller LEADOUT
|
|
if (area==SingleDensity)
|
|
to[101]=CreateTrackInfo(disc->LeadOut.CTRL,disc->LeadOut.ADDR,13085);
|
|
}
|
|
else
|
|
to[101] = CreateTrackInfo(disc->LeadOut.CTRL, disc->LeadOut.ADDR, disc->LeadOut.StartFAD);
|
|
|
|
for (u32 i=first_track-1;i<last_track;i++)
|
|
to[i]=CreateTrackInfo(disc->tracks[i].CTRL,disc->tracks[i].ADDR,disc->tracks[i].StartFAD);
|
|
}
|
|
|
|
void GetDriveSessionInfo(u8* to,u8 session)
|
|
{
|
|
if (!disc)
|
|
return;
|
|
to[0]=2;//status, will get overwritten anyway
|
|
to[1]=0;//0's
|
|
|
|
if (session==0)
|
|
{
|
|
to[2]=disc->sessions.size();//count of sessions
|
|
to[3]=disc->EndFAD>>16;//fad is sessions end
|
|
to[4]=disc->EndFAD>>8;
|
|
to[5]=disc->EndFAD>>0;
|
|
}
|
|
else
|
|
{
|
|
to[2]=disc->sessions[session-1].FirstTrack;//start track of this session
|
|
to[3]=disc->sessions[session-1].StartFAD>>16;//fad is session start
|
|
to[4]=disc->sessions[session-1].StartFAD>>8;
|
|
to[5]=disc->sessions[session-1].StartFAD>>0;
|
|
}
|
|
}
|
|
|
|
void printtoc(TocInfo* toc,SessionInfo* ses)
|
|
{
|
|
INFO_LOG(GDROM, "Sessions %d", ses->SessionCount);
|
|
for (u32 i=0;i<ses->SessionCount;i++)
|
|
{
|
|
INFO_LOG(GDROM, "Session %d: FAD %d,First Track %d", i + 1, ses->SessionFAD[i], ses->SessionStart[i]);
|
|
for (u32 t=toc->FistTrack-1;t<=toc->LastTrack;t++)
|
|
{
|
|
if (toc->tracks[t].Session==i+1)
|
|
{
|
|
INFO_LOG(GDROM, " Track %d : FAD %d CTRL %d ADR %d", t, toc->tracks[t].FAD, toc->tracks[t].Control, toc->tracks[t].Addr);
|
|
}
|
|
}
|
|
}
|
|
INFO_LOG(GDROM, "Session END: FAD END %d", ses->SessionsEndFAD);
|
|
}
|
|
|
|
DiscType GuessDiscType(bool m1, bool m2, bool da)
|
|
{
|
|
if ((m1==true) && (da==false) && (m2==false))
|
|
return CdRom;
|
|
else if (m2)
|
|
return CdRom_XA;
|
|
else if (da && m1)
|
|
return CdRom_Extra;
|
|
else
|
|
return CdRom;
|
|
}
|