From cfd4de316eadd1e4ee496af7d588dd9459bb2aad Mon Sep 17 00:00:00 2001 From: Ulf Wohlers Date: Thu, 6 Mar 2003 13:34:27 +0000 Subject: [PATCH] cdrom interfaces Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@717 --- src/dos/cdrom.cpp | 773 ++++++++++++++++++++++++++++++++++++++++ src/dos/cdrom.h | 179 ++++++++++ src/dos/cdrom_ioctl.cpp | 431 ++++++++++++++++++++++ 3 files changed, 1383 insertions(+) create mode 100644 src/dos/cdrom.cpp create mode 100644 src/dos/cdrom.h create mode 100644 src/dos/cdrom_ioctl.cpp diff --git a/src/dos/cdrom.cpp b/src/dos/cdrom.cpp new file mode 100644 index 00000000..6e1ba761 --- /dev/null +++ b/src/dos/cdrom.cpp @@ -0,0 +1,773 @@ +/* + * Copyright (C) 2002-2003 The DOSBox Team + * + * 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. + * + * This program 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +// ASPI support for WIN32 CDROM + +#ifdef WIN32 + +#include +#include "cdrom.h" +#include "scsidefs.h" // Aspi stuff + +#include "dosbox.h" + +CDROM_Interface_Aspi::CDROM_Interface_Aspi(void) +{ + hASPI = NULL; + hEvent = NULL; + pGetASPI32SupportInfo = NULL; + pSendASPI32Command = NULL; +}; + +CDROM_Interface_Aspi::~CDROM_Interface_Aspi(void) +{ + // Stop Audio + StopAudio(); + + pGetASPI32SupportInfo = NULL; // clear funcs + pSendASPI32Command = NULL; + + if (hASPI) { // free aspi + FreeLibrary(hASPI); + hASPI=NULL; + } +}; + +bool GetRegistryValue(HKEY& hKey,char* valueName, char* buffer, ULONG bufferSize) +// hKey has to be open +{ + // Read subkey + ULONG valType; + ULONG result; + result = RegQueryValueEx(hKey,valueName,NULL,&valType,(unsigned char*)&buffer[0],&bufferSize); + return (result == ERROR_SUCCESS); +}; + +BYTE CDROM_Interface_Aspi::GetHostAdapter(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE buffer[40]; + + for (int i=0; i<255; i++) { + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + memset(&s,0,sizeof(s)); + // Check Media test... + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = i; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_BufLen = 40; + s.SRB_BufPointer = (BYTE FAR*)buffer; + s.SRB_CDBLen = 14; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x4A; + s.CDBByte[1] = (lun<<5)|1; // lun & immediate + s.CDBByte[4] = 0x10; // media + s.CDBByte[8] = 40; + ResetEvent(hEvent); + dwStatus = pSendASPI32Command((LPSRB)&s); + if ((dwStatus==0) && (s.SRB_Status!=SS_INVALID_CMD)) { + DEBUG_ShowMsg(0,"SCSI: Host Adapter found: %d",i); + return i; + }; + }; + DEBUG_ShowMsg(0,"SCSI: Host Adapter not found."); + return 0; +}; + +bool CDROM_Interface_Aspi::ScanRegistryFindKey(HKEY& hKeyBase) +// hKey has to be open +{ + FILETIME time; + ULONG result,newKeyResult; + char subKey[256]; + char buffer[256]; + ULONG bufferSize = 256; + ULONG subKeySize = 256; + HKEY hNewKey; + + ULONG index = 0; + do { + result = RegEnumKeyEx (hKeyBase,index,&subKey[0],&subKeySize,NULL,NULL,0,&time); + if (result==ERROR_SUCCESS) { + // Open Key... + newKeyResult = RegOpenKeyEx (hKeyBase,subKey,0,KEY_READ,&hNewKey); + if (newKeyResult==ERROR_SUCCESS) { + if (GetRegistryValue(hNewKey,"CurrentDriveLetterAssignment",buffer,256)) { + DEBUG_ShowMsg(0,"SCSI: Drive Letter found: %s",buffer); + // aha, something suspicious... + if (buffer[0]==letter) { + // found it... lets see if we can get the scsi values + bool v1 = GetRegistryValue(hNewKey,"SCSILUN",buffer,256); + DEBUG_ShowMsg(0,"SCSI: SCSILUN found: %s",buffer); + lun = buffer[0]-'0'; + bool v2 = GetRegistryValue(hNewKey,"SCSITargetID",buffer,256); + DEBUG_ShowMsg(0,"SCSI: SCSITargetID found: %s",buffer); + target = buffer[0]-'0'; + RegCloseKey(hNewKey); + if (v1 && v2) { + haId = GetHostAdapter(); + return true; + }; + } + }; + }; + RegCloseKey(hNewKey); + }; + index++; + } while ((result==ERROR_SUCCESS) || (result==ERROR_MORE_DATA)); + return false; +}; + +bool CDROM_Interface_Aspi::ScanRegistry(HKEY& hKeyBase) +// hKey has to be open +{ + FILETIME time; + ULONG result,newKeyResult; + char subKey[256]; + ULONG subKeySize= 256; + HKEY hNewKey; + + ULONG index = 0; + do { + result = RegEnumKeyEx (hKeyBase,index,&subKey[0],&subKeySize,NULL,NULL,0,&time); + if ((result==ERROR_SUCCESS) || (result==ERROR_MORE_DATA)) { + // Open Key... + newKeyResult = RegOpenKeyEx (hKeyBase,subKey,0,KEY_READ,&hNewKey); + if (newKeyResult==ERROR_SUCCESS) { + bool found = ScanRegistryFindKey(hNewKey); + RegCloseKey(hNewKey); + if (found) return true; + }; + RegCloseKey(hNewKey); + }; + index++; + } while ((result==ERROR_SUCCESS) || (result==ERROR_MORE_DATA)); + return false; +}; + +bool CDROM_Interface_Aspi::SetDevice(char* path) +{ + // load WNASPI32.DLL + hASPI = LoadLibrary ( "WNASPI32.DLL" ); + if (!hASPI) return false; + // Get Pointer to ASPI funcs + pGetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress(hASPI,"GetASPI32SupportInfo"); + pSendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress(hASPI,"SendASPI32Command"); + if (!pGetASPI32SupportInfo || !pSendASPI32Command) return false; + // Letter + letter = toupper(path[0]); + + // Check OS + OSVERSIONINFO osi; + osi.dwOSVersionInfoSize = sizeof(osi); + GetVersionEx(&osi); + if ((osi.dwPlatformId==VER_PLATFORM_WIN32_NT) && (osi.dwMajorVersion>4)) { + if (GetDriveType(path)==DRIVE_CDROM) { + // WIN XP/NT/2000 + int iDA,iDT,iDL; + letter = path[0]; + HANDLE hF = OpenIOCTLFile(letter,FALSE); + GetIOCTLAdapter(hF,&iDA,&iDT,&iDL); + CloseHandle(hF); + // Set SCSI IDs + haId = iDA; + target = iDT; + lun = iDL; + return true; + } + } else { + // win 95/98/ME have to scan the registry... + // lets hope the layout is always the same... i dunno... + char key[2048]; + HKEY hKeyBase; + bool found = false; + strcpy(key,"ENUM\\SCSI"); + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,key,0,KEY_READ,&hKeyBase)==ERROR_SUCCESS) { + found = ScanRegistry(hKeyBase); + }; + RegCloseKey(hKeyBase); + return found; + } + return false; +}; + +bool CDROM_Interface_Aspi::GetAudioTracks(int& stTrack, int& endTrack, TMSF& leadOut) +{ + TOC toc; + if (GetTOC((LPTOC)&toc) == SS_COMP) { + stTrack = toc.cFirstTrack; + endTrack = toc.cLastTrack; + leadOut.min = (unsigned char)(toc.tracks[endTrack].lAddr >> 8) &0xFF; + leadOut.sec = (unsigned char)(toc.tracks[endTrack].lAddr >> 16) &0xFF; + leadOut.fr = (unsigned char)(toc.tracks[endTrack].lAddr >> 24) &0xFF; + return true; + } + return false; +}; + +bool CDROM_Interface_Aspi::GetAudioTrackInfo (int track, TMSF& start, unsigned char& attr) +{ + TOC toc; + if (GetTOC((LPTOC)&toc) == SS_COMP) { + start.min = (unsigned char)(toc.tracks[track-1].lAddr >> 8) &0xFF; + start.sec = (unsigned char)(toc.tracks[track-1].lAddr >> 16) &0xFF; + start.fr = (unsigned char)(toc.tracks[track-1].lAddr >> 24) &0xFF; + attr = toc.tracks[track-1].cAdrCtrl; + return true; + }; + return false; +}; + +HANDLE CDROM_Interface_Aspi::OpenIOCTLFile(char cLetter,BOOL bAsync) +{ + HANDLE hF; + char szFName[16]; + OSVERSIONINFO ov; + DWORD dwFlags; + DWORD dwIOCTLAttr; +// 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) { + dwFlags^=GENERIC_WRITE; // mmm... no success + hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // -> open drive again + NULL,OPEN_EXISTING,dwIOCTLAttr,NULL); + if (hF==INVALID_HANDLE_VALUE) return NULL; + } + return hF; +} + +void CDROM_Interface_Aspi::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; +} + +DWORD CDROM_Interface_Aspi::GetTOC(LPTOC toc) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = sizeof(*toc); + s.SRB_BufPointer = (BYTE FAR *)toc; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 0x0A; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x43; + s.CDBByte[1] = 0x02; // 0x02 for MSF + s.CDBByte[7] = 0x03; + s.CDBByte[8] = 0x24; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,30000); + + return (s.SRB_Status==SS_COMP); +} + +bool CDROM_Interface_Aspi::PlayAudioSector(unsigned long start,unsigned long len) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0; + s.SRB_BufPointer = 0; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 12; + s.SRB_PostProc = (LPVOID)hEvent; + + s.CDBByte[0] = 0xa5; + s.CDBByte[1] = lun << 5; + s.CDBByte[2] = (unsigned char)((start >> 24) & 0xFF); + s.CDBByte[3] = (unsigned char)((start >> 16) & 0xFF); + s.CDBByte[4] = (unsigned char)((start >> 8) & 0xFF); + s.CDBByte[5] = (unsigned char)((start & 0xFF)); + s.CDBByte[6] = (unsigned char)((len >> 24) & 0xFF); + s.CDBByte[7] = (unsigned char)((len >> 16) & 0xFF); + s.CDBByte[8] = (unsigned char)((len >> 8) & 0xFF); + s.CDBByte[9] = (unsigned char)(len & 0xFF); + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitForSingleObject(hEvent,10000); + + return s.SRB_Status==SS_COMP; +} + +bool CDROM_Interface_Aspi::StopAudio(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x00; + s.SRB_SenseLen = 0x0E; + s.SRB_CDBLen = 0x0A; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x4E; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,30000); + + if (s.SRB_Status!=SS_COMP) return false; + + return true; +}; + +bool CDROM_Interface_Aspi::PauseAudio(bool resume) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x00; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 0x0A; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x4B; + s.CDBByte[8] = (unsigned char)resume; // Pause + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,30000); + + if (s.SRB_Status!=SS_COMP) return false; + + return true; +}; + +bool CDROM_Interface_Aspi::GetAudioSub(unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + SUB_Q_CURRENT_POSITION pos; + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = sizeof(pos); + s.SRB_BufPointer = (BYTE FAR *)&pos; + s.SRB_CDBLen = 10; + s.SRB_PostProc = (LPVOID)hEvent; + + s.CDBByte[0] = 0x42; + s.CDBByte[1] = (lun<<5)|2; // lun & msf + s.CDBByte[2] = 0x40; // subq + s.CDBByte[3] = 0x01; // curr pos info + s.CDBByte[6] = 0; // track number (only in isrc mode, ignored) + s.CDBByte[7] = 0; // alloc len + s.CDBByte[8] = sizeof(pos); + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF); + + if (s.SRB_Status!=SS_COMP) return false; + + attr = (pos.ADR<<4) | pos.Control; + track = pos.TrackNumber; + index = pos.IndexNumber; + absPos.min = pos.AbsoluteAddress[1]; + absPos.sec = pos.AbsoluteAddress[2]; + absPos.fr = pos.AbsoluteAddress[3]; + relPos.min = pos.TrackRelativeAddress[1]; + relPos.sec = pos.TrackRelativeAddress[2]; + relPos.fr = pos.TrackRelativeAddress[3]; + + return true; +}; + +bool CDROM_Interface_Aspi::GetUPC(unsigned char& attr, char* upcdata) +{ + SUB_Q_MEDIA_CATALOG_NUMBER upc; + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = sizeof(upc); + s.SRB_BufPointer = (BYTE FAR *)&upc; + s.SRB_CDBLen = 10; + s.SRB_PostProc = (LPVOID)hEvent; + + s.CDBByte[0] = 0x42; + s.CDBByte[1] = (lun<<5)|2; // lun & msf + s.CDBByte[2] = 0x40; // subq + s.CDBByte[3] = 0x02; // get upc + s.CDBByte[6] = 0; // track number (only in isrc mode, ignored) + s.CDBByte[7] = 0; // alloc len + s.CDBByte[8] = sizeof(upc); + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF); + + if (s.SRB_Status!=SS_COMP) return false; + +// attr = (upc.ADR<<4) | upc.Control; + attr = 0; + int pos = 0; + // Convert to mscdex format +// for (int i=0; i<6; i++) upcdata[i] = (upc.MediaCatalog[pos++]<<4)+(upc.MediaCatalog[pos++]&0x0F); +// upcdata[6] = (upc.MediaCatalog[pos++]<<4); + for (int i=0; i<7; i++) upcdata[i] = upc.MediaCatalog[i]; + + return true; +}; + +bool CDROM_Interface_Aspi::GetAudioStatus(bool& playing, bool& pause) +{ + playing = pause = false; + + SUB_Q_HEADER sub; + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = sizeof(sub); + s.SRB_BufPointer = (BYTE FAR *)⊂ + s.SRB_CDBLen = 10; + s.SRB_PostProc = (LPVOID)hEvent; + + s.CDBByte[0] = 0x42; + s.CDBByte[1] = (lun<<5)|2; // lun & msf + s.CDBByte[2] = 0x00; // no subq + s.CDBByte[3] = 0x00; // dont care + s.CDBByte[6] = 0; // track number (only in isrc mode, ignored) + s.CDBByte[7] = 0; // alloc len + s.CDBByte[8] = sizeof(sub); + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF); + + if (s.SRB_Status!=SS_COMP) return false; + + playing = (sub.AudioStatus==0x11); + pause = (sub.AudioStatus==0x12); + + return true; +}; + +bool CDROM_Interface_Aspi::LoadUnloadMedia(bool unload) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = 0; + s.SRB_BufPointer = 0; + s.SRB_CDBLen = 14; + s.SRB_PostProc = (LPVOID)hEvent; + + s.CDBByte[0] = 0x1B; + s.CDBByte[1] = (lun<<5)|1; // lun & immediate + s.CDBByte[4] = (unload ? 0x02:0x03); // unload/load media + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF); + + if (s.SRB_Status!=SS_COMP) return false; + + return true; +}; + +bool CDROM_Interface_Aspi::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + mediaPresent = mediaChanged = trayOpen = false; + + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE buffer[40]; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = 40; + s.SRB_BufPointer = (BYTE FAR*)buffer; + s.SRB_CDBLen = 14; + s.SRB_PostProc = (LPVOID)hEvent; + + s.CDBByte[0] = 0x4A; + s.CDBByte[1] = (lun<<5)|1; // lun & immediate + s.CDBByte[4] = 0x10; // media + s.CDBByte[8] = 40; + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF); + + if (s.SRB_Status!=SS_COMP) return false; + + mediaChanged = (buffer[0x04]== 0x04); + mediaPresent = (buffer[0x05] & 0x02)>0; + trayOpen = (buffer[0x05] & 0x01)>0; + + return true; +}; + +bool CDROM_Interface_Aspi::ReadSectors(void* buffer, bool raw, unsigned long sector, unsigned long num) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + memset(&s,0,sizeof(s)); + + // FIXME : Is there a method to get cooked sectors with aspi ??? + // all combination i tried were failing. + // so we have to allocate extra mem and copy data to buffer if in cooked mode + char* inPtr = (char*)buffer; + if (!raw) inPtr = new char[num*2352]; + if (!inPtr) return false; + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = haId; + s.SRB_Target = target; + s.SRB_Lun = lun; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = 2352*num; //num*(raw?2352:2048); + s.SRB_BufPointer = (BYTE FAR*)inPtr; + s.SRB_CDBLen = 12; + s.SRB_PostProc = (LPVOID)hEvent; + + s.CDBByte[0] = 0xBE; + s.CDBByte[2] = (unsigned char)((sector >> 24) & 0xFF); + s.CDBByte[3] = (unsigned char)((sector >> 16) & 0xFF); + s.CDBByte[4] = (unsigned char)((sector >> 8) & 0xFF); + s.CDBByte[5] = (unsigned char)((sector & 0xFF)); + s.CDBByte[6] = (unsigned char)((num >> 16) & 0xFF); + s.CDBByte[7] = (unsigned char)((num >> 8) & 0xFF); + s.CDBByte[8] = (unsigned char) (num & 0xFF); + s.CDBByte[9] = (raw?0xF0:0x10); + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if (dwStatus==SS_PENDING) WaitForSingleObject(hEvent,0xFFFFFFFF); + + if (s.SRB_Status!=SS_COMP) { + if (!raw) delete[] inPtr; + return false; + } + + if (!raw) { + // copy user data to buffer + char* source = inPtr; + source+=16; // jump 16 bytes + char* outPtr = (char*)buffer; + for (unsigned long i=0; i1) return false; + start.min = start.fr = 0; + start.sec = 2; + attr = 0x60; // data / permitted + return true; +}; + +bool CDROM_Interface_Fake :: GetAudioSub (unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + attr = 0; + track = index = 1; + relPos.min = relPos.fr = 0; relPos.sec = 2; + absPos.min = absPos.fr = 0; absPos.sec = 2; + return true; +} + +bool CDROM_Interface_Fake :: GetAudioStatus (bool& playing, bool& pause) +{ + playing = pause = false; + return true; +} + +bool CDROM_Interface_Fake :: GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + mediaPresent = true; + mediaChanged = false; + trayOpen = false; + return true; +}; + + diff --git a/src/dos/cdrom.h b/src/dos/cdrom.h new file mode 100644 index 00000000..306dad7d --- /dev/null +++ b/src/dos/cdrom.h @@ -0,0 +1,179 @@ + +#ifndef __CDROM_INTERFACE__ +#define __CDROM_INTERFACE__ + +#define MAX_ASPI_CDROM 5 + +#include + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +typedef struct SMSF { + unsigned char min; + unsigned char sec; + unsigned char fr; +} TMSF; + +extern int CDROM_GetMountType(char* path); + +class CDROM_Interface +{ +public: +// CDROM_Interface (void); + virtual ~CDROM_Interface (void) {}; + + virtual bool SetDevice (char* path) = 0; + + virtual bool GetUPC (unsigned char& attr, char* upc) = 0; + + virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; + virtual bool GetAudioTrackInfo (int track, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioSub (unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; + virtual bool GetAudioStatus (bool& playing, bool& pause) = 0; + virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; + + virtual bool PlayAudioSector (unsigned long start,unsigned long len) = 0; + virtual bool PauseAudio (bool resume) = 0; + virtual bool StopAudio (void) = 0; + + virtual bool ReadSectors (void* buffer, bool raw, unsigned long sector, unsigned long num) = 0; + + virtual bool LoadUnloadMedia (bool unload) = 0; +}; + +class CDROM_Interface_Fake : public CDROM_Interface +{ +public: + bool SetDevice (char* path) { return true; }; + bool GetUPC (unsigned char& attr, char* upc) { attr = 0; strcpy(upc,"UPC"); return true; }; + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, TMSF& start, unsigned char& attr); + bool GetAudioSub (unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetAudioStatus (bool& playing, bool& pause); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + bool PlayAudioSector (unsigned long start,unsigned long len) { return true; }; + bool PauseAudio (bool resume) { return true; }; + bool StopAudio (void) { return true; }; + bool ReadSectors (void* buffer, bool raw, unsigned long sector, unsigned long num) { return true; }; + bool LoadUnloadMedia (bool unload) { return true; }; +}; + + +#if defined (WIN32) /* Win 32 */ + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include +#include "wnaspi32.h" // Aspi stuff + +class CDROM_Interface_Aspi : public CDROM_Interface +{ +public: + CDROM_Interface_Aspi (void); + ~CDROM_Interface_Aspi (void); + + bool SetDevice (char* path); + + bool GetUPC (unsigned char& attr, char* upc); + + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, TMSF& start, unsigned char& attr); + bool GetAudioSub (unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetAudioStatus (bool& playing, bool& pause); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + + bool PlayAudioSector (unsigned long start,unsigned long len); + bool PauseAudio (bool resume); + bool StopAudio (void); + + bool ReadSectors (void* buffer, bool raw, unsigned long sector, unsigned long num); + + bool LoadUnloadMedia (bool unload); + +private: + DWORD GetTOC (LPTOC toc); + HANDLE OpenIOCTLFile (char cLetter, BOOL bAsync); + void GetIOCTLAdapter (HANDLE hF,int * iDA,int * iDT,int * iDL); + bool ScanRegistryFindKey (HKEY& hKeyBase); + bool ScanRegistry (HKEY& hKeyBase); + BYTE GetHostAdapter (void); + + // ASPI stuff + BYTE haId; + BYTE target; + BYTE lun; + char letter; + + // Windows stuff + HINSTANCE hASPI; + HANDLE hEvent; // global event + DWORD (*pGetASPI32SupportInfo) (void); // ptrs to aspi funcs + DWORD (*pSendASPI32Command) (LPSRB); +}; + +class CDROM_Interface_Ioctl : public CDROM_Interface +{ +public: + CDROM_Interface_Ioctl (void); + ~CDROM_Interface_Ioctl (void); + + bool SetDevice (char* path); + + bool GetUPC (unsigned char& attr, char* upc); + + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, TMSF& start, unsigned char& attr); + bool GetAudioSub (unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetAudioStatus (bool& playing, bool& pause); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + + bool PlayAudioSector (unsigned long start,unsigned long len); + bool PauseAudio (bool resume); + bool StopAudio (void); + + bool ReadSectors (void* buffer, bool raw, unsigned long sector, unsigned long num); + + bool LoadUnloadMedia (bool unload); + +private: + + HANDLE hIOCTL; + TMSF oldLeadOut; +}; + +#else /* Linux */ + +class CDROM_Interface_Linux : public CDROM_Interface +{ +public: + CDROM_Interface_Linux (void); + ~CDROM_Interface_Linux (void); + + bool SetDevice (char* path); + + bool GetUPC (unsigned char& attr, char* upc); + + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, TMSF& start, unsigned char& attr); + bool GetAudioSub (unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetAudioStatus (bool& playing, bool& pause); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + + bool PlayAudioSector (unsigned long start,unsigned long len); + bool PauseAudio (bool resume); + bool StopAudio (void); + + bool ReadSectors (void* buffer, bool raw, unsigned long sector, unsigned long num); + + bool LoadUnloadMedia (bool unload); + +private: + + int dhandle; + TMSF oldLeadOut; +}; + +#endif /* linux */ + +#endif /* __CDROM_INTERFACE__ */ \ No newline at end of file diff --git a/src/dos/cdrom_ioctl.cpp b/src/dos/cdrom_ioctl.cpp new file mode 100644 index 00000000..942dc9a7 --- /dev/null +++ b/src/dos/cdrom_ioctl.cpp @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2002-2003 The DOSBox Team + * + * 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. + * + * This program 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +// IOCTL support for linux CDROM + +#if __linux__ + +#include +#include +#include +#include +#include + +#include "cdrom.h" + +CDROM_Interface_Linux::CDROM_Interface_Linux(void) +{ + memset(&oldLeadOut,0,sizeof(oldLeadOut)); +}; + +CDROM_Interface_Linux::~CDROM_Interface_Linux(void) +{ + // Stop Audio, if neccessary + StopAudio(); + close(dhandle); +}; + +bool CDROM_Interface_Linux::SetDevice(char* path) +{ + dhandle = open(path,O_RDONLY|O_NONBLOCK); + return (dhandle>=0); +}; + +bool CDROM_Interface_Linux::GetAudioTracks(int& stTrack, int& endTrack, TMSF& leadOut) +{ + struct cdrom_tochdr header; + + /* read the header information */ + if (ioctl(dhandle, CDROMREADTOCHDR, &header) != 0) return false; + + /* store the resulting information */ + stTrack = header.cdth_trk0; /* you can assume this to be zero */ + endTrack = header.cdth_trk1; + + /* Get the leadout track */ + struct cdrom_tocentry entry; + + entry.cdte_track = CDROM_LEADOUT; /* find the address of the leadout track */ + entry.cdte_format = CDROM_MSF; /* choose MSF addressing */ + + if (ioctl(dhandle, CDROMREADTOCENTRY,&entry)!=0) return false; + + leadOut.min = entry.cdte_addr.msf.minute; + leadOut.sec = entry.cdte_addr.msf.second; + leadOut.fr = entry.cdte_addr.msf.frame; + + return false; +}; + +bool CDROM_Interface_Linux::GetAudioTrackInfo (int track, TMSF& start, unsigned char& attr) +{ + struct cdrom_tocentry entry; + + entry.cdte_track = track; /* find the address of the first track */ + entry.cdte_format = CDROM_MSF; /* choose MSF addressing */ + + if (ioctl(dhandle, CDROMREADTOCENTRY,&entry)!=0) return false; + + /* attribtute */ + attr = (entry.cdte_adr<<4) | entry.cdte_ctrl; + /* store the address information */ + start.min = entry.cdte_addr.msf.minute; + start.sec = entry.cdte_addr.msf.second; + start.fr = entry.cdte_addr.msf.frame; + return true; +}; + +bool CDROM_Interface_Linux::PlayAudioSector(unsigned long start,unsigned long len) +{ + struct cdrom_blk addr; + addr.from = start; + addr.len = len; + return (ioctl(dhandle, CDROMPLAYBLK, &addr)==0); +} + +bool CDROM_Interface_Linux::StopAudio(void) +{ + return (ioctl(dhandle,CDROMSTOP,0)==0); +}; + +bool CDROM_Interface_Linux::PauseAudio(bool resume) +{ + if (resume) return (ioctl(dhandle, CDROMRESUME,0)==0); + else return (ioctl(dhandle, CDROMPAUSE,0)==0); +}; + +bool CDROM_Interface_Linux::GetAudioSub(unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + struct cdrom_subchnl sub; + + sub.cdsc_format = CDROM_MSF; + if (ioctl(dhandle, CDROMSUBCHNL, &sub)!=0) return false; + + /* attribute */ + attr = (sub.cdsc_adr<<4) | sub.cdsc_ctrl; + track = sub.cdsc_trk; + index = sub.cdsc_ind; + relPos.fr = sub.cdsc_absaddr.msf.frame; + relPos.sec = sub.cdsc_absaddr.msf.second; + relPos.min = sub.cdsc_absaddr.msf.minute; + absPos.fr = sub.cdsc_reladdr.msf.frame; + absPos.sec = sub.cdsc_reladdr.msf.second; + absPos.min = sub.cdsc_reladdr.msf.minute; + return true; +}; + +bool CDROM_Interface_Linux::GetUPC(unsigned char& attr, char* upcdata) +{ + return (ioctl(dhandle, CDROM_GET_UPC, (void*)upcdata)==0); +}; + +bool CDROM_Interface_Linux::GetAudioStatus(bool& playing, bool& pause) +{ + struct cdrom_subchnl sub; + + sub.cdsc_format = CDROM_MSF; + if (ioctl(dhandle, CDROMSUBCHNL, &sub)!=0) return false; + + playing = (sub.cdsc_audiostatus==CDROM_AUDIO_PLAY); + pause = (sub.cdsc_audiostatus==CDROM_AUDIO_PAUSED); + + return true; +}; + +bool CDROM_Interface_Linux::LoadUnloadMedia(bool unload) +{ + return (ioctl(dhandle, CDROMEJECT,0)==0); +}; + +bool CDROM_Interface_Linux::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + // Seems not possible to get this values using ioctl... + int track1,track2; + TMSF leadOut; + // If we can read, there's a media + mediaPresent = GetAudioTracks(track1, track2, leadOut); + trayOpen = !mediaPresent; + mediaChanged = (oldLeadOut.min!=leadOut.min) || (oldLeadOut.sec!=leadOut.sec) || (oldLeadOut.fr!=leadOut.fr); + // Save old values + oldLeadOut.min = leadOut.min; + oldLeadOut.sec = leadOut.sec; + oldLeadOut.fr = leadOut.fr; + // always success + return true; +}; + +bool CDROM_Interface_Linux::ReadSectors(void* buffer, bool raw, unsigned long sector, unsigned long num) +{ + // FIXME: ToDo + return false; +}; + +int CDROM_GetMountType(char* path) +// 0 - physical CDROM +// 1 - Iso file +// 2 - subdirectory +{ + // 1. Smells like a real cdrom + // FIXME: Better check if drive is a cdrom + if ((strchr(path,'/')==strrchr(path,'/')) && strstr(path,"cdrom")) return 0; + // 2. Iso file ? + // FIXME : How to detect them ? + // return 1; + // 3. bah, ordinary directory + return 2; +}; + +#else + +// ***************************************************************** +// Windows IOCTL functions (not suitable for 95/98/Me) +// ***************************************************************** + +#include "cdrom.h" +#include // Ioctl stuff +#include "ntddcdrm.h" // Ioctl stuff + +CDROM_Interface_Ioctl::CDROM_Interface_Ioctl() +{ + hIOCTL = INVALID_HANDLE_VALUE; + memset(&oldLeadOut,0,sizeof(oldLeadOut)); +}; + +CDROM_Interface_Ioctl::~CDROM_Interface_Ioctl() +{ + StopAudio(); + CloseHandle(hIOCTL); +}; + +bool CDROM_Interface_Ioctl::GetUPC(unsigned char& attr, char* upc) +{ + // FIXME : To Do + return true; +} + +bool CDROM_Interface_Ioctl::GetAudioTracks(int& stTrack, int& endTrack, TMSF& leadOut) +{ + CDROM_TOC toc; + DWORD byteCount; + BOOL bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL, 0, + &toc, sizeof(toc), &byteCount,NULL); + if (!bStat) return false; + + stTrack = toc.FirstTrack; + endTrack = toc.LastTrack; + leadOut.min = toc.TrackData[endTrack].Address[1]; + leadOut.sec = toc.TrackData[endTrack].Address[2]; + leadOut.fr = toc.TrackData[endTrack].Address[3]; + return true; +}; + +bool CDROM_Interface_Ioctl::GetAudioTrackInfo(int track, TMSF& start, unsigned char& attr) +{ + CDROM_TOC toc; + DWORD byteCount; + BOOL bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL, 0, + &toc, sizeof(toc), &byteCount,NULL); + if (!bStat) return false; + + attr = (toc.TrackData[track-1].Adr << 4) | toc.TrackData[track].Control; + start.min = toc.TrackData[track-1].Address[1]; + start.sec = toc.TrackData[track-1].Address[2]; + start.fr = toc.TrackData[track-1].Address[3]; + return true; +}; + +bool CDROM_Interface_Ioctl::GetAudioSub(unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + CDROM_SUB_Q_DATA_FORMAT insub; + SUB_Q_CHANNEL_DATA sub; + DWORD byteCount; + + insub.Format = IOCTL_CDROM_CURRENT_POSITION; + + BOOL bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL, &insub, sizeof(insub), + &sub, sizeof(sub), &byteCount,NULL); + if (!bStat) return false; + + attr = (sub.CurrentPosition.ADR << 4) | sub.CurrentPosition.Control; + track = sub.CurrentPosition.TrackNumber; + index = sub.CurrentPosition.IndexNumber; + relPos.min = sub.CurrentPosition.TrackRelativeAddress[1]; + relPos.sec = sub.CurrentPosition.TrackRelativeAddress[2]; + relPos.fr = sub.CurrentPosition.TrackRelativeAddress[3]; + absPos.min = sub.CurrentPosition.AbsoluteAddress[1]; + absPos.sec = sub.CurrentPosition.AbsoluteAddress[2]; + absPos.fr = sub.CurrentPosition.AbsoluteAddress[3]; + return true; +}; + +bool CDROM_Interface_Ioctl::GetAudioStatus(bool& playing, bool& pause) +{ + CDROM_SUB_Q_DATA_FORMAT insub; + SUB_Q_CHANNEL_DATA sub; + DWORD byteCount; + + insub.Format = IOCTL_CDROM_CURRENT_POSITION; + + BOOL bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL, &insub, sizeof(insub), + &sub, sizeof(sub), &byteCount,NULL); + if (!bStat) return false; + + playing = (sub.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS); + pause = (sub.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_PAUSED); + + return true; +}; + +bool CDROM_Interface_Ioctl::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + // Seems not possible to get this values using ioctl... + int track1,track2; + TMSF leadOut; + // If we can read, there's a media + mediaPresent = GetAudioTracks(track1, track2, leadOut), + trayOpen = !mediaPresent; + mediaChanged = (oldLeadOut.min!=leadOut.min) || (oldLeadOut.sec!=leadOut.sec) || (oldLeadOut.fr!=leadOut.fr); + // Save old values + oldLeadOut.min = leadOut.min; + oldLeadOut.sec = leadOut.sec; + oldLeadOut.fr = leadOut.fr; + // always success + return true; +}; + +bool CDROM_Interface_Ioctl::PlayAudioSector (unsigned long start,unsigned long len) +{ + CDROM_PLAY_AUDIO_MSF audio; + DWORD byteCount; + // Start + unsigned long addr = start + 150; + audio.StartingF = (UCHAR)(addr%75); addr/=75; + audio.StartingS = (UCHAR)(addr%60); + audio.StartingM = (UCHAR)(addr/60); + // End + addr = start + len + 150; + audio.EndingF = (UCHAR)(addr%75); addr/=75; + audio.EndingS = (UCHAR)(addr%60); + audio.EndingM = (UCHAR)(addr/60); + + BOOL bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF, &audio, sizeof(audio), + NULL, 0, &byteCount,NULL); + return bStat>0; +}; + +bool CDROM_Interface_Ioctl::PauseAudio(bool resume) +{ + BOOL bStat; + DWORD byteCount; + if (resume) bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO, NULL, 0, + NULL, 0, &byteCount,NULL); + else bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, + NULL, 0, &byteCount,NULL); + return bStat>0; +}; + +bool CDROM_Interface_Ioctl::StopAudio(void) +{ + BOOL bStat; + DWORD byteCount; + bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO, NULL, 0, + NULL, 0, &byteCount,NULL); + return bStat>0; +}; + +bool CDROM_Interface_Ioctl::LoadUnloadMedia(bool unload) +{ + BOOL bStat; + DWORD byteCount; + if (unload) bStat = DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, + NULL, 0, &byteCount,NULL); + else bStat = DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, + NULL, 0, &byteCount,NULL); + return bStat>0; +}; + +bool CDROM_Interface_Ioctl::ReadSectors(void* buffer, bool raw, unsigned long sector, unsigned long num) +{ + // TODO : How to copy cooked without current overhead ? + BOOL bStat; + DWORD byteCount; + RAW_READ_INFO in; + char* inPtr; + + in.DiskOffset.LowPart = sector; + in.DiskOffset.HighPart = 0; + in.SectorCount = num; + in.TrackMode = CDDA; + + if (!raw) inPtr = new char[num*RAW_SECTOR_SIZE]; + else inPtr = (char*)buffer; + + bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_RAW_READ, &in, sizeof(in), + inPtr, num*RAW_SECTOR_SIZE, &byteCount,NULL); + + if (!raw) { + char* source = inPtr; + source+=16; // jump 16 bytes + char* outPtr = (char*)buffer; + for (unsigned long i=0; i0); +} + +bool CDROM_Interface_Ioctl::SetDevice(char* path) +{ + if (GetDriveType(path)==DRIVE_CDROM) { + char buffer [256]; + char letter [3] = { 0, ':', 0 }; + letter[0] = path[0]; + strcpy(buffer,"\\\\.\\"); + strcat(buffer,letter); + hIOCTL = CreateFile(buffer, // drive to open + GENERIC_READ, // read access + FILE_SHARE_READ | // share mode + FILE_SHARE_WRITE, + NULL, // default security attributes + OPEN_EXISTING, // disposition + 0, // file attributes + NULL); // do not copy file attributes + return (hIOCTL!=INVALID_HANDLE_VALUE); + } + return false; +}; +/* +int CDROM_GetMountType(char* path) +// 0 - physical CDROM +// 1 - Iso file +// 2 - subdirectory +{ + // 1. Smells like a real cdrom + if ((strlen(path)<=3) && (path[2]=='\\') && (strchr(path,'\\')==strrchr(path,'\\')) && (GetDriveType(path)==DRIVE_CDROM)) return 0; + // 2. Iso file ? + // FIXME : How to detect them ? + // return 1; + // 3. bah, ordinary directory + return 2; +}; +*/ +#endif \ No newline at end of file