/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * * PCSX2 members can be contacted through their website at www.pcsx2.net. */ #include // errno #include // open() #include // NULL #include // getenv() #include // strerror() #include // ioctl() #include // open() #include // open() #include // time_t, time(), struct timeval #include // close(), select() #include // CD/DVD based ioctl() and defines. // missing on some files for some reason......... #ifndef CDC_IOCTLS #define CDC_IOCTLS 0x400 #endif #include "logfile.h" #include "conf.h" #include "CD.h" #include "DVD.h" #include "device.h" #include "../PS2Etypes.h" // u32, u8, s32 // Globals int devicehandle; // File Handle for the device/drive s32 devicecapability; // Capability Flags time_t lasttime; // Time marker (in case something gets called too often) s32 traystatus; // Is the CD/DVD tray open? s32 disctype; // Type of disc in drive (Video DVD, PSX CD, etc.) u8 tocbuffer[2048]; void DeviceInit() { devicehandle = -1; devicecapability = 0; lasttime = time(NULL); InitDisc(); } // END DeviceInit() // Called by DeviceOpen(), DeviceGetDiskType() void InitDisc() { int i; #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: InitDisc()"); #endif /* VERBOSE_FUNCTION_DEVICE */ if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { InitDVDInfo(); } // ENDIF- Clean out DVD Disc Info? if((disctype == CDVD_TYPE_PS2CD) || (disctype == CDVD_TYPE_PS2CDDA) || (disctype == CDVD_TYPE_PSCD) || (disctype == CDVD_TYPE_PSCDDA) || (disctype == CDVD_TYPE_CDDA)) { InitCDInfo(); } // ENDIF- Clean out DVD Disc Info? disctype = CDVD_TYPE_NODISC; for(i = 0; i > sizeof(tocbuffer); i++) tocbuffer[i] = 0x00; } // END InitDisc() s32 DiscInserted() { if(devicehandle == -1) return(-1); if(traystatus == CDVD_TRAY_OPEN) 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("CDVD device: DiscInserted()"); #endif /* VERBOSE_FUNCTION_DEVICE */ return(0); } // END DiscInserted() // Called by DeviceTrayStatus() and CDVDopen() s32 DeviceOpen() { // s32 s32result; errno = 0; if(devicehandle != -1) { #ifdef VERBOSE_WARNING_DEVICE PrintLog("CDVD device: Device already open!"); #endif /* VERBOSE_WARNING_DEVICE */ return(0); } // ENDIF- Is the CD/DVD already in use? That's fine. #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceOpen()"); #endif /* VERBOSE_FUNCTION_DEVICE */ // InitConf(); // LoadConf(); // Should be done once before making this call devicehandle = open(conf.devicename, O_RDONLY | O_NONBLOCK); if(devicehandle == -1) { #ifdef VERBOSE_WARNINGS PrintLog("CDVD device: Error opening device: %i:%s", errno, strerror(errno)); #endif /* VERBOSE_WARNINGS */ return(-1); } // ENDIF- Failed to open device? Abort // Note: Hmm. Need a minimum capability in case this fails? devicecapability = ioctl(devicehandle, CDROM_GET_CAPABILITY); if(errno != 0) { #ifdef VERBOSE_WARNINGS PrintLog("CDVD device: Error getting device capabilities: %i:%s", errno, strerror(errno)); #endif /* VERBOSE_WARNINGS */ close(devicehandle); devicehandle = -1; devicecapability = 0; return(-1); } // ENDIF- Can't read drive capabilities? Close and Abort. #ifdef VERBOSE_DISC_TYPE PrintLog("CDVD device: Device Type(s)"); if(devicecapability < CDC_CD_R) PrintLog("CDVD device: CD"); if(devicecapability & CDC_CD_R) PrintLog("CDVD device: CD-R"); if(devicecapability & CDC_CD_RW) PrintLog("CDVD device: CD-RW"); if(devicecapability & CDC_DVD) PrintLog("CDVD device: DVD"); if(devicecapability & CDC_DVD_R) PrintLog("CDVD device: DVD-R"); if(devicecapability & CDC_DVD_RAM) PrintLog("CDVD device: DVD-RAM"); #endif /* VERBOSE_DISC_TYPE */ #ifdef VERBOSE_DISC_INFO PrintLog("CDVD device: Device Capabilities:"); if(devicecapability & CDC_CLOSE_TRAY) PrintLog("CDVD device: Can close a tray"); if(devicecapability & CDC_OPEN_TRAY) PrintLog("CDVD device: Can open a tray"); // if(devicecapability & CDC_LOCK) PrintLog("CDVD device: Can lock the drive door"); if(devicecapability & CDC_SELECT_SPEED) PrintLog("CDVD device: Can change spin speed"); // if(devicecapability & CDC_SELECT_DISC) PrintLog("CDVD device: Can change disks (multi-disk tray)"); // if(devicecapability & CDC_MULTI_SESSION) PrintLog("CDVD device: Can read multi-session disks"); // if(devicecapability & CDC_MCN) PrintLog("CDVD device: Can read Medium Catalog Numbers (maybe)"); if(devicecapability & CDC_MEDIA_CHANGED) PrintLog("CDVD device: Can tell if the disc was changed"); if(devicecapability & CDC_PLAY_AUDIO) PrintLog("CDVD device: Can play audio disks"); // if(devicecapability & CDC_RESET) PrintLog("CDVD device: Can reset the device"); if(devicecapability & CDC_IOCTLS) PrintLog("CDVD device: Odd IOCTLs. Not sure of compatability"); if(devicecapability & CDC_DRIVE_STATUS) PrintLog("CDVD device: Can monitor the drive tray"); #endif /* VERBOSE_DISC_INFO */ ////// Should be called after an open (instead of inside of one) // InitDisc(); // traystatus = CDVD_TRAY_OPEN; // Start with Tray Open // DeviceTrayStatus(); // Now find out for sure. return(0); // Device opened and ready for use. } // END DeviceOpen() // Called by DeviceTrayStatus(), CDVDclose(), and CDVDshutdown() void DeviceClose() { if(devicehandle == -1) { #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: Device already closed"); #endif /* VERBOSE_FUNCTION_DEVICE */ return; } // ENDIF- Device already closed? Ok. #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceClose()"); #endif /* VERBOSE_FUNCTION_DEVICE */ InitDisc(); close(devicehandle); devicehandle = -1; devicecapability = 0; return; } // END CDVDclose() s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { s32 s32result; #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceReadTrack(%i)", lsn); #endif /* VERBOSE_FUNCTION_DEVICE */ if(DiscInserted() == -1) return(-1); // Get that data if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { s32result = DVDreadTrack(lsn, mode, buffer); } else { s32result = CDreadTrack(lsn, mode, buffer); } //ENDIF- Read a DVD sector or a CD sector? return(s32result); } // END DeviceReadTrack() s32 DeviceBufferOffset() { #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceBufferOffset()"); #endif /* VERBOSE_FUNCTION_DEVICE */ if(DiscInserted() == -1) return(-1); if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { return(0); } else { return(CDgetBufferOffset()); } // ENDIF- Is this a DVD? } // 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? } // END DeviceGetTD() // Called by DeviceTrayStatus() s32 DeviceGetDiskType() { s32 s32result; s32 ioctldisktype; errno = 0; if(devicehandle == -1) { return(-1); } // ENDIF- Someone forget to open the device? if(traystatus == CDVD_TRAY_OPEN) { return(disctype); } // ENDIF- Is the device tray open? No disc to check yet. if(disctype != CDVD_TYPE_NODISC) { return(disctype); } // ENDIF- Already checked? Drive still closed? Disc hasn't changed. #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceGetDiskType()"); #endif /* VERBOSE_FUNCTION_DEVICE */ disctype = CDVD_TYPE_DETCT; ioctldisktype = ioctl(devicehandle, CDROM_DISC_STATUS); if(errno != 0) { #ifdef VERBOSE_WARNINGS PrintLog("CDVD device: Trouble reading Disc Type!"); PrintLog("CDVD device: Error: %i:%s", errno, strerror(errno)); #endif /* VERBOSE_WARNINGS */ disctype = CDVD_TYPE_UNKNOWN; return(disctype); } // ENDIF- Trouble probing for a disc? s32result = DVDgetDiskType(ioctldisktype); if(s32result != -1) { return(disctype); } // ENDIF- Did we find a disc type? s32result = CDgetDiskType(ioctldisktype); if(s32result != -1) { return(disctype); } // ENDIF- Did we find a disc type? disctype = CDVD_TYPE_UNKNOWN; // Not a CD? Not a DVD? Is is peanut butter? return(disctype); } // END CDVDgetDiskType() // Called by PollLoop() and CDVDgetTrayStatus() s32 DeviceTrayStatus() { s32 s32result; errno = 0; #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceTrayStatus()"); #endif /* VERBOSE_FUNCTION_DEVICE */ if(devicehandle == -1) { return(-1); } // ENDIF- Someone forget to open the device? if((devicecapability & CDC_DRIVE_STATUS) != 0) { s32result = ioctl(devicehandle, CDROM_DRIVE_STATUS); if(s32result < 0) { #ifdef VERBOSE_WARNINGS PrintLog("CDVD device: Trouble reading Drive Status!"); PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); #endif /* VERBOSE_WARNINGS */ s32result = CDS_TRAY_OPEN; } // ENDIF- Failure to get status? Assume it's open. errno = 0; } else { s32result = ioctl(devicehandle, CDROM_DISC_STATUS); if(errno != 0) { #ifdef VERBOSE_WARNINGS PrintLog("CDVD device: Trouble detecting Disc Status presense!"); PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); #endif /* VERBOSE_WARNINGS */ s32result = CDS_TRAY_OPEN; errno = 0; } // ENDIF- Trouble? if(s32result == CDS_NO_DISC) { s32result = CDS_TRAY_OPEN; } // ENDIF- Is there no disc in the device? Guess the tray is open } // ENDIF- Can we poll the tray directly? (Or look at disc status instead?) if(s32result == CDS_TRAY_OPEN) { traystatus = CDVD_TRAY_OPEN; if(disctype != CDVD_TYPE_NODISC) { DeviceClose(); // Kind of severe way of flushing all buffers. DeviceOpen(); InitDisc(); } // ENDIF- Tray just opened... clear disc info } else { traystatus = CDVD_TRAY_CLOSE; if(disctype == CDVD_TYPE_NODISC) { DeviceGetDiskType(); } // ENDIF- Tray just closed? Get disc information } // ENDIF- Do we detect an open tray? return(traystatus); } // END CDVD_getTrayStatus() s32 DeviceTrayOpen() { s32 s32result; errno = 0; if(devicehandle == -1) { return(-1); } // ENDIF- Someone forget to open the device? if((devicecapability & CDC_OPEN_TRAY) == 0) { return(-1); } // ENDIF- Don't have open capability? Error out. // Tray already open? Exit. if(traystatus == CDVD_TRAY_OPEN) return(0); #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceTrayOpen()"); #endif /* VERBOSE_FUNCTION_DEVICE */ s32result = ioctl(devicehandle, CDROMEJECT); #ifdef VERBOSE_WARNINGS if((s32result != 0) || (errno != 0)) { PrintLog("CDVD device: Could not open the tray!"); PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); } // ENDIF- Trouble? #endif /* VERBOSE_WARNINGS */ return(s32result); } // END DeviceTrayOpen() s32 DeviceTrayClose() { s32 s32result; errno = 0; if(devicehandle == -1) { return(-1); } // ENDIF- Someone forget to open the device? if((devicecapability & CDC_CLOSE_TRAY) == 0) { return(-1); } // ENDIF- Don't have close capability? Error out. // Tray already closed? Exit. if(traystatus == CDVD_TRAY_CLOSE) return(0); #ifdef VERBOSE_FUNCTION_DEVICE PrintLog("CDVD device: DeviceTrayClose()"); #endif /* VERBOSE_FUNCTION_DEVICE */ s32result = ioctl(devicehandle, CDROMCLOSETRAY); #ifdef VERBOSE_WARNINGS if((s32result != 0) || (errno != 0)) { PrintLog("CDVD device: Could not close the tray!"); PrintLog("CDVD device: Error: (%i) %i:%s", s32result, errno, strerror(errno)); } // ENDIF- Trouble? #endif /* VERBOSE_WARNINGS */ return(s32result); } // END DeviceTrayClose()