pcsx2/plugins/CDVDpeops/Ioctrl.c

384 lines
11 KiB
C

/***************************************************************************
ioctrl.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:
//
// 2003/11/16 - Pete
// - generic cleanup for the Peops release
//
//*************************************************************************//
/////////////////////////////////////////////////////////
#include "stdafx.h"
#define _IN_IOCTL
#include "externals.h"
/////////////////////////////////////////////////////////
HANDLE hIOCTL=NULL; // global drive file handle
DWORD dwIOCTLAttr=0; // open attribute
OVERLAPPED ovcIOCTL; // global overlapped struct
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; // global read bufs
RAW_READ_INFO rawIOCTL;
/////////////////////////////////////////////////////////
// open drive
void OpenIOCTLHandle(int iA,int iT,int iL)
{
char cLetter;
if(hIOCTL) return;
cLetter=MapIOCTLDriveLetter(iA,iT,iL); // get drive
if(!cLetter) return;
hIOCTL=OpenIOCTLFile(cLetter, // open drive
(iUseCaching==2)?TRUE:FALSE); // (caching:2 -> overlapped)
}
/////////////////////////////////////////////////////////
// close drive
void CloseIOCTLHandle(void)
{
if(hIOCTL) CloseHandle(hIOCTL);
hIOCTL=NULL;
}
/////////////////////////////////////////////////////////
// get drive letter by a,t,l
char MapIOCTLDriveLetter(int iA,int iT,int iL)
{
char cLetter[4];int iDA,iDT,iDL;HANDLE hF;
strcpy(cLetter,"C:\\");
for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++)
{
if(GetDriveType(cLetter)==DRIVE_CDROM)
{
hF=OpenIOCTLFile(cLetter[0],FALSE);
GetIOCTLAdapter(hF,&iDA,&iDT,&iDL);
CloseHandle(hF);
if(iA==iDA && iT==iDT && iL==iDL)
return cLetter[0];
}
}
return 0;
}
/////////////////////////////////////////////////////////
// get cd drive list, using ioctl, not aspi
int GetIOCTLCDDrives(char * pDList)
{
char cLetter[4];int iDA,iDT,iDL;HANDLE hF;
int iCnt=0;char * p=pDList;
strcpy(cLetter,"C:\\");
for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++)
{
if(GetDriveType(cLetter)==DRIVE_CDROM)
{
hF=OpenIOCTLFile(cLetter[0],FALSE);
GetIOCTLAdapter(hF,&iDA,&iDT,&iDL);
CloseHandle(hF);
if(iDA!=-1 && iDT!=-1 && iDL!=-1)
{
wsprintf(p,"[%d:%d:%d] Drive %c:",
iDA,iDT,iDL,cLetter[0]);
p+=strlen(p)+1;
iCnt++;
}
}
}
return iCnt;
}
/////////////////////////////////////////////////////////
// open drive in sync/async mode
HANDLE OpenIOCTLFile(char cLetter,BOOL bAsync)
{
HANDLE hF;char szFName[16];
OSVERSIONINFO ov;DWORD dwFlags;
if(bAsync) dwIOCTLAttr=FILE_FLAG_OVERLAPPED;
else dwIOCTLAttr=0;
memset(&ov,0,sizeof(OSVERSIONINFO));
ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(&ov);
if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) &&
(ov.dwMajorVersion>4))
dwFlags = GENERIC_READ|GENERIC_WRITE; // add gen write on W2k/XP
else dwFlags = GENERIC_READ;
wsprintf(szFName, "\\\\.\\%c:",cLetter);
hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // open drive
NULL,OPEN_EXISTING,dwIOCTLAttr,NULL);
if(hF==INVALID_HANDLE_VALUE) // mmm... no success?
{
dwFlags^=GENERIC_WRITE; // -> try write toggle
hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // -> open drive again
NULL,OPEN_EXISTING,dwIOCTLAttr,NULL);
if(hF==INVALID_HANDLE_VALUE) return NULL;
}
return hF;
}
/////////////////////////////////////////////////////////
// get a,t,l
void GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL)
{
char szBuf[1024];PSCSI_ADDRESS pSA;DWORD dwRet;
*iDA=*iDT=*iDL=-1;
if(hF==NULL) return;
memset(szBuf,0,1024);
pSA=(PSCSI_ADDRESS)szBuf;
pSA->Length=sizeof(SCSI_ADDRESS);
if(!DeviceIoControl(hF,IOCTL_SCSI_GET_ADDRESS,NULL,
0,pSA,sizeof(SCSI_ADDRESS),
&dwRet,NULL))
return;
*iDA = pSA->PortNumber;
*iDT = pSA->TargetId;
*iDL = pSA->Lun;
}
/////////////////////////////////////////////////////////
// we fake the aspi call in ioctl scsi mode
DWORD IOCTLSendASPI32Command(LPSRB pSRB)
{
LPSRB_ExecSCSICmd pSC;DWORD dwRet;BOOL bStat;
if(!pSRB) return SS_ERR;
if(hIOCTL==NULL ||
pSRB->SRB_Cmd!=SC_EXEC_SCSI_CMD) // we only fake exec aspi scsi commands
{
pSRB->SRB_Status=SS_ERR;
return SS_ERR;
}
pSC=(LPSRB_ExecSCSICmd)pSRB;
memset(&sptIOCTL,0,sizeof(sptIOCTL));
sptIOCTL.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
sptIOCTL.spt.CdbLength = pSC->SRB_CDBLen;
sptIOCTL.spt.DataTransferLength = pSC->SRB_BufLen;
sptIOCTL.spt.TimeOutValue = 60;
sptIOCTL.spt.DataBuffer = pSC->SRB_BufPointer;
sptIOCTL.spt.SenseInfoLength = 14;
sptIOCTL.spt.TargetId = pSC->SRB_Target;
sptIOCTL.spt.Lun = pSC->SRB_Lun;
sptIOCTL.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
if(pSC->SRB_Flags&SRB_DIR_IN) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_IN;
else if(pSC->SRB_Flags&SRB_DIR_OUT) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_OUT;
else sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
memcpy(sptIOCTL.spt.Cdb,pSC->CDBByte,pSC->SRB_CDBLen);
if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async?
{
ovcIOCTL.Internal=0;
ovcIOCTL.InternalHigh=0;
ovcIOCTL.Offset=0;
ovcIOCTL.OffsetHigh=0;
ovcIOCTL.hEvent=hEvent;
bStat = DeviceIoControl(hIOCTL,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
&sptIOCTL,
sizeof(sptIOCTL),
&sptIOCTL,
sizeof(sptIOCTL),
&dwRet,
&ovcIOCTL);
}
else // sync?
{
bStat = DeviceIoControl(hIOCTL,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
&sptIOCTL,
sizeof(sptIOCTL),
&sptIOCTL,
sizeof(sptIOCTL),
&dwRet,
NULL);
}
if(!bStat) // some err?
{
DWORD dwErrCode;
dwErrCode=GetLastError();
if(dwErrCode==ERROR_IO_PENDING) // -> pending?
{
pSC->SRB_Status=SS_COMP; // --> ok
return SS_PENDING;
}
pSC->SRB_Status=SS_ERR; // -> else error
return SS_ERR;
}
pSC->SRB_Status=SS_COMP;
return SS_COMP;
}
/////////////////////////////////////////////////////////
// special raw mode... works on TEAC532S, for example
DWORD ReadIOCTL_Raw(BOOL bWait,FRAMEBUF * f)
{
DWORD dwRet;BOOL bStat;
if(hIOCTL==NULL) return SS_ERR;
rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048; // 2048 is needed here
rawIOCTL.SectorCount = f->dwFrameCnt;
rawIOCTL.TrackMode = XAForm2;//CDDA;//YellowMode2;//XAForm2;
if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async?
{
ovcIOCTL.Internal=0;
ovcIOCTL.InternalHigh=0;
ovcIOCTL.Offset=0;
ovcIOCTL.OffsetHigh=0;
ovcIOCTL.hEvent=hEvent;
ResetEvent(hEvent);
bStat = DeviceIoControl(hIOCTL,
IOCTL_CDROM_RAW_READ,
&rawIOCTL,sizeof(RAW_READ_INFO),
&(f->BufData[0]),f->dwBufLen,//2048,
&dwRet, &ovcIOCTL);
}
else // sync?
{
bStat = DeviceIoControl(hIOCTL,
IOCTL_CDROM_RAW_READ,
&rawIOCTL,sizeof(RAW_READ_INFO),
&(f->BufData[0]),f->dwBufLen,//2048,
&dwRet,NULL);
}
if(!bStat)
{
DWORD dwErrCode;
dwErrCode=GetLastError();
#ifdef DBGOUT
auxprintf("errorcode %d\n", dwErrCode);
#endif
if(dwErrCode==ERROR_IO_PENDING)
{
// we do a wait here, not later... no real async mode anyway
// bDoWaiting=TRUE;
WaitGenEvent(0xFFFFFFFF);
}
else
{
sx.SRB_Status=SS_ERR;
return SS_ERR;
}
}
sx.SRB_Status=SS_COMP;
return SS_COMP;
}
/////////////////////////////////////////////////////////
// special raw + special sub... dunno if this really
// works on any drive (teac is working, but giving unprecise
// subdata)
DWORD ReadIOCTL_Raw_Sub(BOOL bWait,FRAMEBUF * f)
{
DWORD dwRet;BOOL bStat;
SUB_Q_CHANNEL_DATA qd;unsigned char * p;
CDROM_SUB_Q_DATA_FORMAT qf;
if(hIOCTL==NULL) return SS_ERR;
rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048;
rawIOCTL.SectorCount = f->dwFrameCnt;
rawIOCTL.TrackMode = XAForm2;
bStat = DeviceIoControl(hIOCTL,
IOCTL_CDROM_RAW_READ,
&rawIOCTL,sizeof(RAW_READ_INFO),
&(f->BufData[0]),f->dwBufLen,
&dwRet,NULL);
if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;}
qf.Format=IOCTL_CDROM_CURRENT_POSITION;
qf.Track=1;
bStat = DeviceIoControl(hIOCTL,
IOCTL_CDROM_READ_Q_CHANNEL,
&qf,sizeof(CDROM_SUB_Q_DATA_FORMAT),
&qd,sizeof(SUB_Q_CHANNEL_DATA),
&dwRet,NULL);
p=(unsigned char*)&qd;
SubCData[12]=(p[5]<<4)|(p[5]>>4);
SubCData[13]=p[6];
SubCData[14]=p[7];
SubCData[15]=p[13];
SubCData[16]=p[14];
SubCData[17]=p[15];
SubCData[18]=0;
SubCData[19]=p[9];
SubCData[20]=p[10];
SubCData[21]=p[11];
SubCData[15]=itob(SubCData[15]);
SubCData[16]=itob(SubCData[16]);
SubCData[17]=itob(SubCData[17]);
SubCData[19]=itob(SubCData[19]);
SubCData[20]=itob(SubCData[20]);
SubCData[21]=itob(SubCData[21]);
if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;}
sx.SRB_Status=SS_COMP;
return SS_COMP;
}
/////////////////////////////////////////////////////////