mirror of
https://github.com/libretro/pcsx2.git
synced 2024-11-25 02:09:52 +00:00
384 lines
11 KiB
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;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|