VOGONS

Common searches


CD-ROM issues in OSX

Topic actions

Reply 21 of 44, by azumanga

User metadata
Rank Newbie
Rank
Newbie
wd wrote:

Thanks for the info, not sure but would it be possible to use the
cdrom_ioctl_linux.cpp for OSX? Might require to change a few ifdefs.

I am not sure. There probably are some similarities, but I can't say for sure how much could be re-used.
Anyway, I have found some information on the Apple website, including sample code for reading CD-ROM sectors: link

Reply 23 of 44, by azumanga

User metadata
Rank Newbie
Rank
Newbie

Here is my first semi-successful attempt.
The ReadSectors() function actually works at least for retrieving the volume label on "Extreme Assault", but SetDevice() is currently bogus so I use a hardcoded device name.
I also don't have the faintest idea on how to implement GetUPC(), which is luckily not needed for getting the volume label.
I just wish there were some people around with more experience in Mac software development... 🙁


#if defined (MACOSX)

// only Mac includes listed here:
#include <IOKit/storage/IOMediaBSDClient.h>
#include <IOKit/storage/IOCDTypes.h>
#include <sys/ioctl.h>
#include <fcntl.h>

CDROM_Interface_Ioctl::CDROM_Interface_Ioctl(void) : CDROM_Interface_SDL()
{
::strcpy(device_name, "");
}

bool CDROM_Interface_Ioctl::GetUPC(unsigned char& attr, char* upc)
{
// unsupported...
return false;
}

bool CDROM_Interface_Ioctl::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num)
{
// this function appears to work (at least for retrieving the volume label),
// but the device name is hardcoded, which is not good, of course...
// we should somehow be able to derive the proper name (see CDROM_Interface_Ioctl::SetDevice())

// the "raw" flag is ignored at the moment

// open first session on internal CD drive
// (assuming the ISO9660 data is on that session and the disc in that drive)
int cdrom_fd = ::open("/dev/rdisk1s0", O_RDONLY | O_NONBLOCK);
if (-1 == cdrom_fd )
{
LOG_MSG("could not open device fd");
return false;
}

u_int32_t blockSize = 0;
if (::ioctl(cdrom_fd, DKIOCGETBLOCKSIZE, &blockSize))
{
LOG_MSG("Error getting preferred block size, trying default size");
blockSize = kCDSectorSizeMode1; // other sizes do not seem to work anyway, at least not on the "Extreme Assault" CD
}
LOG_MSG("Trying Block Size of %d bytes", blockSize);

Bitu buflen = num * blockSize;
Bit8u* buf = new Bit8u[buflen];

int ret = ::lseek(cdrom_fd, sector * blockSize, SEEK_SET);
if (ret >= 0)
{
LOG_MSG("SEEK ok");
ret = ::read(cdrom_fd, buf, buflen);
}
else
{
LOG_MSG("SEEK failed");
}
if (ret != buflen)
{
Show last 35 lines
		LOG_MSG("read less than we want (%d instead of %d)", ret, buflen);
ret = -1;
}
::close(cdrom_fd);

MEM_BlockWrite(buffer, buf, buflen);
delete[] buf;

if ( ret > 0 )
{
LOG_MSG("ReadSectors successful");
}
else
{
LOG_MSG("ReadSectors failed");
}
return (ret > 0);
}

bool CDROM_Interface_Ioctl::SetDevice(char* path, int forceCD)
{
// this probably needs to be fixed - we need to be able to derive
// e.g. device_name "/dev/rdisk1s0" from path "/Volumes/EXTREME"
bool success = CDROM_Interface_SDL::SetDevice(path, forceCD);
if (success)
{
const char* tmp = SDL_CDName(forceCD);
if (tmp) safe_strncpy(device_name, tmp, 512);
else success = false;
}
return success;
}

#endif // defined (MACOSX)

Reply 25 of 44, by azumanga

User metadata
Rank Newbie
Rank
Newbie

I maybe should add that when I try to give the devicename in the mount command instead of the directory below /Volumes/, dosbox complains that the given path is not a directory.
I have not yet found the point in the code where is check is made.
If you would adjust it to allow devicenodes as well as directories, CDROM_Interface_Ioctl::SetDevice() would probably work as intended, if you use mount like this:

mount d /dev/rdisk1s0 -t cdrom -usecd 0

Reply 26 of 44, by wd

User metadata
Rank DOSBox Author
Rank
DOSBox Author

What's the exact error message? Have a look at dos_programs.cpp,
look out for the section containing PROGRAM_MOUNT_ERROR_1

The whole thing looks nice, though i would have expected it to be much
closer to the linux thing (especially no custom includes). Thanks for this one.

Reply 28 of 44, by prismra

User metadata
Rank Newbie
Rank
Newbie

Is there any possible way to make it so you can simply provide the device name so you don't have to deal with cumbersome mount commands every time? Or would it be a huge rewrite kinda thing?

Rocking the following:

Roland MT-32
Roland SC-55 Sound Canvas

Reply 31 of 44, by azumanga

User metadata
Rank Newbie
Rank
Newbie

Another attempt, this time with sortof working SetDevice().
I am not certain if this will do the trick for audio tracks as well, though.
But the volume label can now be properly retrieved from real CDs.
This has not been tested with ISO images and the like, yet, btw., only with "real" CD-ROMs.
It may or may not break some things, so beware.

#if defined (MACOSX)

#include <IOKit/storage/IOMediaBSDClient.h>
#include <IOKit/storage/IOCDTypes.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>

CDROM_Interface_Ioctl::CDROM_Interface_Ioctl(void) : CDROM_Interface_SDL()
{
::strcpy(device_name, "");
}

bool CDROM_Interface_Ioctl::GetUPC(unsigned char& attr, char* upc)
{
// unsupported...
return false;
}

bool CDROM_Interface_Ioctl::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num)
{
// the "raw" flag is ignored at the moment

// open device
LOG_MSG("ReadSectors for dev %s", device_name );
int cdrom_fd = ::open(device_name, O_RDONLY | O_NONBLOCK);
if (-1 == cdrom_fd )
{
LOG_MSG("could not open device fd");
return false;
}

u_int32_t blockSize = 0;
if (::ioctl(cdrom_fd, DKIOCGETBLOCKSIZE, &blockSize))
{
LOG_MSG("Error getting preferred block size, trying default size");
blockSize = kCDSectorSizeMode1; // other sizes do not seem to work anyway, at least not on the "Extreme Assault" CD
}
LOG_MSG("Trying Block Size of %d bytes", blockSize);

Bitu buflen = num * blockSize;
Bit8u* buf = new Bit8u[buflen];

int ret = ::lseek(cdrom_fd, sector * blockSize, SEEK_SET);
if (ret >= 0)
{
LOG_MSG("SEEK ok");
ret = ::read(cdrom_fd, buf, buflen);
}
else
{
LOG_MSG("SEEK failed");
}
if (ret != buflen)
{
LOG_MSG("read less than we want (%d instead of %d)", ret, buflen);
ret = -1;
}
Show last 79 lines
	::close(cdrom_fd);

MEM_BlockWrite(buffer, buf, buflen);
delete[] buf;

if ( ret > 0 )
{
LOG_MSG("ReadSectors successful");
}
else
{
LOG_MSG("ReadSectors failed");
}
return (ret > 0);
}

bool CDROM_Interface_Ioctl::SetDevice(char* path, int forceCD)
{
// try to get all mounts from Mac OS X
struct statfs* pMntInfo = NULL;
int nMountedFsCount = ::getmntinfo( &pMntInfo, MNT_WAIT );
if ( 0 >= nMountedFsCount )
{
// no mounts could be retrieved
return false;
}

// this is the mount destination we are looking for...
const std::string strSearchDst( path );
// let's see if we find a device we can use...
std::string strDevice;
const std::string strIso9660( "cd9660" );
const std::string strDevDisk( "/dev/disk" );
const std::string strDevRDisk( "/dev/rdisk" );
// not used, at the moment... maybe we will need two separate devices: one for the data track and one for the audio tracks
//const std::string strRedbook( "cddafs" );
for ( int i = 0; i < nMountedFsCount; i++ )
{
std::string strFsTypeUtf8( pMntInfo[i].f_fstypename );
std::string strMntSrcUtf8( pMntInfo[i].f_mntfromname );
std::string strMntDstUtf8( pMntInfo[i].f_mntonname );
// add trailing slash ("path" always has one, but the strings fetched via getmntinfo() never have one)
strMntDstUtf8 += "/";
if ( 0 == strSearchDst.compare( strMntDstUtf8 ) )
{
// mountpoint found!
// check if the filesystem is iso9660
if ( 0 == strIso9660.compare( strFsTypeUtf8 ) )
{
// bingo! but we may still need to modify /dev/diskXYZ to /dev/rdiskXYZ
strDevice = strMntSrcUtf8;
if ( 0 == strDevice.find( strDevDisk ) )
{
std::string strDevSuffix = strDevice.substr( strDevDisk.length(), strDevice.length() - strDevDisk.length() );
strDevice = strDevRDisk + strDevSuffix;
}
break;
}
}
}

if ( strDevice.empty() )
{
// given path does not match a device with ISO9660 filesystem :-(
return false;
}

// looks good so far, let's feed this to SetDevice() from the baseclass...
bool success = CDROM_Interface_SDL::SetDevice( const_cast<char*>(strDevice.c_str()), forceCD);
if (success)
{
// everything OK, we can store the device name
safe_strncpy(device_name, strDevice.c_str(), 512);
}
return success;
}

#endif // defined (MACOSX)

Reply 32 of 44, by azumanga

User metadata
Rank Newbie
Rank
Newbie

Here is a better (though still not perfect) version of SetDevice():

bool CDROM_Interface_Ioctl::SetDevice(char* path, int forceCD)
{
// try to get all mounts from Mac OS X
struct statfs* pMntInfo = NULL;
int nMountedFsCount = ::getmntinfo( &pMntInfo, MNT_WAIT );
if ( 0 >= nMountedFsCount )
{
// no mounts could be retrieved
return false;
}

// this is the mount destination we are looking for...
const std::string strSearchDst( path );
// let's see if we find a device we can use...
std::string strDevice;
const std::string strIso9660( "cd9660" );
const std::string strDevDisk( "/dev/disk" );
const std::string strDevRDisk( "/dev/rdisk" );
for ( int i = 0; i < nMountedFsCount; i++ )
{
std::string strFsTypeUtf8( pMntInfo[i].f_fstypename );
std::string strMntSrcUtf8( pMntInfo[i].f_mntfromname );
std::string strMntDstUtf8( pMntInfo[i].f_mntonname );
// add trailing slash ("path" always has one, but the strings fetched via getmntinfo() never have one)
strMntDstUtf8 += "/";
if ( 0 == strSearchDst.compare( strMntDstUtf8 ) )
{
// mountpoint found!
// check if the filesystem is iso9660
if ( 0 == strIso9660.compare( strFsTypeUtf8 ) )
{
// bingo! but we may still need to modify /dev/diskXYZ to /dev/rdiskXYZ
strDevice = strMntSrcUtf8;
if ( 0 == strDevice.find( strDevDisk ) )
{
std::string strDevSuffix = strDevice.substr( strDevDisk.length(), strDevice.length() - strDevDisk.length() );
strDevice = strDevRDisk + strDevSuffix;
}
break;
}
}
}

if ( strDevice.empty() )
{
// given path does not match a device with ISO9660 filesystem :-(
return false;
}

// we got the CD-ROM device, for CD-Audio we may need a different device (session marker detection is a bit shaky)
std::string strAudioDevice = strDevice;
size_t nSessionMarkerIdx = strDevice.rfind( 's', strDevice.length() );
size_t nCharSInDiskIdx = strDevice.find( 's', 0 );
if ( std::string::npos != nSessionMarkerIdx )
{
if ( nSessionMarkerIdx != nCharSInDiskIdx )
{
// session marker found, adjust the audio device name ("/dev/rdiskXsY" => "/dev/rdiskX")
strAudioDevice = strDevice.substr(0, nSessionMarkerIdx);
}
Show last 13 lines
	}

// looks good so far, let's feed this to SetDevice() from the baseclass with the audio device
// (this allows us to eject the disc, although audio track playback still does not work)
bool success = CDROM_Interface_SDL::SetDevice( const_cast<char*>(strAudioDevice.c_str()), forceCD);
if (success)
{
// everything OK, we can store the device name
safe_strncpy(device_name, strDevice.c_str(), 512);
}
return success;
}

Reply 33 of 44, by darkgamorck

User metadata
Rank Member
Rank
Member

Disclaimer: Some of this content is a repost of my private messages that I've been sending wd regarding this patch, since he asked me to look into it.

I've been messing with this code... and thus far I can't tell if the new functions work because there is so much plumbing missing for this code. I'm a wimpy ASP.NET c# programmer, so I'm pretty far removed from my element here (though I did take a few C++ classes in college). I've made mods to a number of files to support the new functionality, but the issue I'm having right now is finding a replacement function for the SDL_CDNumDrives function provided by SDL.

Right now the CDROM_GetMountType function in src/dos/cdrom.cpp seems to depend upon that CD-ROM SDL functionality for determining whether or not the path is for a physical cd-rom, an iso file or a directory. The SDL CDROM functions do not appear to be functional at all under OS X so this approach is not functioning.

CDROM_GetMountType returns a 0 if the path is detected to match up with the mount path of a physical CD-ROM. I've generated replacement functions for SDL_CDNumDrives() and SDL_CDName(int num) called OSX_CDNumDrives() and OSX_CDName(int num) respectively. These were cobbled together using pieces of the patch that were posted and parts of Apple's sample IOKit code. However in OS X - a CD like Mechwarrior 2 is mounted in two different places with two different device nodes. /dev/disk1s0 is the ISO 9660 track and it's mount point is /Volumes/MECH2. /dev/disk1 is the virtual mount for the aiff representations of the Audio tracks on the disk.

Now when using IO Kit code to loop through and determine what mounted devices exist (per Apple's instructions) the CD device is pulled as /dev/rdisk1. So when I run my mount command "mount e /Volumes/MECH2 -t cdrom -ioctl" it fails to mount as a physical CD-ROM because the device path for my mount point will not match up with the device patch for the actual CD-ROM device as returned by IOKit. If I try the mount command using the virtual audio track mount point for the disk, it appears to work according to the logging I have placed in all of my code, but then I get the error "MSCDEX: Failure: Path is not valid" error.

Here is the code for the two replacement functions I described earlier. This code is scattered throughout cdrom.h:

#if defined (MACOSX)
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <errno.h>
#include <paths.h>
#include <sys/param.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
#include <IOKit/storage/IOCDMedia.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/storage/IOCDTypes.h>
#include <IOKit/storage/IOMediaBSDClient.h>
#include <CoreFoundation/CoreFoundation.h>
#endif

// ******************************************************
// OSX CDROM SDL Alternate Functions
// ******************************************************

#if defined (MACOSX)
int OSX_CDNumDrives()
{
io_iterator_t mediaIterator;
mach_port_t masterPort;
kern_return_t kernResult;
CFMutableDictionaryRef classesToMatch;
io_object_t nextMedia;
int ctr = 0;

kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
if ( kernResult != KERN_SUCCESS )
{
printf( "IOMasterPort returned %d\n", kernResult );
return 0;
}
// CD media are instances of class kIOCDMediaClass.
classesToMatch = IOServiceMatching( kIOCDMediaClass );
if ( classesToMatch == NULL )
{
printf( "IOServiceMatching returned a NULL dictionary.\n" );
}
else
{
// Each IOMedia object has a property with key kIOMediaEjectableKey
// which is true if the media is indeed ejectable. So add this
// property to the CFDictionary for matching.
CFDictionarySetValue( classesToMatch,
CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
}
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Preparing to loop through devices");
kernResult = IOServiceGetMatchingServices( masterPort,
classesToMatch, &mediaIterator );
if (kernResult != KERN_SUCCESS || &mediaIterator == NULL)
{
return 0;
}
nextMedia = IOIteratorNext( mediaIterator );
while ( nextMedia )
Show last 140 lines
	{
ctr++;
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Device Found");
nextMedia = IOIteratorNext( mediaIterator );
}
LOG(LOG_ALL,LOG_NORMAL)("CDROM: No More Devices");
IOObjectRelease( nextMedia );
IOObjectRelease( mediaIterator );

return ctr;
}

char deviceFilePath[ MAXPATHLEN ];

char* OSX_CDName(int num)
{
io_iterator_t mediaIterator;
mach_port_t masterPort;
kern_return_t kernResult;
CFMutableDictionaryRef classesToMatch;
io_object_t nextMedia;
int ctr = -1;
std::string strDevice;

CFIndex maxPathSize = sizeof(deviceFilePath);

LOG(LOG_ALL,LOG_NORMAL)("CDROM: Searching for %d device", num);

kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
if ( kernResult != KERN_SUCCESS )
{
printf( "IOMasterPort returned %d\n", kernResult );
return 0;
}
// CD media are instances of class kIOCDMediaClass.
classesToMatch = IOServiceMatching( kIOCDMediaClass );
if ( classesToMatch == NULL )
{
printf( "IOServiceMatching returned a NULL dictionary.\n" );
}
else
{
// Each IOMedia object has a property with key kIOMediaEjectableKey
// which is true if the media is indeed ejectable. So add this
// property to the CFDictionary for matching.
CFDictionarySetValue( classesToMatch,
CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
}
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Preparing to loop through devices");
kernResult = IOServiceGetMatchingServices( masterPort,
classesToMatch, &mediaIterator );
if (kernResult != KERN_SUCCESS || &mediaIterator == NULL)
{
return 0;
}
nextMedia = IOIteratorNext( mediaIterator );
while ( nextMedia )
{
ctr++;
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Device Found");
if (ctr == num)
{
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Device Matched");
CFTypeRef deviceFilePathAsCFString;
deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(
nextMedia, CFSTR( kIOBSDNameKey ),
kCFAllocatorDefault, 0 );
deviceFilePath[0] = '\0';
if ( deviceFilePathAsCFString )
{
size_t devPathLength;
strcpy( deviceFilePath, _PATH_DEV );
// Add "r" before the BSD node name from the I/O Registry
// to specify the raw disk node. The raw disk node receives
// I/O requests directly and does not go through the
// buffer cache.
strcat( deviceFilePath, "r");
devPathLength = strlen( deviceFilePath );
if ( CFStringGetCString( (CFStringRef) deviceFilePathAsCFString,
deviceFilePath + devPathLength,
maxPathSize - devPathLength,
kCFStringEncodingASCII ) )

{
// try to get all mounts from Mac OS X
struct statfs* pMntInfo = NULL;
int nMountedFsCount = ::getmntinfo( &pMntInfo, MNT_WAIT );



const std::string strSearchDst( deviceFilePath );
// let's see if we find a device we can use...
const std::string strIso9660( "cd9660" );
const std::string strDevDisk( "/dev/disk" );
const std::string strDevRDisk( "/dev/rdisk" );
for ( int i = 0; i < nMountedFsCount; i++ )
{
std::string strFsTypeUtf8( pMntInfo[i].f_fstypename );
std::string strMntSrcUtf8( pMntInfo[i].f_mntfromname );
std::string strMntDstUtf8( pMntInfo[i].f_mntonname );

LOG(LOG_ALL,LOG_NORMAL)("CDROM: Checking Mount Point %s", pMntInfo[i].f_mntonname);
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Device Path is %s", pMntInfo[i].f_mntfromname);

// add trailing slash ("path" always has one, but the strings fetched via getmntinfo() never have one)
strMntDstUtf8 += "/";
// bingo! but we may still need to modify /dev/diskXYZ to /dev/rdiskXYZ
strDevice = strMntSrcUtf8;
if ( 0 == strDevice.find( strDevDisk ) )
{
std::string strDevSuffix = strDevice.substr( strDevDisk.length(), strDevice.length() - strDevDisk.length() );
strDevice = strDevRDisk + strDevSuffix;
}
if ( 0 == strSearchDst.compare( strDevice ) )
{
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Device Path Match");
// mountpoint found!
// check if the filesystem is iso9660
//if ( 0 == strIso9660.compare( strFsTypeUtf8 ) )
//{
strMntDstUtf8.copy(deviceFilePath, maxPathSize);
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Device Set to %s", deviceFilePath);
//break;
//}
}
}
}
}
CFRelease( deviceFilePathAsCFString );
}
nextMedia = IOIteratorNext( mediaIterator );
}
LOG(LOG_ALL,LOG_NORMAL)("CDROM: No More Devices");
IOObjectRelease( nextMedia );
IOObjectRelease( mediaIterator );

return deviceFilePath;
}
#endif

Here is my reimplementation of CDROM_GetMountType:

int CDROM_GetMountType(char* path, int forceCD)
// 0 - physical CDROM
// 1 - Iso file
// 2 - subdirectory
{
// 1. Smells like a real cdrom
// if ((strlen(path)<=3) && (path[2]=='\\') && (strchr(path,'\\')==strrchr(path,'\\')) && (GetDriveType(path)==DRIVE_CDROM)) return 0;

const char* cdName;
char buffer[512];
strcpy(buffer,path);
#if defined (WIN32) || defined(OS2)
upcase(buffer);
#endif

LOG(LOG_ALL,LOG_NORMAL)("CDROM: Counting Drives");

#if defined (MACOSX)
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Calling OSX Function");
int num = OSX_CDNumDrives();
#else
LOG(LOG_ALL,LOG_NORMAL)("CDROM: Calling SDL Function");
int num = SDL_CDNumDrives();
#endif

LOG(LOG_ALL,LOG_NORMAL)("CDROM: %d drives found",num);

// If cd drive is forced then check if its in range and return 0
if ((forceCD>=0) && (forceCD<num)) {
LOG(LOG_ALL,LOG_ERROR)("CDROM: Using drive %d",forceCD);
return 0;
}

// compare names
for (int i=0; i<num; i++) {
#if defined (MACOSX)
cdName = OSX_CDName(i);
#else
cdName = SDL_CDName(i);
#endif
if (strcmp(buffer,cdName)==0) return 0;
};

// Detect ISO
struct stat file_stat;
if ((stat(path, &file_stat) == 0) && S_ISREG(file_stat.st_mode)) return 1;
return 2;
};

All of that code is within cdrom.cpp.

Here are my changes to the CMscdex::AddDrive function in dos_mscdex.cpp:

#if defined (LINUX) || defined(OS2) || defined (MACOSX)
// Always use IOCTL in Linux or OS/2
cdrom[numDrives] = new CDROM_Interface_Ioctl();
LOG(LOG_MISC,LOG_NORMAL)("MSCDEX: IOCTL Interface.");
#else
// Default case windows and other oses
cdrom[numDrives] = new CDROM_Interface_SDL();
LOG(LOG_MISC,LOG_NORMAL)("MSCDEX: SDL Interface.");
#endif

Nothing too big there. I simply added on some code to make sure IOCTL was used for OS X. I also made a similar change in the cdrom.h file for OS X:

#if defined (LINUX) || defined (OS2) || defined (MACOSX)

class CDROM_Interface_Ioctl : public CDROM_Interface_SDL
{
public:
CDROM_Interface_Ioctl (void);

bool SetDevice (char* path, int forceCD);
bool GetUPC (unsigned char& attr, char* upc);
bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num);

private:
char device_name[512];
};

#endif /* LINUX */

The code posted by the previous poster was placed into the cdrom_ioctl_linux file. I used the combinatons of his last two posts to generate a complete "patch":

#if defined (MACOSX) 

#include <IOKit/storage/IOMediaBSDClient.h>
#include <IOKit/storage/IOCDTypes.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>

CDROM_Interface_Ioctl::CDROM_Interface_Ioctl(void) : CDROM_Interface_SDL()
{
strcpy(device_name, "");
}

bool CDROM_Interface_Ioctl::GetUPC(unsigned char& attr, char* upc)
{
// unsupported...
return false;
}

bool CDROM_Interface_Ioctl::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num)
{
// the "raw" flag is ignored at the moment

// open device
LOG_MSG("ReadSectors for dev %s", device_name );
int cdrom_fd = open(device_name, O_RDONLY | O_NONBLOCK);
if (-1 == cdrom_fd )
{
LOG_MSG("could not open device fd");
return false;
}

u_int32_t blockSize = 0;
if (ioctl(cdrom_fd, DKIOCGETBLOCKSIZE, &blockSize))
{
LOG_MSG("Error getting preferred block size, trying default size");
blockSize = kCDSectorSizeMode1; // other sizes do not seem to work anyway, at least not on the "Extreme Assault" CD
}
LOG_MSG("Trying Block Size of %d bytes", blockSize);

Bitu buflen = num * blockSize;
Bit8u* buf = new Bit8u[buflen];

int ret = lseek(cdrom_fd, sector * blockSize, SEEK_SET);
if (ret >= 0)
{
LOG_MSG("SEEK ok");
ret = read(cdrom_fd, buf, buflen);
}
else
{
LOG_MSG("SEEK failed");
}
if (ret != buflen)
{
LOG_MSG("read less than we want (%d instead of %d)", ret, buflen);
ret = -1;
}
Show last 91 lines
   close(cdrom_fd); 

MEM_BlockWrite(buffer, buf, buflen);
delete[] buf;

if ( ret > 0 )
{
LOG_MSG("ReadSectors successful");
}
else
{
LOG_MSG("ReadSectors failed");
}
return (ret > 0);
}

bool CDROM_Interface_Ioctl::SetDevice(char* path, int forceCD)
{
// try to get all mounts from Mac OS X
struct statfs* pMntInfo = NULL;
int nMountedFsCount = getmntinfo( &pMntInfo, MNT_WAIT );
if ( 0 >= nMountedFsCount )
{
// no mounts could be retrieved
return false;
}

// this is the mount destination we are looking for...
const std::string strSearchDst( path );
// let's see if we find a device we can use...
std::string strDevice;
const std::string strIso9660( "cd9660" );
const std::string strDevDisk( "/dev/disk" );
const std::string strDevRDisk( "/dev/rdisk" );
for ( int i = 0; i < nMountedFsCount; i++ )
{
std::string strFsTypeUtf8( pMntInfo[i].f_fstypename );
std::string strMntSrcUtf8( pMntInfo[i].f_mntfromname );
std::string strMntDstUtf8( pMntInfo[i].f_mntonname );
// add trailing slash ("path" always has one, but the strings fetched via getmntinfo() never have one)
strMntDstUtf8 += "/";
if ( 0 == strSearchDst.compare( strMntDstUtf8 ) )
{
// mountpoint found!
// check if the filesystem is iso9660
if ( 0 == strIso9660.compare( strFsTypeUtf8 ) )
{
// bingo! but we may still need to modify /dev/diskXYZ to /dev/rdiskXYZ
strDevice = strMntSrcUtf8;
if ( 0 == strDevice.find( strDevDisk ) )
{
std::string strDevSuffix = strDevice.substr( strDevDisk.length(), strDevice.length() - strDevDisk.length() );
strDevice = strDevRDisk + strDevSuffix;
}
break;
}
}
}

if ( strDevice.empty() )
{
// given path does not match a device with ISO9660 filesystem :-(
return false;
}

// we got the CD-ROM device, for CD-Audio we may need a different device (session marker detection is a bit shaky)
std::string strAudioDevice = strDevice;
size_t nSessionMarkerIdx = strDevice.rfind( 's', strDevice.length() );
size_t nCharSInDiskIdx = strDevice.find( 's', 0 );
if ( std::string::npos != nSessionMarkerIdx )
{
if ( nSessionMarkerIdx != nCharSInDiskIdx )
{
// session marker found, adjust the audio device name ("/dev/rdiskXsY" => "/dev/rdiskX")
strAudioDevice = strDevice.substr(0, nSessionMarkerIdx);
}
}

// looks good so far, let's feed this to SetDevice() from the baseclass with the audio device
// (this allows us to eject the disc, although audio track playback still does not work)
bool success = CDROM_Interface_SDL::SetDevice( const_cast<char*>(strAudioDevice.c_str()), forceCD);
if (success)
{
// everything OK, we can store the device name
safe_strncpy(device_name, strDevice.c_str(), 512);
}
return success;
}

#endif // defined (MACOSX)

Of course I don't think that code ever gets executed, but I may be wrong on that. I might do some more digging on this tommorow.

Note: To actually link the compiled objects you will need to add -framework IOKit to the linker argument list.

Reply 34 of 44, by IIGS_User

User metadata
Rank Oldbie
Rank
Oldbie
DosFreak wrote:

Well I'm sure you could but you'd only get the Data. You could create a CUE/BIN image, not sure what program you would use to do that in OSX though.

It seems, Toast (MacOS CD burner standard softw.) knows about the bin/cue format, but my mind isn't very stable about it. I can choose the bin/cue format in the left window part and Toast directs me to drag a .cue file into the main window.

I'm also not sure how to create such files, so I'm also not a stable imgmount user.

Attachments

  • toast.png
    Filename
    toast.png
    File size
    66.12 KiB
    Views
    1764 views
    File comment
    Toast & bin/cue?
    File license
    Fair use/fair dealing exception

Klimawandel.

Reply 35 of 44, by saintian

User metadata
Rank Newbie
Rank
Newbie

Hello.

I'm no developer, but I solved the problem, thanks to UAKM's fantastic option to set the discs to different drives.

First, I made disk images out of all four disks, using Toast 8.0. I just made ordinary disk images, no bin/cue files. Then I mounted these, so they show up as discs, not "harddrives", if u know what I mean, in Finder.

Next up, I added some mount codes in the dosbox.conf file:

mount d /volumes/disk1 -t cdrom usecd 0 -ioctl -label disk1
mount e /volumes/disk2 -t cdrom usecd 0 -ioctl -label disk2
mount f /volumes/disk3 -t cdrom usecd 0 -ioctl -label disk3
mount g /volumes/disk4 -t cdrom usecd 0 -ioctl -label disk4

The game woulden't swap CD's without the -label option, I noticed.

Next, in the game setup, you just choose where the different discs are located. Drive D is disk1, drive E is disk 2 etc etc...

That was really it. How Access thought about some people having 4 CD-ROM drives back then is beyond me. But the solution was already there, hardcoded into the game. With a huge smile on my face, I sat down and started playing Under A Killing Moon again. Oh my, the nostalgia!!! 😁

Oh, by the way:

Shift/Control toggles your height in the game, in case you forgot. E makes you stand up really fast. I had to google that too :p

Reply 36 of 44, by IIGS_User

User metadata
Rank Oldbie
Rank
Oldbie
saintian wrote:

Then I mounted these, so they show up as discs, not "harddrives", if u know what I mean, in Finder.

Mounted them using Toast, I assume? 😀

Klimawandel.

Reply 38 of 44, by prismra

User metadata
Rank Newbie
Rank
Newbie

Hey guys. Just wanted to drop by and check up on this issue. I appreciate the ripping/mounting workaround but that is not really practical. Is there any way a fix for this will end up in the next version?

Rocking the following:

Roland MT-32
Roland SC-55 Sound Canvas

Reply 39 of 44, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author

@prismra
I don't own any multi cd game. So I can't fix it myself, but considering you find the current solution not practical I take it that you will fix it. Thanks a lot of people will appreciate your efforts!

Water flows down the stream
How to ask questions the smart way!