/* Copyright 2004-2005 Theo Berkau1Copyright 2005 Joost Peters23This file is part of Yabause.45Yabause is free software; you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation; either version 2 of the License, or8(at your option) any later version.910Yabause is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with Yabause; if not, write to the Free Software17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA18*/1920#include <windows.h>21#include <stdio.h>22#include "windows/cd.h"2324//////////////////////////////////////////////////////////////////////////////2526static HANDLE hCDROM;27static SCSI_PASS_THROUGH_DIRECT sptd;28static int KillCDThread=0;29static HANDLE thread_handle=INVALID_HANDLE_VALUE;30static int drivestatus=0;31static DWORD thread_id;3233CDInterface ArchCD = {34CDCORE_SPTI,35"Windows SPTI Driver",36SPTICDInit,37SPTICDDeInit,38SPTICDGetStatus,39SPTICDReadTOC,40SPTICDReadSectorFAD,41SPTICDReadAheadFAD,42};4344//////////////////////////////////////////////////////////////////////////////45// SPTI Interface46//////////////////////////////////////////////////////////////////////////////4748DWORD WINAPI __stdcall SPTICDThread(void *b);4950int SPTICDInit(const char *cdrom_name) {51char pipe_name[7];5253sprintf(pipe_name, "\\\\.\\?:");54pipe_name[4] = cdrom_name[0];5556if ((hCDROM = CreateFileA(pipe_name, GENERIC_READ | GENERIC_WRITE,57FILE_SHARE_READ | FILE_SHARE_WRITE,58NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,59NULL)) == INVALID_HANDLE_VALUE)60{61return -1;62}6364// Setup a separate thread for handling SPTI commands(that way the emulation65// code doesn't have to wait for a response)66KillCDThread=0;67thread_handle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) SPTICDThread,(void *) &KillCDThread,0,&thread_id);6869// Set it to highest priority to avoid breaks70// SetThreadPriority(thread_handle,THREAD_PRIORITY_HIGHEST);7172return 0;73}7475//////////////////////////////////////////////////////////////////////////////7677void SPTICDDeInit() {78if (thread_handle != INVALID_HANDLE_VALUE)79{80// Set the flag telling it to stop81KillCDThread=1;82if (WaitForSingleObject(thread_handle,INFINITE) == WAIT_TIMEOUT)83{84// Couldn't close thread cleanly85TerminateThread(thread_handle,0);86}87CloseHandle(thread_handle);88thread_handle = INVALID_HANDLE_VALUE;89}9091CloseHandle(hCDROM);92}9394//////////////////////////////////////////////////////////////////////////////9596DWORD WINAPI __stdcall SPTICDThread(void *b)97{98while (KillCDThread != 1)99{100DWORD dwBytesReturned;101unsigned char statusbuf[8];102BOOL success;103104// Check to see if we have any work to do(for now, let's just do a drive105// status check once a second)106107sptd.Length=sizeof(sptd);108sptd.PathId=0; //109sptd.TargetId=0; // Don't need these, they're automatically generated110sptd.Lun=0; //111sptd.CdbLength=12;112sptd.SenseInfoLength=0; // No sense data113sptd.DataIn=SCSI_IOCTL_DATA_IN;114sptd.TimeOutValue=60; // may need to be changed115sptd.DataBuffer=(PVOID)&(statusbuf);116sptd.SenseInfoOffset=0;117sptd.DataTransferLength=8; // may need to change this118119sptd.Cdb[0]=0xBD; // CDB12 code120sptd.Cdb[1]=0; // Reserved121sptd.Cdb[2]=0; // Reserved122sptd.Cdb[3]=0; // Reserved123sptd.Cdb[4]=0; // Reserved124sptd.Cdb[5]=0; // Reserved125sptd.Cdb[6]=0; // Reserved126sptd.Cdb[7]=0; // Reserved127sptd.Cdb[8]=0; // Allocation Length(byte 1)128sptd.Cdb[9]=8; // Allocation Length(byte 2) (may have to change this)129sptd.Cdb[10]=0; // Reserved130sptd.Cdb[11]=0; // Control131sptd.Cdb[12]=0;132sptd.Cdb[13]=0;133sptd.Cdb[14]=0;134sptd.Cdb[15]=0;135136success=DeviceIoControl(hCDROM, IOCTL_SCSI_PASS_THROUGH_DIRECT,137(PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),138NULL, 0, &dwBytesReturned, NULL);139140if (success)141{142// Figure out drive status143144// Is door open?145if (statusbuf[1] & 0x10)146drivestatus = 3;147else148{149// Ok, so the door is closed, now is there a disc there?150success = DeviceIoControl(hCDROM, IOCTL_STORAGE_CHECK_VERIFY,151NULL, 0, NULL, 0, &dwBytesReturned, NULL);152if (!success)153drivestatus = 2;154else155drivestatus = 0;156}157}158else159drivestatus = 2;160161Sleep(1000);162}163164return 0;165}166167//////////////////////////////////////////////////////////////////////////////168169int SPTICDGetStatus() {170// This function is called periodically to see what the status of the171// drive is.172//173// Should return one of the following values:174// 0 - CD Present, disc spinning175// 1 - CD Present, disc not spinning176// 2 - CD not present177// 3 - Tray open178//179// If you really don't want to bother too much with this function, just180// return status 0. Though it is kind of nice when the bios's cd player,181// etc. recognizes when you've ejected the tray and popped in another disc.182/*183DWORD dwBytesReturned;184unsigned char statusbuf[8];185BOOL success;186187sptd.Length=sizeof(sptd);188sptd.PathId=0; //189sptd.TargetId=0; // Don't need these, they're automatically generated190sptd.Lun=0; //191sptd.CdbLength=12;192sptd.SenseInfoLength=0; // No sense data193sptd.DataIn=SCSI_IOCTL_DATA_IN;194sptd.TimeOutValue=60; // may need to be changed195sptd.DataBuffer=(PVOID)&(statusbuf);196sptd.SenseInfoOffset=0;197sptd.DataTransferLength=8; // may need to change this198199sptd.Cdb[0]=0xBD; // CDB12 code200sptd.Cdb[1]=0; // Reserved201sptd.Cdb[2]=0; // Reserved202sptd.Cdb[3]=0; // Reserved203sptd.Cdb[4]=0; // Reserved204sptd.Cdb[5]=0; // Reserved205sptd.Cdb[6]=0; // Reserved206sptd.Cdb[7]=0; // Reserved207sptd.Cdb[8]=0; // Allocation Length(byte 1)208sptd.Cdb[9]=8; // Allocation Length(byte 2) (may have to change this)209sptd.Cdb[10]=0; // Reserved210sptd.Cdb[11]=0; // Control211sptd.Cdb[12]=0;212sptd.Cdb[13]=0;213sptd.Cdb[14]=0;214sptd.Cdb[15]=0;215216success=DeviceIoControl(hCDROM, IOCTL_SCSI_PASS_THROUGH_DIRECT,217(PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),218NULL, 0, &dwBytesReturned, NULL);219220if (success)221{222// Figure out drive status223224// Is door open?225if (statusbuf[1] & 0x10) return 3;226227// Ok, so the door is closed, now is there a disc there?228success = DeviceIoControl(hCDROM, IOCTL_STORAGE_CHECK_VERIFY,229NULL, 0, NULL, 0, &dwBytesReturned, NULL);230if (!success)231return 2;232233return 0;234}235236return 2;237*/238return drivestatus;239}240241//////////////////////////////////////////////////////////////////////////////242243#define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f)244245s32 SPTICDReadTOC(u32 *TOC) {246// FILE *debugfp;247CDROM_TOC ctTOC;248DWORD dwNotUsed;249int i;250251if (hCDROM != INVALID_HANDLE_VALUE)252{253memset(TOC, 0xFF, 0xCC * 2);254memset(&ctTOC, 0xFF, sizeof(CDROM_TOC));255256if (DeviceIoControl (hCDROM, IOCTL_CDROM_READ_TOC,257NULL, 0, &ctTOC, sizeof(ctTOC),258&dwNotUsed, NULL) == 0)259{260return 0;261}262263// convert TOC to saturn format264for (i = 0; i < ctTOC.LastTrack; i++)265{266TOC[i] = (ctTOC.TrackData[i].Control << 28) |267(ctTOC.TrackData[i].Adr << 24) |268MSF_TO_FAD(ctTOC.TrackData[i].Address[1], ctTOC.TrackData[i].Address[2], ctTOC.TrackData[i].Address[3]);269}270271// Do First, Last, and Lead out sections here272273TOC[99] = (ctTOC.TrackData[0].Control << 28) |274(ctTOC.TrackData[0].Adr << 24) |275(ctTOC.FirstTrack << 16);276277TOC[100] = (ctTOC.TrackData[ctTOC.LastTrack - 1].Control << 28) |278(ctTOC.TrackData[ctTOC.LastTrack - 1].Adr << 24) |279(ctTOC.LastTrack << 16);280281TOC[101] = (ctTOC.TrackData[ctTOC.LastTrack].Control << 28) |282(ctTOC.TrackData[ctTOC.LastTrack].Adr << 24) |283MSF_TO_FAD(ctTOC.TrackData[ctTOC.LastTrack].Address[1], ctTOC.TrackData[ctTOC.LastTrack].Address[2], ctTOC.TrackData[ctTOC.LastTrack].Address[3]);284285// debugfp = fopen("cot2toc.bin", "wb");286// fwrite((void *)TOC, 1, 0xCC * 2, debugfp);287// fclose(debugfp);288289return (0xCC * 2);290}291292return 0;293}294295//////////////////////////////////////////////////////////////////////////////296297int SPTICDReadSectorFAD(u32 FAD, void *buffer) {298// This function is supposed to read exactly 1 -RAW- 2352-byte sector at299// the specified FAD address to buffer. Should return true if successful,300// false if there was an error.301//302// Special Note: To convert from FAD to LBA/LSN, minus 150.303//304// The whole process needed to be changed since I need more control over305// sector detection, etc. Not to mention it means less work for the porter306// since they only have to implement raw sector reading as opposed to307// implementing mode 1, mode 2 form1/form2, -and- raw sector reading.308309DWORD dwBytesReturned;310BOOL success;311312sptd.Length=sizeof(sptd);313sptd.PathId=0; //314sptd.TargetId=0; // Don't need these, they're automatically generated315sptd.Lun=0; //316sptd.CdbLength=12;317sptd.SenseInfoLength=0; // No sense data318sptd.DataIn=SCSI_IOCTL_DATA_IN;319sptd.TimeOutValue=60; // may need to be changed320sptd.DataBuffer=(PVOID)buffer;321sptd.SenseInfoOffset=0;322sptd.DataTransferLength=2352;323324sptd.Cdb[0]=0xBE; // CDB12 code325sptd.Cdb[1]=0; // Sector Type, RELADR326FAD -= 150;327sptd.Cdb[2]=(unsigned char)((FAD & 0xFF000000) >> 24); // lba(byte 1)328sptd.Cdb[3]=(unsigned char)((FAD & 0x00FF0000) >> 16); // lba(byte 2)329sptd.Cdb[4]=(unsigned char)((FAD & 0x0000FF00) >> 8); // lba(byte 3)330sptd.Cdb[5]=(unsigned char)(FAD & 0x000000FF); // lba(byte 4)331sptd.Cdb[6]=0; // number of sectors(byte 1)332sptd.Cdb[7]=0; // number of sectors(byte 2)333sptd.Cdb[8]=1; // number of sectors(byte 3)334sptd.Cdb[9]=0xF8; // Sync + All Headers + User data + EDC/ECC335sptd.Cdb[10]=0;336sptd.Cdb[11]=0;337sptd.Cdb[12]=0;338sptd.Cdb[13]=0;339sptd.Cdb[14]=0;340sptd.Cdb[15]=0;341342success=DeviceIoControl(hCDROM,343IOCTL_SCSI_PASS_THROUGH_DIRECT,344(PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),345NULL, 0,346&dwBytesReturned,347NULL);348349if (!success)350{351return 0;352}353354return 1;355}356357//////////////////////////////////////////////////////////////////////////////358359void SPTICDReadAheadFAD(u32 FAD) {360// No-op361}362363//////////////////////////////////////////////////////////////////////////////364365366