pcsx2/plugins/CDVDlinuz/Src/Win32/device.c

1167 lines
19 KiB
C

/* device.c
* Copyright (C) 2002-2005 PCSX2 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 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
*
* PCSX2 members can be contacted through their website at www.pcsx2.net.
*/
#include <windows.h>
#include <ddk/ntddcdrm.h> // IOCTL_CDROM..., IOCTL_STORAGE...
#include <ddk/ntdddisk.h> // IOCTL_DISK...
#include <stdio.h> // sprintf()
#include <time.h> // time_t
#define CDVDdefs
#include "PS2Edefs.h"
#include "logfile.h"
#include "conf.h"
#include "CD.h"
#include "DVD.h"
#include "device.h"
HANDLE devicehandle;
OVERLAPPED waitevent;
time_t lasttime;
s32 traystatus;
int traystatusmethod;
s32 disctype;
char tocbuffer[2048];
void DeviceInit() {
devicehandle = NULL;
waitevent.hEvent = NULL;
waitevent.Internal = 0;
waitevent.InternalHigh = 0;
waitevent.Offset = 0;
waitevent.OffsetHigh = 0;
lasttime = 0;
InitDisc();
} // END DeviceInit()
void InitDisc() {
int i;
InitCDInfo();
InitDVDInfo();
traystatus = CDVD_TRAY_OPEN;
traystatusmethod = 0; // Poll all until one works
disctype = CDVD_TYPE_NODISC;
for(i = 0; i < 2048; i++) tocbuffer[i] = 0;
} // END InitDisc()
s32 DiscInserted() {
if(traystatus != CDVD_TRAY_CLOSE) return(-1);
if(disctype == CDVD_TYPE_ILLEGAL) return(-1);
// if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through?
if(disctype == CDVD_TYPE_DETCTDVDD) return(-1);
if(disctype == CDVD_TYPE_DETCTDVDS) return(-1);
if(disctype == CDVD_TYPE_DETCTCD) return(-1);
if(disctype == CDVD_TYPE_DETCT) return(-1);
if(disctype == CDVD_TYPE_NODISC) return(-1);
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: DiscInserted()");
#endif /* VERBOSE_FUNCTION_DEVICE */
return(0);
} // END DiscInserted()
// Returns errcode (or 0 if successful)
DWORD FinishCommand(BOOL boolresult) {
DWORD errcode;
DWORD waitcode;
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: FinishCommand()");
#endif /* VERBOSE_FUNCTION_DEVICE */
if(boolresult == TRUE) {
ResetEvent(waitevent.hEvent);
return(0);
} // ENDIF- Device is ready? Say so.
errcode = GetLastError();
if(errcode == ERROR_IO_PENDING) {
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: Waiting for completion.");
#endif /* VERBOSE_FUNCTION_DEVICE */
waitcode = WaitForSingleObject(waitevent.hEvent, 10 * 1000); // 10 sec wait
if((waitcode == WAIT_FAILED) || (waitcode == WAIT_ABANDONED)) {
errcode = GetLastError();
} else if(waitcode == WAIT_TIMEOUT) {
errcode = 21;
CancelIo(devicehandle); // Speculative Line
} else {
ResetEvent(waitevent.hEvent);
return(0); // Success!
} // ENDIF- Trouble waiting? (Or doesn't finish in 5 seconds?)
} // ENDIF- Should we wait for the call to finish?
ResetEvent(waitevent.hEvent);
return(errcode);
} // END DeviceCommand()
s32 DeviceOpen() {
char tempname[256];
UINT drivetype;
DWORD errcode;
if(conf.devicename[0] == 0) return(-1);
if(devicehandle != NULL) return(0);
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: DeviceOpen()");
#endif /* VERBOSE_FUNCTION_DEVICE */
// InitConf();
// LoadConf(); // Should be done at least once before this call
// Root Directory reference
if(conf.devicename[1] == 0) {
sprintf(tempname, "%s:\\", conf.devicename);
} else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) {
sprintf(tempname, "%s\\", conf.devicename);
} else {
sprintf(tempname, "%s", conf.devicename);
} // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in.
drivetype = GetDriveType(tempname);
if(drivetype != DRIVE_CDROM) {
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Not a CD-ROM!");
PrintLog("CDVDlinuz device: (Came back: %u)", drivetype);
errcode = GetLastError();
if(errcode > 0) PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
return(-1);
} // ENDIF- Not a CD-ROM? Say so!
// Hmm. Do we want to include DRIVE_REMOVABLE... just in case?
// Device Reference
if(conf.devicename[1] == 0) {
sprintf(tempname, "\\\\.\\%s:", conf.devicename);
} else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) {
sprintf(tempname, "\\\\.\\%s", conf.devicename);
} else {
sprintf(tempname, "%s", conf.devicename);
} // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in.
devicehandle = CreateFile(tempname,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if(devicehandle == INVALID_HANDLE_VALUE) {
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Couldn't open device read-only! Read-Write perhaps?");
errcode = GetLastError();
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
devicehandle = CreateFile(tempname,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
} // ENDIF- Couldn't open for read? Try read/write (for those drives that insist)
if(devicehandle == INVALID_HANDLE_VALUE) {
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Couldn't open device!");
errcode = GetLastError();
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
devicehandle = NULL;
return(-1);
} // ENDIF- Couldn't open that way either? Abort.
waitevent.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(waitevent.hEvent == INVALID_HANDLE_VALUE) {
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Couldn't open event handler!");
errcode = GetLastError();
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
waitevent.hEvent = NULL;
CloseHandle(devicehandle);
devicehandle = NULL;
} // ENDIF- Couldn't create an "Wait for I/O" handle? Abort.
// More here... DeviceIoControl? for Drive Capabilities
// DEVICE_CAPABILITIES?
////// Should be done just after the first DeviceOpen();
// InitDisc(); // ?
// DeviceTrayStatus();
return(0);
} // END DeviceOpen()
void DeviceClose() {
if(devicehandle == NULL) return;
if(devicehandle == INVALID_HANDLE_VALUE) {
devicehandle = NULL;
return;
} // ENDIF- Bad value? Just clear the value.
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: DeviceClose()");
#endif /* VERBOSE_FUNCTION_DEVICE */
if(waitevent.hEvent != NULL) {
if(waitevent.hEvent != INVALID_HANDLE_VALUE) {
CancelIo(devicehandle);
CloseHandle(waitevent.hEvent);
} // ENDIF- Is this handle actually open?
waitevent.hEvent = NULL;
waitevent.Offset = 0;
waitevent.OffsetHigh = 0;
} // ENDIF- Reset the event handle?
CloseHandle(devicehandle);
devicehandle = NULL;
return;
} // END DeviceClose()
s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) {
if(DiscInserted() == -1) return(-1);
if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) {
return(DVDreadTrack(lsn, mode, buffer));
} else {
return(CDreadTrack(lsn, mode, buffer));
} // ENDIF- Is this a DVD?
} // END DeviceReadTrack()
s32 DeviceBufferOffset() {
if(DiscInserted() == -1) return(-1);
if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) {
return(0);
} else {
return(CDgetBufferOffset());
} // ENDIF- Is this a DVD?
return(-1);
} // END DeviceBufferOffset()
s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) {
if(DiscInserted() == -1) return(-1);
if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) {
return(DVDgetTD(track, cdvdtd));
} else {
return(CDgetTD(track, cdvdtd));
} // ENDIF- Is this a DVD?
return(-1);
} // END DeviceGetTD()
s32 DeviceGetDiskType() {
s32 s32result;
if(devicehandle == NULL) return(-1);
if(devicehandle == INVALID_HANDLE_VALUE) return(-1);
if(traystatus == CDVD_TRAY_OPEN) return(disctype);
if(disctype != CDVD_TYPE_NODISC) return(disctype);
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: DeviceGetDiskType()");
#endif /* VERBOSE_FUNCTION_DEVICE */
disctype = CDVD_TYPE_DETCT;
s32result = DVDgetDiskType();
if(s32result != -1) return(disctype);
s32result = CDgetDiskType();
if(s32result != -1) return(disctype);
disctype = CDVD_TYPE_UNKNOWN;
return(disctype);
} // END DeviceGetDiskType()
BOOL DeviceTrayStatusStorage() {
BOOL boolresult;
DWORD byteswritten;
DWORD errcode;
boolresult = DeviceIoControl(devicehandle,
IOCTL_STORAGE_CHECK_VERIFY,
NULL,
0,
NULL,
0,
&byteswritten,
NULL);
errcode = FinishCommand(boolresult);
if(errcode == 0) return(TRUE);
if(errcode == 21) return(FALSE); // Device not ready? (Valid error)
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Trouble detecting drive status (STORAGE)!");
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
return(FALSE);
} // END DeviceTrayStatusStorage()
BOOL DeviceTrayStatusCDRom() {
BOOL boolresult;
DWORD byteswritten;
DWORD errcode;
boolresult = DeviceIoControl(devicehandle,
IOCTL_CDROM_CHECK_VERIFY,
NULL,
0,
NULL,
0,
&byteswritten,
NULL);
errcode = FinishCommand(boolresult);
if(errcode == 0) return(TRUE);
if(errcode == 21) return(FALSE); // Device not ready? (Valid error)
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Trouble detecting drive status (CDROM)!");
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
return(FALSE);
} // END DeviceTrayStatusCDRom()
BOOL DeviceTrayStatusDisk() {
BOOL boolresult;
DWORD byteswritten;
DWORD errcode;
boolresult = DeviceIoControl(devicehandle,
IOCTL_DISK_CHECK_VERIFY,
NULL,
0,
NULL,
0,
&byteswritten,
NULL);
errcode = FinishCommand(boolresult);
if(errcode == 0) return(TRUE);
if(errcode == 21) return(FALSE); // Device not ready? (Valid error)
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Trouble detecting drive status (DISK)!");
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
return(FALSE);
} // END DeviceTrayStatusDisk()
s32 DeviceTrayStatus() {
BOOL boolresult;
if(devicehandle == NULL) return(-1);
if(devicehandle == INVALID_HANDLE_VALUE) return(-1);
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: DeviceTrayStatus()");
#endif /* VERBOSE_FUNCTION_DEVICE */
switch(traystatusmethod) {
case 1:
boolresult = DeviceTrayStatusStorage();
break;
case 2:
boolresult = DeviceTrayStatusCDRom();
break;
case 3:
boolresult = DeviceTrayStatusDisk();
break;
default:
boolresult = FALSE;
break;
} // ENDSWITCH traystatusmethod- One method already working? Try it again.
if(boolresult == FALSE) {
traystatusmethod = 0;
boolresult = DeviceTrayStatusStorage();
if(boolresult == TRUE) {
traystatusmethod = 1;
} else {
boolresult = DeviceTrayStatusCDRom();
if(boolresult == TRUE) {
traystatusmethod = 2;
} else {
boolresult = DeviceTrayStatusDisk();
if(boolresult == TRUE) traystatusmethod = 3;
} // ENDIF- Did we succeed with CDRom?
} // ENDIF- Did we succeed with Storage?
} // Single call to already working test just failed? Test them all.
if(boolresult == FALSE) {
if(traystatus == CDVD_TRAY_CLOSE) {
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: Tray just opened!");
#endif /* VERBOSE_FUNCTION_DEVICE */
traystatus = CDVD_TRAY_OPEN;
DeviceClose();
DeviceOpen();
InitDisc();
} // ENDIF- Just opened? clear disc info
return(traystatus);
} // ENDIF- Still failed? Assume no disc in drive then.
if(traystatus == CDVD_TRAY_OPEN) {
traystatus = CDVD_TRAY_CLOSE;
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: Tray just closed!");
#endif /* VERBOSE_FUNCTION_DEVICE */
DeviceGetDiskType();
return(traystatus);
} // ENDIF- Just closed? Get disc information
return(traystatus);
} // END DeviceTrayStatus()
s32 DeviceTrayOpen() {
BOOL boolresult;
DWORD byteswritten;
DWORD errcode;
if(devicehandle == NULL) return(-1);
if(devicehandle == INVALID_HANDLE_VALUE) return(-1);
if(traystatus == CDVD_TRAY_OPEN) return(0);
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: DeviceOpenTray()");
#endif /* VERBOSE_FUNCTION_DEVICE */
boolresult = DeviceIoControl(devicehandle,
IOCTL_STORAGE_EJECT_MEDIA,
NULL,
0,
NULL,
0,
&byteswritten,
&waitevent);
errcode = FinishCommand(boolresult);
if(errcode != 0) {
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Couldn't signal media to eject! (STORAGE)");
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
// boolresult = DeviceIoControl(devicehandle,
// IOCTL_DISK_EJECT_MEDIA,
// NULL,
// 0,
// NULL,
// 0,
// &byteswritten,
// NULL);
// } // ENDIF- Storage Call failed? Try Disk call.
// if(boolresult == FALSE) {
// #ifdef VERBOSE_WARNING_DEVICE
// PrintLog("CDVDlinuz device: Couldn't signal media to eject! (DISK)");
// PrintError("CDVDlinuz device", errcode);
// #endif /* VERBOSE_WARNING_DEVICE */
return(-1);
} // ENDIF- Disk Call failed as well? Give it up.
return(0);
} // END DeviceTrayOpen()
s32 DeviceTrayClose() {
BOOL boolresult;
DWORD byteswritten;
DWORD errcode;
if(devicehandle == NULL) return(-1);
if(devicehandle == INVALID_HANDLE_VALUE) return(-1);
if(traystatus == CDVD_TRAY_CLOSE) return(0);
#ifdef VERBOSE_FUNCTION_DEVICE
PrintLog("CDVDlinuz device: DeviceCloseTray()");
#endif /* VERBOSE_FUNCTION_DEVICE */
boolresult = DeviceIoControl(devicehandle,
IOCTL_STORAGE_LOAD_MEDIA,
NULL,
0,
NULL,
0,
&byteswritten,
NULL);
errcode = FinishCommand(boolresult);
if(errcode != 0) {
#ifdef VERBOSE_WARNING_DEVICE
PrintLog("CDVDlinuz device: Couldn't signal media to load! (STORAGE)");
PrintError("CDVDlinuz device", errcode);
#endif /* VERBOSE_WARNING_DEVICE */
// boolresult = DeviceIoControl(devicehandle,
// IOCTL_CDROM_LOAD_MEDIA,
// NULL,
// 0,
// NULL,
// 0,
// &byteswritten,
// NULL);
// } // ENDIF- Storage call failed. CDRom call?
// if(boolresult == FALSE) {
// errcode = GetLastError();
// #ifdef VERBOSE_WARNING_DEVICE
// PrintLog("CDVDlinuz device: Couldn't signal media to load! (CDROM)");
// PrintError("CDVDlinuz device", errcode);
// #endif /* VERBOSE_WARNING_DEVICE */
// boolresult = DeviceIoControl(devicehandle,
// IOCTL_DISK_LOAD_MEDIA,
// NULL,
// 0,
// NULL,
// 0,
// &byteswritten,
// NULL);
// } // ENDIF- CDRom call failed. Disk call?
// if(boolresult == FALSE) {
// #ifdef VERBOSE_WARNING_DEVICE
// PrintLog("CDVDlinuz device: Couldn't signal media to load! (DISK)");
// PrintError("CDVDlinuz device", errcode);
// #endif /* VERBOSE_WARNING_DEVICE */
return(-1);
} // ENDIF- Media not available?
return(0);
} // END DeviceTrayClose()