mirror of https://github.com/PCSX2/pcsx2.git
CDVD: macOS physical disc support
This commit is contained in:
parent
643e0b1039
commit
9a5dd4c19d
|
@ -0,0 +1,119 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include <IOKit/storage/IOMedia.h>
|
||||
#include <IOKit/storage/IOCDMedia.h>
|
||||
#include <IOKit/storage/IODVDMedia.h>
|
||||
#include <IOKit/IOBSD.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
std::vector<std::string> GetDriveListFromClasses(CFMutableDictionaryRef classes)
|
||||
{
|
||||
io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
kern_return_t result;
|
||||
std::vector<std::string> drives;
|
||||
|
||||
CFDictionarySetValue(classes, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
|
||||
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classes, &iterator);
|
||||
if (result != KERN_SUCCESS)
|
||||
return drives;
|
||||
io_object_t media = IOIteratorNext(iterator);
|
||||
while (media)
|
||||
{
|
||||
CFTypeRef path_cfstr = IORegistryEntryCreateCFProperty(media, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
|
||||
if (path_cfstr)
|
||||
{
|
||||
char path[PATH_MAX] = {0};
|
||||
strlcpy(path, "/dev/r", PATH_MAX);
|
||||
size_t path_prefix_len = strnlen(path, PATH_MAX);
|
||||
result = CFStringGetCString((CFStringRef)path_cfstr, path + path_prefix_len, PATH_MAX - path_prefix_len, kCFStringEncodingUTF8);
|
||||
if (result)
|
||||
{
|
||||
drives.emplace_back(path);
|
||||
}
|
||||
CFRelease(path_cfstr);
|
||||
}
|
||||
IOObjectRelease(media);
|
||||
media = IOIteratorNext(iterator);
|
||||
}
|
||||
IOObjectRelease(iterator);
|
||||
return drives;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::vector<std::string> GetOpticalDriveList()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
std::vector<std::string> drives;
|
||||
|
||||
CFMutableDictionaryRef cd_classes = IOServiceMatching(kIOCDMediaClass);
|
||||
if (cd_classes)
|
||||
{
|
||||
std::vector<std::string> cd = GetDriveListFromClasses(cd_classes);
|
||||
drives.insert(drives.end(), cd.begin(), cd.end());
|
||||
}
|
||||
|
||||
CFMutableDictionaryRef dvd_classes = IOServiceMatching(kIODVDMediaClass);
|
||||
if (dvd_classes)
|
||||
{
|
||||
std::vector<std::string> dvd = GetDriveListFromClasses(dvd_classes);
|
||||
drives.insert(drives.end(), dvd.begin(), dvd.end());
|
||||
}
|
||||
return drives;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetValidDrive(std::string& drive)
|
||||
{
|
||||
if (!drive.empty())
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd != -1)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
drive.clear();
|
||||
}
|
||||
#else
|
||||
drive.clear();
|
||||
#endif
|
||||
}
|
||||
if (drive.empty())
|
||||
{
|
||||
auto drives = GetOpticalDriveList();
|
||||
if (!drives.empty())
|
||||
drive = drives.front();
|
||||
}
|
||||
if (!drive.empty())
|
||||
printf(" * CDVD: Opening drive '%s'...\n", drive.c_str());
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <IOKit/storage/IOCDMediaBSDClient.h>
|
||||
#include <IOKit/storage/IODVDMediaBSDClient.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
IOCtlSrc::IOCtlSrc(decltype(m_filename) filename)
|
||||
: m_filename(filename)
|
||||
{
|
||||
if (!Reopen())
|
||||
throw std::runtime_error(" * CDVD: Error opening source.\n");
|
||||
}
|
||||
|
||||
IOCtlSrc::~IOCtlSrc()
|
||||
{
|
||||
if (m_device != -1)
|
||||
{
|
||||
SetSpindleSpeed(true);
|
||||
close(m_device);
|
||||
}
|
||||
}
|
||||
|
||||
bool IOCtlSrc::Reopen()
|
||||
{
|
||||
if (m_device != -1)
|
||||
close(m_device);
|
||||
|
||||
// O_NONBLOCK allows a valid file descriptor to be returned even if the
|
||||
// drive is empty. Probably does other things too.
|
||||
m_device = open(m_filename.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
// DVD detection MUST be first on Linux - The TOC ioctls work for both
|
||||
// CDs and DVDs.
|
||||
if (ReadDVDInfo() || ReadCDInfo())
|
||||
SetSpindleSpeed(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IOCtlSrc::SetSpindleSpeed(bool restore_defaults) const
|
||||
{
|
||||
// TODO: Seems it's actually able to set it (DKIOCCDSETSPEED) but I don't have
|
||||
// physical drives right now to test
|
||||
}
|
||||
|
||||
u32 IOCtlSrc::GetSectorCount() const
|
||||
{
|
||||
return m_sectors;
|
||||
}
|
||||
|
||||
u32 IOCtlSrc::GetLayerBreakAddress() const
|
||||
{
|
||||
return m_layer_break;
|
||||
}
|
||||
|
||||
s32 IOCtlSrc::GetMediaType() const
|
||||
{
|
||||
return m_media_type;
|
||||
}
|
||||
|
||||
const std::vector<toc_entry>& IOCtlSrc::ReadTOC() const
|
||||
{
|
||||
return m_toc;
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadSectors2048(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
const ssize_t bytes_to_read = 2048 * count;
|
||||
ssize_t bytes_read = pread(m_device, buffer, bytes_to_read, sector * 2048ULL);
|
||||
if (bytes_read == bytes_to_read)
|
||||
return true;
|
||||
|
||||
if (bytes_read == -1)
|
||||
fprintf(stderr, " * CDVD read sectors %u-%u failed: %s\n",
|
||||
sector, sector + count - 1, strerror(errno));
|
||||
else
|
||||
fprintf(stderr, " * CDVD read sectors %u-%u: %zd bytes read, %zd bytes expected\n",
|
||||
sector, sector + count - 1, bytes_read, bytes_to_read);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
dk_cd_read_t desc;
|
||||
memset(&desc, 0, sizeof(dk_cd_read_t));
|
||||
desc.sectorArea = kCDSectorAreaUser;
|
||||
desc.sectorType = kCDSectorTypeCDDA;
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
desc.offset = (sector + i) * 2352ULL;
|
||||
desc.buffer = buffer + i * 2352;
|
||||
desc.bufferLength = 2352;
|
||||
if (ioctl(m_device, DKIOCCDREAD, &desc) == -1)
|
||||
{
|
||||
fprintf(stderr, " * CDVD CDROMREADRAW sector %u failed: %s\n",
|
||||
sector + i, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadDVDInfo()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
dk_dvd_read_structure_t dvdrs;
|
||||
memset(&dvdrs, 0, sizeof(dk_dvd_read_structure_t));
|
||||
dvdrs.format = kDVDStructureFormatPhysicalFormatInfo;
|
||||
dvdrs.layer = 0;
|
||||
|
||||
DVDPhysicalFormatInfo layer0;
|
||||
dvdrs.buffer = &layer0;
|
||||
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
|
||||
|
||||
int ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
|
||||
if (ret == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 start_sector = *(u32*)layer0.startingPhysicalSectorNumberOfDataArea;
|
||||
u32 end_sector = *(u32*)layer0.endPhysicalSectorNumberOfDataArea;
|
||||
if (layer0.numberOfLayers == 0)
|
||||
{
|
||||
// Single layer
|
||||
m_media_type = 0;
|
||||
m_layer_break = 0;
|
||||
m_sectors = end_sector - start_sector + 1;
|
||||
}
|
||||
else if (layer0.trackPath == 0)
|
||||
{
|
||||
// Dual layer, Parallel Track Path
|
||||
DVDPhysicalFormatInfo layer1;
|
||||
dvdrs.layer = 1;
|
||||
dvdrs.buffer = &layer1;
|
||||
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
|
||||
ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
|
||||
if (ret == -1)
|
||||
return false;
|
||||
u32 layer1_start_sector = *(u32*)layer1.startingPhysicalSectorNumberOfDataArea;
|
||||
u32 layer1_end_sector = *(u32*)layer1.endPhysicalSectorNumberOfDataArea;
|
||||
|
||||
m_media_type = 1;
|
||||
m_layer_break = end_sector - start_sector;
|
||||
m_sectors = end_sector - start_sector + 1 + layer1_end_sector - layer1_start_sector + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dual layer, Opposite Track Path
|
||||
u32 end_sector_layer0 = *(u32*)layer0.endSectorNumberInLayerZero;
|
||||
m_media_type = 2;
|
||||
m_layer_break = end_sector_layer0 - start_sector;
|
||||
m_sectors = end_sector_layer0 - start_sector + 1 + end_sector - (~end_sector_layer0 & 0xFFFFFFU) + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadCDInfo()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
u8* buffer = (u8*)malloc(2048);
|
||||
dk_cd_read_toc_t cdrt;
|
||||
memset(&cdrt, 0, sizeof(dk_cd_read_toc_t));
|
||||
cdrt.format = kCDTOCFormatTOC;
|
||||
cdrt.formatAsTime = 1;
|
||||
cdrt.address.track = 0;
|
||||
cdrt.buffer = buffer;
|
||||
cdrt.bufferLength = 2048;
|
||||
memset(buffer, 0, 2048);
|
||||
|
||||
if (ioctl(m_device, DKIOCCDREADTOC, &cdrt) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
CDTOC* toc = (CDTOC*)buffer;
|
||||
|
||||
u32 desc_count = CDTOCGetDescriptorCount(toc);
|
||||
|
||||
for (u32 i = 0; i < desc_count; ++i)
|
||||
{
|
||||
CDTOCDescriptor desc = toc->descriptors[i];
|
||||
if (desc.point < 0xa0 && desc.adr == 1)
|
||||
{
|
||||
u32 lba = CDConvertMSFToLBA(desc.p);
|
||||
m_toc.push_back({lba, desc.point, desc.adr, desc.control});
|
||||
m_sectors = lba;
|
||||
}
|
||||
}
|
||||
|
||||
m_media_type = -1;
|
||||
|
||||
free(buffer);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::DiscReady()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
if (!m_sectors)
|
||||
{
|
||||
Reopen();
|
||||
}
|
||||
|
||||
return !!m_sectors;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
|
@ -16,18 +16,14 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <libudev.h>
|
||||
#include <linux/cdrom.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
std::vector<std::string> GetOpticalDriveList()
|
||||
{
|
||||
#ifdef __linux__
|
||||
udev* udev_context = udev_new();
|
||||
if (!udev_context)
|
||||
return {};
|
||||
|
@ -56,16 +52,12 @@ std::vector<std::string> GetOpticalDriveList()
|
|||
udev_unref(udev_context);
|
||||
|
||||
return drives;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetValidDrive(std::string& drive)
|
||||
{
|
||||
if (!drive.empty())
|
||||
{
|
||||
#ifdef __linux__
|
||||
int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd != -1)
|
||||
{
|
||||
|
@ -77,9 +69,6 @@ void GetValidDrive(std::string& drive)
|
|||
{
|
||||
drive.clear();
|
||||
}
|
||||
#else
|
||||
drive.clear();
|
||||
#endif
|
||||
}
|
||||
if (drive.empty())
|
||||
{
|
||||
|
|
|
@ -17,10 +17,7 @@
|
|||
#include "CDVD/CDVDdiscReader.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/cdrom.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
@ -108,7 +105,6 @@ bool IOCtlSrc::ReadSectors2048(u32 sector, u32 count, u8* buffer) const
|
|||
|
||||
bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
#ifdef __linux__
|
||||
union
|
||||
{
|
||||
cdrom_msf msf;
|
||||
|
@ -130,14 +126,10 @@ bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
|
|||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadDVDInfo()
|
||||
{
|
||||
#ifdef __linux__
|
||||
dvd_struct dvdrs;
|
||||
dvdrs.type = DVD_STRUCT_PHYSICAL;
|
||||
dvdrs.physical.layer_num = 0;
|
||||
|
@ -180,14 +172,10 @@ bool IOCtlSrc::ReadDVDInfo()
|
|||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadCDInfo()
|
||||
{
|
||||
#ifdef __linux__
|
||||
cdrom_tochdr header;
|
||||
|
||||
if (ioctl(m_device, CDROMREADTOCHDR, &header) == -1)
|
||||
|
@ -214,14 +202,10 @@ bool IOCtlSrc::ReadCDInfo()
|
|||
m_media_type = -1;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::DiscReady()
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
|
@ -239,7 +223,4 @@ bool IOCtlSrc::DiscReady()
|
|||
}
|
||||
|
||||
return !!m_sectors;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -916,14 +916,14 @@ set(pcsx2LinuxSources
|
|||
)
|
||||
|
||||
set(pcsx2OSXSources
|
||||
CDVD/Linux/DriveUtility.cpp
|
||||
CDVD/Linux/IOCtlSrc.cpp
|
||||
CDVD/Darwin/DriveUtility.cpp
|
||||
CDVD/Darwin/IOCtlSrc.cpp
|
||||
Darwin/DarwinFlatFileReader.cpp
|
||||
)
|
||||
|
||||
set(pcsx2FreeBSDSources
|
||||
CDVD/Linux/DriveUtility.cpp
|
||||
CDVD/Linux/IOCtlSrc.cpp
|
||||
CDVD/Darwin/DriveUtility.cpp
|
||||
CDVD/Darwin/IOCtlSrc.cpp
|
||||
Darwin/DarwinFlatFileReader.cpp
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue