#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <paths.h>
#include <sys/param.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
#include <IOKit/storage/IOMediaBSDClient.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/storage/IOCDTypes.h>
#include <IOKit/storage/IOCDMedia.h>
#include <CoreFoundation/CoreFoundation.h>
#include <util.h>
#include "cdbase.h"
static int MacOSXCDInit(const char *);
static void MacOSXCDDeInit(void);
static int MacOSXCDGetStatus(void);
static s32 MacOSXCDReadTOC(u32 *);
static int MacOSXCDReadSectorFAD(u32, void *);
static void MacOSXCDReadAheadFAD(u32);
CDInterface ArchCD = {
CDCORE_ARCH,
"MacOSX CD Drive",
MacOSXCDInit,
MacOSXCDDeInit,
MacOSXCDGetStatus,
MacOSXCDReadTOC,
MacOSXCDReadSectorFAD,
MacOSXCDReadAheadFAD,
};
static int hCDROM;
static int MacOSXCDInit(const char * useless_for_now)
{
CFMutableDictionaryRef classesToMatch;
io_iterator_t mediaIterator;
io_object_t media;
char cdrom_name[ MAXPATHLEN ];
classesToMatch = IOServiceMatching(kIOCDMediaClass);
CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey),
kCFBooleanTrue);
IOServiceGetMatchingServices(kIOMasterPortDefault,
classesToMatch, &mediaIterator);
media = IOIteratorNext(mediaIterator);
if(media)
{
CFTypeRef path;
path = IORegistryEntryCreateCFProperty(media,
CFSTR(kIOBSDNameKey),
kCFAllocatorDefault, 0);
if (path)
{
size_t length;
strcpy(cdrom_name, _PATH_DEV);
strcat(cdrom_name, "r");
length = strlen(cdrom_name);
CFStringGetCString(path, cdrom_name + length,
MAXPATHLEN - length, kCFStringEncodingUTF8);
CFRelease(path);
}
IOObjectRelease(media);
}
if ((hCDROM = open(cdrom_name, O_RDONLY)) == -1)
{
return -1;
}
return 0;
}
static void MacOSXCDDeInit(void)
{
if (hCDROM != -1)
{
close(hCDROM);
}
}
static CDTOC * GetTOCFromCDPath(void)
{
CFMutableDictionaryRef classesToMatch;
io_iterator_t mediaIterator;
io_object_t media;
CDTOC * TOC;
classesToMatch = IOServiceMatching(kIOCDMediaClass);
CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey),
kCFBooleanTrue);
IOServiceGetMatchingServices(kIOMasterPortDefault,
classesToMatch, &mediaIterator);
media = IOIteratorNext(mediaIterator);
if(media)
{
CFDataRef TOCData = IORegistryEntryCreateCFProperty(media, CFSTR(kIOCDMediaTOCKey), kCFAllocatorDefault, 0);
TOC = malloc(CFDataGetLength(TOCData));
CFDataGetBytes(TOCData,CFRangeMake(0,CFDataGetLength(TOCData)),(UInt8 *)TOC);
CFRelease(TOCData);
IOObjectRelease(media);
}
return TOC;
}
static s32 MacOSXCDReadTOC(u32 *TOC)
{
int add150 = 150, tracks = 0;
u_char track;
int i, fad = 0;
CDTOC *cdTOC = GetTOCFromCDPath();
CDTOCDescriptor *pTrackDescriptors;
pTrackDescriptors = cdTOC->descriptors;
memset(TOC, 0xFF, 0xCC * 2);
for( i = 3; i < CDTOCGetDescriptorCount(cdTOC); i++ ) {
track = pTrackDescriptors[i].point;
fad = CDConvertMSFToLBA(pTrackDescriptors[i].p) + add150;
if ((track > 99) || (track < 1))
continue;
TOC[i-3] = (pTrackDescriptors[i].control << 28 | pTrackDescriptors[i].adr << 24 | fad);
tracks++;
}
TOC[99] = pTrackDescriptors[0].control << 28 | pTrackDescriptors[0].adr << 24 | 1 << 16;
TOC[100] = pTrackDescriptors[1].control << 28 | pTrackDescriptors[1].adr << 24 | tracks << 16;
TOC[101] = pTrackDescriptors[2].control << 28 | pTrackDescriptors[2].adr << 24 | CDConvertMSFToLBA(pTrackDescriptors[2].p) + add150;
return (0xCC * 2);
}
static int MacOSXCDGetStatus(void)
{
return 0;
}
static int MacOSXCDReadSectorFAD(u32 FAD, void *buffer)
{
const int blockSize = 2352;
#ifdef CRAB_REWRITE
const int cacheBlocks = 32;
static u8 cache[blockSize * cacheBlocks];
static u32 cacheFAD = 0xFFFFFF00;
#endif
if (hCDROM != -1)
{
#ifdef CRAB_REWRITE
if(FAD < cacheFAD || FAD >= cacheFAD + cacheBlocks) {
if(!pread(hCDROM, cache, blockSize * cacheBlocks,
(FAD - 150) * blockSize)) {
return 0;
}
cacheFAD = FAD;
}
memcpy(buffer, cache + (blockSize * (FAD - cacheFAD)), blockSize);
return 1;
#else
if (pread(hCDROM, buffer, blockSize, (FAD - 150) * blockSize))
return true;
#endif
}
return false;
}
static void MacOSXCDReadAheadFAD(UNUSED u32 FAD)
{
}