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

617 lines
16 KiB
C++

// Cdvd.cpp: implementation of the CCdvd class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Cdvd.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#if defined(CDVD_SIMPLE_INTERFACE)
// our fuckup method of interfacing ;p
CCdvd OBJECT_HOLDER_CDVD;
CDVD_INTF_FUNC_T1 FUNCTION_GETNUMSECTORS;
CDVD_INTF_FUNC_T1 FUNCTION_GETTOC;
CDVD_INTF_FUNC_T1 FUNCTION_TESTREADY;
CDVD_INTF_FUNC_T2 FUNCTION_SETSPEED;
CDVD_INTF_FUNC_T1 FUNCTION_STOP;
CDVD_INTF_FUNC_T2 FUNCTION_SETSECTORSIZE;
CDVD_INTF_FUNC_T3 FUNCTION_PLAY;
CDVD_INTF_FUNC_T4 FUNCTION_READSECTOR;
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CCdvd::CCdvd()
{
m_hIoctlDrv = NULL;
m_hAspi = NULL;
m_bAspiInitialized = FALSE;
m_bIoctlInitialized = FALSE;
m_bDriveOpened = FALSE;
m_nCurrentDrive = -1;
m_nCurrentBuffer = 0;
m_nDrives = 0;
m_IntfType = CDVD_INTF_UNKNOWN;
m_nMmcDataMode = CDVD_MMC_DATAMODE_RAW;
m_nCurrentReadMode = CDVD_READ_MMC;
memset(m_drvDetails, 0, CDVD_MAX_SUPPORTED_DRIVES * sizeof(ADAPTERINFO));
memset(m_srbReadCd, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd));
memset(m_srbRead10, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd));
memset(m_srbReadMat, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd));
memset(m_srbReadSony, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd));
memset(m_srbReadNec, 0, CDVD_NUM_BUFFERS * sizeof(SRB_ExecSCSICmd));
memset(m_sptwbReadCd, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF));
memset(m_sptwbRead10, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF));
memset(m_sptwbReadMat, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF));
memset(m_sptwbReadSony, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF));
memset(m_sptwbReadNec, 0, CDVD_NUM_BUFFERS * sizeof(SPTD_WITH_SENSE_BUFF));
memset(&m_tocDetails, 0, sizeof(TOCDATA));
GetNumSectors = Dummy_T1;
GetToc = Dummy_T1;
Stop = Dummy_T1;
Play = Dummy_T3;
TestReady = Dummy_T1;
// GetHeader = Dummy_T1;
SetSpeed = Dummy_T2;
SetSectorSize = Dummy_T2;
ReadSector = Dummy_T4;
UpdateInterfaceObject();
}
CCdvd::~CCdvd()
{
CloseDrive();
Shutdown();
}
// based on msdn example
WIN32OSTYPE CCdvd::GetWin32OSType()
{
WIN32OSTYPE wintype;
UI32 version;
OSVERSIONINFO *osvi;
version = GetVersion();
if(version < 0x80000000)
{
osvi = (OSVERSIONINFO *) malloc(sizeof(OSVERSIONINFO));
if (osvi)
{
memset(osvi, 0, sizeof(OSVERSIONINFO));
osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(osvi);
if (osvi->dwMajorVersion >= 4L)
wintype = WINNTNEW;
else
wintype = WINNTOLD;
free(osvi);
}
}
else if (LOBYTE(LOWORD(version)) < 4L)
wintype = WIN32S;
else
wintype = WIN95;
return wintype;
}
// Initializes an interface, only one should be initialized. :)
int CCdvd::Init(CDVD_INTERFACE_TYPE intf_type)
{
int retval = CDVD_ERROR_SUCCESS;
switch(intf_type)
{
case CDVD_INTF_ASPI:
m_IntfType = CDVD_INTF_ASPI;
Aspi_Init();
break;
//case CDVD_INTF_IOCTL:
// m_IntfType = CDVD_INTF_IOCTL;
// Ioctl_Init();
// break;
case CDVD_INTF_UNKNOWN:
if(m_bAspiInitialized)
retval = CDVD_INTF_ASPI;
else
if(m_bIoctlInitialized) retval = CDVD_INTF_IOCTL;
else
retval = CDVD_INTF_UNKNOWN;
break;
default:
retval = CDVD_ERROR_FAIL;
break;
}
return retval;
}
// shutsdown previously opened interface
int CCdvd::Shutdown()
{
int retval = CDVD_ERROR_SUCCESS;
switch(m_IntfType)
{
case CDVD_INTF_ASPI:
Aspi_Shutdown();
break;
//case CDVD_INTF_IOCTL:
// Ioctl_Shutdown();
// break;
default: break;
}
m_IntfType = CDVD_INTF_UNKNOWN;
return retval;
}
// retrieve number of c/dvd drives
int CCdvd::GetNumDrives() const
{
return m_nDrives;
}
// open a drive for reading
int CCdvd::OpenDrive(int drv_num)
{
int retval = CDVD_ERROR_FAIL;
_ASSERT(drv_num < CDVD_MAX_SUPPORTED_DRIVES);
// run-time check, for now.
if(drv_num > (int) m_nDrives)
return CDVD_ERROR_FAIL;
m_bDriveOpened = FALSE;
switch(m_IntfType)
{
case CDVD_INTF_ASPI:
if(Aspi_OpenDrive(drv_num) == CDVD_ERROR_SUCCESS)
{
m_bDriveOpened = TRUE;
retval = CDVD_ERROR_SUCCESS;
}
break;
//case CDVD_INTF_IOCTL:
// if(Ioctl_OpenDrive(drv_num) == CDVD_ERROR_SUCCESS)
// {
// m_bDriveOpened = TRUE;
// retval = CDVD_ERROR_SUCCESS;
// }
default: break;
}
return retval;
}
// close a previously opened drive
int CCdvd::CloseDrive()
{
int retval = CDVD_ERROR_SUCCESS;
switch(m_IntfType)
{
case CDVD_INTF_ASPI: Aspi_CloseDrive(); break;
//case CDVD_INTF_IOCTL: Ioctl_CloseDrive(); break;
default: break;
}
return retval;
}
// allocate and initialize buffers for BOTH aspi and ioctl
int CCdvd::InitializeBuffers()
{
int retval = CDVD_ERROR_SUCCESS;
UI32 result = 0xFFFFFFFF;
for(int i=0; i < CDVD_NUM_BUFFERS; i++)
{
if(m_ReadBuffer[i].AB_BufPointer != NULL) continue;
m_ReadBuffer[i].AB_BufLen = CDVD_NUM_SECTORS_PER_BUFF * CDVD_SECTOR_SIZE_CD;
m_ReadBuffer[i].AB_BufPointer = (PBYTE) VirtualAlloc
(
NULL,
m_ReadBuffer[i].AB_BufLen,
MEM_COMMIT,
PAGE_READWRITE
);
result &= (UI32) m_ReadBuffer[i].AB_BufPointer;
if(m_ReadBuffer[i].AB_BufPointer != NULL)
memset(m_ReadBuffer[i].AB_BufPointer, 0, m_ReadBuffer[i].AB_BufLen);
}
if(result == 0)
{
ShutdownBuffers();
retval = CDVD_ERROR_FAIL;
TRACE("unable to allocate all buffers\n");
}
return retval;
}
// free-up previously allocated buffers
int CCdvd::ShutdownBuffers()
{
int retval = CDVD_ERROR_SUCCESS;
for(int i=0; i < CDVD_NUM_BUFFERS; i++)
{
if(m_ReadBuffer[i].AB_BufPointer != NULL)
VirtualFree( m_ReadBuffer[i].AB_BufPointer, 0, MEM_RELEASE );
m_ReadBuffer[i].AB_BufPointer = NULL;
m_ReadBuffer[i].AB_BufLen = 0;
}
return retval;
}
// set the current buffer to be used
// only 2! at the moment
int CCdvd::SetCurrentBuffer(int buf_num)
{
int retval = CDVD_ERROR_SUCCESS;
if(buf_num >= CDVD_NUM_BUFFERS)
return CDVD_ERROR_FAIL;
m_nCurrentBuffer = buf_num;
return retval;
}
// this is terribly WRONG :P, but i dont care, works most of the time :p
int CCdvd::ExtractTocData(UI08 *buffer)
{
int retval = CDVD_ERROR_SUCCESS;
LPTOCDATA pdata = (LPTOCDATA) buffer;
memcpy(&m_tocDetails, buffer, sizeof(TOCDATA));
int total_tracks = 0;
int mediatype = GetCdvdMediaType();
UI32 numRead = ((UI32) pdata->datalen_byte1) << 8 | (UI32) (pdata->datalen_byte0);
SetCurrentBuffer(0);
memset(&m_trkDetails, 0, sizeof(DECODEDTRACKINFO));
int offset = 4;
for(int i = 0; i < pdata->last_track_num; i++)
{
offset = i*8+4;
LPTOCTRACKDESCRIPTOR pdesc = (LPTOCTRACKDESCRIPTOR) (buffer + offset);
UI32 start_track = ((UI32) pdesc->lba_byte3) << 24 |
((UI32) pdesc->lba_byte2) << 16 |
((UI32) pdesc->lba_byte1) << 8 |
(UI32) pdesc->lba_byte0;
// track types, 0x00 - cdda, 0x01 - data, 0x02 - cdxa
UI08 tracktype = 0;
if(mediatype == CDVD_MEDIATYPE_DVD)
{
tracktype = 0x01; // data sector
}
else if(((this)->*(ReadSector))(start_track, NULL) == CDVD_ERROR_SUCCESS)
{
tracktype = (UI08) * (m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer+15);
}
else
{
// skip setting info for this track, and try to proceed with others
++total_tracks;
continue;
}
// okay, something is fucked.. just lie and say its a cdda :p
if(tracktype > 2) tracktype = 0;
m_trkDetails.track_offset[i] = start_track;
m_trkDetails.track_type[i] = tracktype;
TRACE("track %ld -> start_at: %ld with type: %ld\n", i, start_track, tracktype);
++total_tracks;
}
if(total_tracks) m_trkDetails.total_tracks = total_tracks;
return retval;
}
// set read mode (i.e. mmc, scsi10 etc).
// Note: only mmc and scsi10 is enabled
// i've disabled all goddamn proprietary read modes
// on this version (sony, nec, matsushita)
int CCdvd::SetReadMode(CDVD_READ_MODE read_mode, int data_mode)
{
_ASSERT(read_mode >= CDVD_READ_MMC && read_mode <= CDVD_READ_SCSI10);
m_nCurrentReadMode = read_mode;
m_nMmcDataMode = data_mode;
int retval = CDVD_ERROR_SUCCESS;
switch(m_IntfType)
{
case CDVD_INTF_ASPI:
retval = Aspi_SetReadMode(read_mode);
break;
//case CDVD_INTF_IOCTL:
// retval = Ioctl_SetReadMode();
// break;
default:
retval = CDVD_ERROR_FAIL;
break;
}
return CDVD_ERROR_SUCCESS;
}
// returns CDVD_ERROR_PENDING if SS_PENDING, CDVD_ERROR_SUCCESS if SS_COMP
// and CDVD_ERROR_FAIL if you are a dumbass and you haven't set any read_mode
int CCdvd::GetSrbStatus(int srb_num)
{
int retval = CDVD_ERROR_SUCCESS;
switch(m_IntfType)
{
case CDVD_INTF_ASPI:
retval = Aspi_GetSrbStatus(srb_num);
break;
//case CDVD_INTF_IOCTL:
// retval = Ioctl_GetSrbStatus(srb_num);
// break;
default:
retval = CDVD_ERROR_FAIL;
break;
}
return retval;
}
int CCdvd::GetCdvdConfiguration(UI16 feature, UI08 *dest, UI32 dest_size)
{
int retval = CDVD_ERROR_SUCCESS;
switch(m_IntfType)
{
case CDVD_INTF_ASPI:
retval = Aspi_GetConfiguration(feature, dest, dest_size);
break;
//case CDVD_INTF_IOCTL:
// retval = Ioctl_GetConfiguration(feature, dest, dest_size);
// break;
default:
retval = CDVD_ERROR_FAIL;
break;
}
return retval;
}
const UI16 CDVD_FEATURE_READCD = 0x001E;
const UI16 CDVD_FEATURE_READDVD = 0x001F;
// as the name says
int CCdvd::GetCdvdDriveType()
{
int drivetype = CDVD_DRIVETYPE_UNKNOWN;
UI08 buffer[1024];
UI16 feature_available = 0;
BOOL is_cdromdrive = FALSE;
BOOL is_dvddrive = FALSE;
if(GetCdvdConfiguration(CDVD_FEATURE_READCD, buffer, sizeof(buffer))
== CDVD_ERROR_SUCCESS)
{
feature_available = (UI16) buffer[8] << 8 | (UI16) buffer[9];
if(feature_available == CDVD_FEATURE_READCD)
{
is_cdromdrive = TRUE;
}
}
if(GetCdvdConfiguration(CDVD_FEATURE_READDVD, buffer, sizeof(buffer))
== CDVD_ERROR_SUCCESS)
{
feature_available = (UI16) buffer[8] << 8 | (UI16) buffer[9];
if(feature_available == CDVD_FEATURE_READDVD)
{
is_dvddrive = TRUE;
}
}
if(is_dvddrive && is_cdromdrive) drivetype = CDVD_DRIVETYPE_CDVD;
if(is_dvddrive && !is_cdromdrive) drivetype = CDVD_DRIVETYPE_DVD;
if(!is_dvddrive && is_cdromdrive) drivetype = CDVD_DRIVETYPE_CD;
return drivetype;
}
// as the naem says
int CCdvd::GetCdvdMediaType()
{
int mediatype = CDVD_MEDIATYPE_UNKNOWN;
UI08 buffer[1024];
UI08 media;
if(GetCdvdConfiguration(CDVD_FEATURE_READCD, buffer, sizeof(buffer))
== CDVD_ERROR_SUCCESS)
{
media = buffer[10] & 0x01; // current loaded media is a cdrom if "Current" bit is on
if(media)
{
return CDVD_MEDIATYPE_CD;
}
}
if(GetCdvdConfiguration(CDVD_FEATURE_READDVD, buffer, sizeof(buffer))
== CDVD_ERROR_SUCCESS)
{
media = buffer[10] & 0x01; // current loaded media is a dvd if "Current" bit is on
if(media)
{
return CDVD_MEDIATYPE_DVD;
}
}
return mediatype;
}
// automatically detect read_mode as well as set it.
int CCdvd::DetectAndSetReadMode()
{
#define CHECKMODE(m) memset(m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer, 0xCC, m_ReadBuffer[m_nCurrentBuffer].AB_BufLen); \
SetReadMode((m), m_nMmcDataMode);\
if(((this)->*(ReadSector))(0, NULL) == CDVD_ERROR_SUCCESS){\
if(*((UI32*) m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer) != 0xCCCCCCCC){\
TRACE("data: %08Xh, detected read mode: %ld\n", *((UI32*) m_ReadBuffer[m_nCurrentBuffer].AB_BufPointer), (m));\
return (m);\
}\
}
int retval = CDVD_ERROR_FAIL;
if(GetCdvdDriveType() != CDVD_DRIVETYPE_UNKNOWN)
{
int mediatype = GetCdvdMediaType();
if(mediatype != CDVD_MEDIATYPE_UNKNOWN) // no freaking media present dipshit
{
if(mediatype == CDVD_MEDIATYPE_DVD)
{
m_nMmcDataMode = CDVD_MMC_DATAMODE_USER;
}
else if(mediatype == CDVD_MEDIATYPE_CD)
{
m_nMmcDataMode = CDVD_MMC_DATAMODE_RAW;
}
// start checking which one will work;
SetCurrentBuffer(0);
// lets try scsi10 first, since scsi10/scsi12 is mandatory for dvd's
if(((this)->*(SetSectorSize))((m_nMmcDataMode == CDVD_MMC_DATAMODE_RAW) ?
CDVD_SECTOR_SIZE_CD : CDVD_SECTOR_SIZE_DVD) == CDVD_ERROR_SUCCESS)
{
CHECKMODE(CDVD_READ_SCSI10);
}
// then check for mmc
CHECKMODE(CDVD_READ_MMC);
// mmc doesnt work? lets try the others
TRACE("cdvdlib: failed to retrieve mode. \n");
// disabled all other read_modes for now.
//CHECKMODE(CDVD_READ_D8);
//CHECKMODE(CDVD_READ_D410);
//CHECKMODE(CDVD_READ_D412);
}
}
return retval;
}
// update the global interface for some magic
void CCdvd::UpdateInterfaceObject()
{
#if defined(CDVD_SIMPLE_INTERFACE)
FUNCTION_GETNUMSECTORS = GetNumSectors;
FUNCTION_GETTOC = GetToc;
FUNCTION_TESTREADY = TestReady;
FUNCTION_SETSPEED = SetSpeed;
FUNCTION_STOP = Stop;
FUNCTION_SETSECTORSIZE = SetSectorSize;
FUNCTION_PLAY = Play;
FUNCTION_READSECTOR = ReadSector;
#endif
}
TOCDATA CCdvd::GetTocData()
{
TOCDATA dummy;
if(m_nCurrentDrive == -1)
{
memset(&dummy, 0, sizeof(TOCDATA));
return dummy;
}
return m_tocDetails;
}
DECODEDTRACKINFO CCdvd::GetTrackDetail()
{
DECODEDTRACKINFO dummy;
if(m_nCurrentDrive == -1)
{
memset(&dummy, 0, sizeof(DECODEDTRACKINFO));
return dummy;
}
return m_trkDetails;
}
UI08 *CCdvd::GetBufferAddress(int buff_num) const
{
_ASSERT(buff_num < CDVD_NUM_BUFFERS);
return m_ReadBuffer[buff_num].AB_BufPointer;
}
ADAPTERINFO CCdvd::GetAdapterDetail(int drv_num)
{
_ASSERT(drv_num < CDVD_MAX_SUPPORTED_DRIVES);
ADAPTERINFO dummy;
if(m_nDrives == 0)
{
memset(&dummy, 0, sizeof(ADAPTERINFO));
return dummy;
}
return m_drvDetails[drv_num];
}
/***********************************************************/
/* DUMMY C/DVD Methods */
/***********************************************************/
int CCdvd::Dummy_T1()
{
TRACE("cdvdlib: dummy_t1\n");
return CDVD_ERROR_UNINITIALIZED;
}
int CCdvd::Dummy_T2(int a)
{
TRACE("cdvdlib: dummy_t2\n");
return CDVD_ERROR_UNINITIALIZED;
}
int CCdvd::Dummy_T3(int a, int b)
{
TRACE("cdvdlib: dummy_t3\n");
return CDVD_ERROR_UNINITIALIZED;
}
int CCdvd::Dummy_T4(int a, HANDLE *b)
{
TRACE("cdvdlib: dummy_t4\n");
return CDVD_ERROR_UNINITIALIZED;
}