- commit patch [ 630863 ] Fix and integrate MacOSX cdrom
by Jeremy Parsons <brefin@mac.com> http://sourceforge.net/tracker/index.php?func=detail&aid=630863&group_id=12580&atid=312580 - modified: iodev/cdrom.cc configure.in configure - removed: iodev/cdrom_osx.cc
This commit is contained in:
parent
8ab3a76bbf
commit
428b686df6
4
bochs/configure
vendored
4
bochs/configure
vendored
@ -1,5 +1,5 @@
|
||||
#! /bin/sh
|
||||
# From configure.in Id: configure.in,v 1.156 2002/10/27 13:28:30 bdenney Exp .
|
||||
# From configure.in Id: configure.in,v 1.157 2002/10/28 05:49:42 bdenney Exp .
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.53.
|
||||
#
|
||||
@ -19987,7 +19987,7 @@ echo "${ECHO_T}yes" >&6
|
||||
# use cdrom_osx
|
||||
echo "$as_me:$LINENO: result: Using OSX IOKit CD Interface" >&5
|
||||
echo "${ECHO_T}Using OSX IOKit CD Interface" >&6
|
||||
CDROM_OBJS="cdrom_osx.o"
|
||||
CDROM_OBJS="cdrom.o"
|
||||
EXTRA_LINK_OPTS="${EXTRA_LINK_OPTS} -framework IOKit -framework CoreFoundation"
|
||||
fi
|
||||
case $target in
|
||||
|
@ -2,7 +2,7 @@ dnl // Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(bochs.h)
|
||||
AC_REVISION([[$Id: configure.in,v 1.157 2002-10-28 05:49:42 bdenney Exp $]])
|
||||
AC_REVISION([[$Id: configure.in,v 1.158 2002-11-01 16:36:27 bdenney Exp $]])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_HEADER(ltdlconf.h)
|
||||
|
||||
@ -1366,7 +1366,7 @@ if test "$bx_cdrom" = 1; then
|
||||
elif test "$can_use_osx_cdrom" = yes; then
|
||||
# use cdrom_osx
|
||||
AC_MSG_RESULT(Using OSX IOKit CD Interface)
|
||||
CDROM_OBJS="cdrom_osx.o"
|
||||
CDROM_OBJS="cdrom.o"
|
||||
EXTRA_LINK_OPTS="${EXTRA_LINK_OPTS} -framework IOKit -framework CoreFoundation"
|
||||
fi
|
||||
case $target in
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: cdrom.cc,v 1.49 2002-10-25 11:44:38 bdenney Exp $
|
||||
// $Id: cdrom.cc,v 1.50 2002-11-01 16:36:26 bdenney Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
@ -93,6 +93,64 @@ extern "C" {
|
||||
#define CD_FRAMESIZE 2048
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <dev/disk.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 <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
// These definitions were taken from mount_cd9660.c
|
||||
// There are some similar definitions in IOCDTypes.h
|
||||
// however there seems to be some dissagreement in
|
||||
// the definition of CDTOC.length
|
||||
struct _CDMSF {
|
||||
u_char minute;
|
||||
u_char second;
|
||||
u_char frame;
|
||||
};
|
||||
|
||||
#define MSF_TO_LBA(msf) \
|
||||
(((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
|
||||
|
||||
struct _CDTOC_Desc {
|
||||
u_char session;
|
||||
u_char ctrl_adr; /* typed to be machine and compiler independent */
|
||||
u_char tno;
|
||||
u_char point;
|
||||
struct _CDMSF address;
|
||||
u_char zero;
|
||||
struct _CDMSF p;
|
||||
};
|
||||
|
||||
struct _CDTOC {
|
||||
u_short length; /* in native cpu endian */
|
||||
u_char first_session;
|
||||
u_char last_session;
|
||||
struct _CDTOC_Desc trackdesc[1];
|
||||
};
|
||||
|
||||
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator, mach_port_t *masterPort );
|
||||
static kern_return_t GetDeviceFilePath( io_iterator_t mediaIterator, char *deviceFilePath, CFIndex maxPathSize );
|
||||
//int OpenDrive( const char *deviceFilePath );
|
||||
static struct _CDTOC * ReadTOC( const char * devpath );
|
||||
|
||||
static char CDDevicePath[ MAXPATHLEN ];
|
||||
|
||||
#define BX_CD_FRAMESIZE 2048
|
||||
#define CD_FRAMESIZE 2048
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
// windows.h included by bochs.h
|
||||
#include <winioctl.h>
|
||||
@ -119,6 +177,189 @@ static HINSTANCE hASPI = NULL;
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator,
|
||||
mach_port_t *masterPort )
|
||||
{
|
||||
kern_return_t kernResult;
|
||||
CFMutableDictionaryRef classesToMatch;
|
||||
kernResult = IOMasterPort( bootstrap_port, masterPort );
|
||||
if ( kernResult != KERN_SUCCESS )
|
||||
{
|
||||
fprintf ( stderr, "IOMasterPort returned %d\n", kernResult );
|
||||
return kernResult;
|
||||
}
|
||||
// CD media are instances of class kIOCDMediaClass.
|
||||
classesToMatch = IOServiceMatching( kIOCDMediaClass );
|
||||
if ( classesToMatch == NULL )
|
||||
fprintf ( stderr, "IOServiceMatching returned a NULL dictionary.\n" );
|
||||
else
|
||||
{
|
||||
// Each IOMedia object has a property with key kIOMediaEjectable
|
||||
// which is true if the media is indeed ejectable. So add property
|
||||
// to CFDictionary for matching.
|
||||
CFDictionarySetValue( classesToMatch,
|
||||
CFSTR( kIOMediaEjectable ), kCFBooleanTrue );
|
||||
}
|
||||
kernResult = IOServiceGetMatchingServices( *masterPort,
|
||||
classesToMatch, mediaIterator );
|
||||
if ( (kernResult != KERN_SUCCESS) || (*mediaIterator == NULL) )
|
||||
fprintf( stderr, "No ejectable CD media found.\n kernResult = %d\n", kernResult );
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
|
||||
static kern_return_t GetDeviceFilePath( io_iterator_t mediaIterator,
|
||||
char *deviceFilePath, CFIndex maxPathSize )
|
||||
{
|
||||
io_object_t nextMedia;
|
||||
kern_return_t kernResult = KERN_FAILURE;
|
||||
nextMedia = IOIteratorNext( mediaIterator );
|
||||
if ( nextMedia == NULL )
|
||||
{
|
||||
*deviceFilePath = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
CFTypeRef deviceFilePathAsCFString;
|
||||
deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(
|
||||
nextMedia, CFSTR( kIOBSDName ),
|
||||
kCFAllocatorDefault, 0 );
|
||||
*deviceFilePath = '\0';
|
||||
if ( deviceFilePathAsCFString )
|
||||
{
|
||||
size_t devPathLength = strlen( _PATH_DEV );
|
||||
strcpy( deviceFilePath, _PATH_DEV );
|
||||
if ( CFStringGetCString( (const __CFString *) deviceFilePathAsCFString,
|
||||
deviceFilePath + devPathLength,
|
||||
maxPathSize - devPathLength,
|
||||
kCFStringEncodingASCII ) )
|
||||
{
|
||||
// fprintf( stderr, "BSD path: %s\n", deviceFilePath );
|
||||
kernResult = KERN_SUCCESS;
|
||||
}
|
||||
CFRelease( deviceFilePathAsCFString );
|
||||
}
|
||||
}
|
||||
IOObjectRelease( nextMedia );
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
|
||||
static int OpenDrive( const char *deviceFilePath )
|
||||
{
|
||||
|
||||
int fileDescriptor;
|
||||
|
||||
fileDescriptor = open( deviceFilePath, O_RDONLY );
|
||||
if ( fileDescriptor == -1 )
|
||||
fprintf( stderr, "Error %d opening device %s.\n", errno, deviceFilePath );
|
||||
return fileDescriptor;
|
||||
|
||||
}
|
||||
|
||||
static struct _CDTOC * ReadTOC( const char * devpath ) {
|
||||
|
||||
struct _CDTOC * toc_p = NULL;
|
||||
io_iterator_t iterator = 0;
|
||||
io_registry_entry_t service = 0;
|
||||
CFDictionaryRef properties = 0;
|
||||
CFDataRef data = 0;
|
||||
mach_port_t port = 0;
|
||||
char * devname;
|
||||
|
||||
if (( devname = strrchr( devpath, '/' )) != NULL ) {
|
||||
++devname;
|
||||
}
|
||||
else {
|
||||
devname = (char *) devpath;
|
||||
}
|
||||
|
||||
if ( IOMasterPort(bootstrap_port, &port ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IOMasterPort failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( IOServiceGetMatchingServices( port, IOBSDNameMatching( port, 0, devname ),
|
||||
&iterator ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IOServiceGetMatchingServices failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
service = IOIteratorNext( iterator );
|
||||
|
||||
IOObjectRelease( iterator );
|
||||
|
||||
iterator = 0;
|
||||
|
||||
while ( service && !IOObjectConformsTo( service, "IOCDMedia" )) {
|
||||
if ( IORegistryEntryGetParentIterator( service, kIOServicePlane,
|
||||
&iterator ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
IOObjectRelease( service );
|
||||
service = IOIteratorNext( iterator );
|
||||
IOObjectRelease( iterator );
|
||||
|
||||
}
|
||||
|
||||
if ( service == NULL ) {
|
||||
fprintf( stderr, "CD media not found\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( IORegistryEntryCreateCFProperties( service, (__CFDictionary **) &properties,
|
||||
kCFAllocatorDefault,
|
||||
kNilOptions ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
data = (CFDataRef) CFDictionaryGetValue( properties, CFSTR("TOC") );
|
||||
if ( data == NULL ) {
|
||||
fprintf( stderr, "CFDictionaryGetValue failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
else {
|
||||
|
||||
CFRange range;
|
||||
CFIndex buflen;
|
||||
|
||||
buflen = CFDataGetLength( data ) + 1;
|
||||
range = CFRangeMake( 0, buflen );
|
||||
toc_p = (struct _CDTOC *) malloc( buflen );
|
||||
if ( toc_p == NULL ) {
|
||||
fprintf( stderr, "Out of memory\n" );
|
||||
goto Exit;
|
||||
}
|
||||
else {
|
||||
CFDataGetBytes( data, range, (unsigned char *) toc_p );
|
||||
}
|
||||
|
||||
/*
|
||||
fprintf( stderr, "Table of contents\n length %d first %d last %d\n",
|
||||
toc_p->length, toc_p->first_session, toc_p->last_session );
|
||||
*/
|
||||
|
||||
CFRelease( properties );
|
||||
|
||||
}
|
||||
|
||||
|
||||
Exit:
|
||||
|
||||
if ( service ) {
|
||||
IOObjectRelease( service );
|
||||
}
|
||||
|
||||
return toc_p;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
bool ReadCDSector(unsigned int hid, unsigned int tid, unsigned int lun, unsigned long frame, unsigned char *buf, int bufsize)
|
||||
@ -213,7 +454,7 @@ cdrom_interface::cdrom_interface(char *dev)
|
||||
|
||||
void
|
||||
cdrom_interface::init(void) {
|
||||
BX_DEBUG(("Init $Id: cdrom.cc,v 1.49 2002-10-25 11:44:38 bdenney Exp $"));
|
||||
BX_DEBUG(("Init $Id: cdrom.cc,v 1.50 2002-11-01 16:36:26 bdenney Exp $"));
|
||||
BX_INFO(("file = '%s'",path));
|
||||
}
|
||||
|
||||
@ -327,6 +568,37 @@ cdrom_interface::insert_cdrom(char *dev)
|
||||
if (hFile !=(void *)0xFFFFFFFF)
|
||||
fd=1;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
if(strcmp(path, "drive") == 0)
|
||||
{
|
||||
mach_port_t masterPort = NULL;
|
||||
io_iterator_t mediaIterator;
|
||||
kern_return_t kernResult;
|
||||
|
||||
BX_INFO(( "Insert CDROM" ));
|
||||
|
||||
kernResult = FindEjectableCDMedia( &mediaIterator, &masterPort );
|
||||
if ( kernResult != KERN_SUCCESS ) {
|
||||
BX_INFO (("Unable to find CDROM"));
|
||||
return false;
|
||||
}
|
||||
|
||||
kernResult = GetDeviceFilePath( mediaIterator, CDDevicePath, sizeof( CDDevicePath ) );
|
||||
if ( kernResult != KERN_SUCCESS ) {
|
||||
BX_INFO (("Unable to get CDROM device file path" ));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here a cdrom was found so see if we can read from it.
|
||||
// At this point a failure will result in panic.
|
||||
if ( strlen( CDDevicePath ) ) {
|
||||
fd = open(CDDevicePath, O_RDONLY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open(path, O_RDONLY);
|
||||
}
|
||||
#else
|
||||
// all platforms except win32
|
||||
fd = open(path, O_RDONLY);
|
||||
@ -421,7 +693,7 @@ cdrom_interface::read_toc(uint8* buf, int* length, bx_bool msf, int start_track)
|
||||
BX_PANIC(("cdrom: read_toc: file not open."));
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#if defined(WIN32)
|
||||
if (1) { // This is a hack and works okay if there's one rom track only
|
||||
#else
|
||||
if (using_file) {
|
||||
@ -652,6 +924,78 @@ cdrom_interface::read_toc(uint8* buf, int* length, bx_bool msf, int start_track)
|
||||
|
||||
return true;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
// Read CD TOC. Returns false if start track is out of bounds.
|
||||
|
||||
#if 1
|
||||
{
|
||||
struct _CDTOC * toc = ReadTOC( CDDevicePath );
|
||||
|
||||
if ((start_track > toc->last_session) && (start_track != 0xaa))
|
||||
return false;
|
||||
|
||||
buf[2] = toc->first_session;
|
||||
buf[3] = toc->last_session;
|
||||
|
||||
if (start_track < toc->first_session)
|
||||
start_track = toc->first_session;
|
||||
|
||||
int len = 4;
|
||||
for (int i = start_track; i <= toc->last_session; i++) {
|
||||
buf[len++] = 0; // Reserved
|
||||
buf[len++] = toc->trackdesc[i].ctrl_adr ; // ADR, control
|
||||
buf[len++] = i; // Track number
|
||||
buf[len++] = 0; // Reserved
|
||||
|
||||
// Start address
|
||||
if (msf) {
|
||||
buf[len++] = 0; // reserved
|
||||
buf[len++] = toc->trackdesc[i].address.minute;
|
||||
buf[len++] = toc->trackdesc[i].address.second;
|
||||
buf[len++] = toc->trackdesc[i].address.frame;
|
||||
} else {
|
||||
unsigned lba = (unsigned)(MSF_TO_LBA(toc->trackdesc[i].address));
|
||||
buf[len++] = (lba >> 24) & 0xff;
|
||||
buf[len++] = (lba >> 16) & 0xff;
|
||||
buf[len++] = (lba >> 8) & 0xff;
|
||||
buf[len++] = (lba >> 0) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// Lead out track
|
||||
buf[len++] = 0; // Reserved
|
||||
buf[len++] = 0x16; // ADR, control
|
||||
buf[len++] = 0xaa; // Track number
|
||||
buf[len++] = 0; // Reserved
|
||||
|
||||
uint32 blocks = capacity();
|
||||
|
||||
// Start address
|
||||
if (msf) {
|
||||
buf[len++] = 0; // reserved
|
||||
buf[len++] = (uint8)(((blocks + 150) / 75) / 60); // minute
|
||||
buf[len++] = (uint8)(((blocks + 150) / 75) % 60); // second
|
||||
buf[len++] = (uint8)((blocks + 150) % 75); // frame;
|
||||
} else {
|
||||
buf[len++] = (blocks >> 24) & 0xff;
|
||||
buf[len++] = (blocks >> 16) & 0xff;
|
||||
buf[len++] = (blocks >> 8) & 0xff;
|
||||
buf[len++] = (blocks >> 0) & 0xff;
|
||||
}
|
||||
|
||||
buf[0] = ((len-2) >> 8) & 0xff;
|
||||
buf[1] = (len-2) & 0xff;
|
||||
|
||||
*length = len;
|
||||
|
||||
return true;
|
||||
// BX_INFO(( "Read TOC - Not Implemented" ));
|
||||
// return false;
|
||||
}
|
||||
#else
|
||||
BX_INFO(( "Read TOC - Not Implemented" ));
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
BX_INFO(("read_toc: your OS is not supported yet."));
|
||||
return(false); // OS not supported yet, return false always.
|
||||
@ -819,6 +1163,75 @@ cdrom_interface::capacity()
|
||||
return (GetFileSize(hFile, &FileSize) / 2048);
|
||||
}
|
||||
}
|
||||
#elif defined __APPLE__
|
||||
// Find the size of the first data track on the cd. This has produced
|
||||
// the same results as the linux version on every cd I have tried, about
|
||||
// 5. The differences here seem to be that the entries in the TOC when
|
||||
// retrieved from the IOKit interface appear in a reversed order when
|
||||
// compared with the linux READTOCENTRY ioctl.
|
||||
{
|
||||
// Return CD-ROM capacity. I believe you want to return
|
||||
// the number of bytes of capacity the actual media has.
|
||||
|
||||
BX_INFO(( "Capacity" ));
|
||||
|
||||
struct _CDTOC * toc = ReadTOC( CDDevicePath );
|
||||
|
||||
if ( toc == NULL ) {
|
||||
BX_PANIC(( "capacity: Failed to read toc" ));
|
||||
}
|
||||
|
||||
size_t toc_entries = ( toc->length - 2 ) / sizeof( struct _CDTOC_Desc );
|
||||
|
||||
BX_DEBUG(( "reading %d toc entries\n", toc_entries ));
|
||||
|
||||
int start_sector = -1;
|
||||
int data_track = -1;
|
||||
|
||||
// Iterate through the list backward. Pick the first data track and
|
||||
// get the address of the immediately previous (or following depending
|
||||
// on how you look at it). The difference in the sector numbers
|
||||
// is returned as the sized of the data track.
|
||||
for ( int i=toc_entries - 1; i>=0; i-- ) {
|
||||
|
||||
BX_DEBUG(( "session %d ctl_adr %d tno %d point %d lba %d z %d p lba %d\n",
|
||||
(int)toc->trackdesc[i].session,
|
||||
(int)toc->trackdesc[i].ctrl_adr,
|
||||
(int)toc->trackdesc[i].tno,
|
||||
(int)toc->trackdesc[i].point,
|
||||
MSF_TO_LBA( toc->trackdesc[i].address ),
|
||||
(int)toc->trackdesc[i].zero,
|
||||
MSF_TO_LBA(toc->trackdesc[i].p )));
|
||||
|
||||
if ( start_sector != -1 ) {
|
||||
|
||||
start_sector = MSF_TO_LBA(toc->trackdesc[i].p) - start_sector;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (( toc->trackdesc[i].ctrl_adr >> 4) != 1 ) continue;
|
||||
|
||||
if ( toc->trackdesc[i].ctrl_adr & 0x04 ) {
|
||||
|
||||
data_track = toc->trackdesc[i].point;
|
||||
|
||||
start_sector = MSF_TO_LBA(toc->trackdesc[i].p);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free( toc );
|
||||
|
||||
if ( start_sector == -1 ) {
|
||||
start_sector = 0;
|
||||
}
|
||||
|
||||
BX_INFO(("first data track %d data size is %d", data_track, start_sector));
|
||||
|
||||
return start_sector;
|
||||
}
|
||||
#else
|
||||
BX_ERROR(( "capacity: your OS is not supported yet." ));
|
||||
return(0);
|
||||
@ -844,6 +1257,26 @@ cdrom_interface::read_block(uint8* buf, int lba)
|
||||
}
|
||||
ReadFile(hFile, (void *) buf, BX_CD_FRAMESIZE, (unsigned long *) &n, NULL);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#define CD_SEEK_DISTANCE kCDSectorSizeWhole
|
||||
if(using_file)
|
||||
{
|
||||
pos = lseek(fd, lba*BX_CD_FRAMESIZE, SEEK_SET);
|
||||
if (pos < 0) {
|
||||
BX_PANIC(("cdrom: read_block: lseek returned error."));
|
||||
}
|
||||
n = read(fd, buf, BX_CD_FRAMESIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This seek will leave us 16 bytes from the start of the data
|
||||
// hence the magic number.
|
||||
pos = lseek(fd, lba*CD_SEEK_DISTANCE + 16, SEEK_SET);
|
||||
if (pos < 0) {
|
||||
BX_PANIC(("cdrom: read_block: lseek returned error."));
|
||||
}
|
||||
n = read(fd, buf, CD_FRAMESIZE);
|
||||
}
|
||||
#else
|
||||
pos = lseek(fd, lba*BX_CD_FRAMESIZE, SEEK_SET);
|
||||
if (pos < 0) {
|
||||
|
@ -1,489 +0,0 @@
|
||||
// CDROM interface for MacOSX 10+. Uses IOKit facilities
|
||||
// inplace of the ioctl driver interface used by the rest
|
||||
// of the Unixes.
|
||||
//
|
||||
// Features:
|
||||
//
|
||||
// To configure and build with this cdrom interface, configure
|
||||
// with:
|
||||
//
|
||||
// ./configure --enable-cdrom --with-osxcdrom
|
||||
//
|
||||
// On MacOSX the CD device special file -/dev/cdrom,/dev/disk3,etc..., is
|
||||
// determined dynamically by the kernel so the user should not,
|
||||
// theoretically, need to set cdromd in the configuration file. However,
|
||||
// to conform to the existing boch design the user should just add any
|
||||
// file path to keep the core of bochs happy example,
|
||||
//
|
||||
// cdromd: dev=/dev/cdrom, status=inserted
|
||||
//
|
||||
// is fine, even though there is no /dev/cdrom.
|
||||
//
|
||||
// Much of the IOKit code was taken from two sources, "Inside MacOSX:
|
||||
// Accessing Hardware From Applications", a pdf document and the mount
|
||||
// source ("mount_cd9660.c") both of these are available on the
|
||||
// apple website, http://developer.apple.com
|
||||
//
|
||||
// The ::read_toc bochs interface is not implemented. The reason for
|
||||
// this is that at this point we do not have an application that will
|
||||
// excersize this interface. The actual reading of the toc using IOKit
|
||||
// is here and is used to get the size of the data on the cd for
|
||||
// ::capacity. The issue with read_toc is formatting the toc entries to
|
||||
// pass back to bochs.
|
||||
//
|
||||
// The loggin functions are not available outside of the cdrom_interface
|
||||
// class. That is the reason for the printfs in the static functions below.
|
||||
// Each cdrom_interface should inherit from cdrom_interface_base. The methods
|
||||
// that need to be implemented uniquely should be declared virtual in
|
||||
// cdrom_interface_base. cdrom.h needs to be untangled from the rest of
|
||||
// the system for this to work painlessly.
|
||||
//
|
||||
// Scott Brumbaugh <scott@openosx.com> Dec 5, 2001
|
||||
//
|
||||
|
||||
#include "bochs.h"
|
||||
|
||||
#define LOG_THIS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <dev/disk.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 <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
// These definitions were taken from mount_cd9660.c
|
||||
// There are some similar definitions in IOCDTypes.h
|
||||
// however there seems to be some dissagreement in
|
||||
// the definition of CDTOC.length
|
||||
struct _CDMSF {
|
||||
u_char minute;
|
||||
u_char second;
|
||||
u_char frame;
|
||||
};
|
||||
|
||||
#define MSF_TO_LBA(msf) \
|
||||
(((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
|
||||
|
||||
struct _CDTOC_Desc {
|
||||
u_char session;
|
||||
u_char ctrl_adr; /* typed to be machine and compiler independent */
|
||||
u_char tno;
|
||||
u_char point;
|
||||
struct _CDMSF address;
|
||||
u_char zero;
|
||||
struct _CDMSF p;
|
||||
};
|
||||
|
||||
struct _CDTOC {
|
||||
u_short length; /* in native cpu endian */
|
||||
u_char first_session;
|
||||
u_char last_session;
|
||||
struct _CDTOC_Desc trackdesc[1];
|
||||
};
|
||||
|
||||
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator,
|
||||
mach_port_t *masterPort )
|
||||
{
|
||||
kern_return_t kernResult;
|
||||
CFMutableDictionaryRef classesToMatch;
|
||||
kernResult = IOMasterPort( bootstrap_port, masterPort );
|
||||
if ( kernResult != KERN_SUCCESS )
|
||||
{
|
||||
fprintf ( stderr, "IOMasterPort returned %d\n", kernResult );
|
||||
return kernResult;
|
||||
}
|
||||
// CD media are instances of class kIOCDMediaClass.
|
||||
classesToMatch = IOServiceMatching( kIOCDMediaClass );
|
||||
if ( classesToMatch == NULL )
|
||||
fprintf ( stderr, "IOServiceMatching returned a NULL dictionary.\n" );
|
||||
else
|
||||
{
|
||||
// Each IOMedia object has a property with key kIOMediaEjectable
|
||||
// which is true if the media is indeed ejectable. So add property
|
||||
// to CFDictionary for matching.
|
||||
CFDictionarySetValue( classesToMatch,
|
||||
CFSTR( kIOMediaEjectable ), kCFBooleanTrue );
|
||||
}
|
||||
kernResult = IOServiceGetMatchingServices( *masterPort,
|
||||
classesToMatch, mediaIterator );
|
||||
if ( (kernResult != KERN_SUCCESS) || (*mediaIterator == NULL) )
|
||||
fprintf( stderr, "No ejectable CD media found.\n kernResult = %d\n", kernResult );
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
|
||||
static kern_return_t GetDeviceFilePath( io_iterator_t mediaIterator,
|
||||
char *deviceFilePath, CFIndex maxPathSize )
|
||||
{
|
||||
io_object_t nextMedia;
|
||||
kern_return_t kernResult = KERN_FAILURE;
|
||||
nextMedia = IOIteratorNext( mediaIterator );
|
||||
if ( nextMedia == NULL )
|
||||
{
|
||||
*deviceFilePath = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
CFTypeRef deviceFilePathAsCFString;
|
||||
deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(
|
||||
nextMedia, CFSTR( kIOBSDName ),
|
||||
kCFAllocatorDefault, 0 );
|
||||
*deviceFilePath = '\0';
|
||||
if ( deviceFilePathAsCFString )
|
||||
{
|
||||
size_t devPathLength = strlen( _PATH_DEV );
|
||||
strcpy( deviceFilePath, _PATH_DEV );
|
||||
if ( CFStringGetCString( (const __CFString *) deviceFilePathAsCFString,
|
||||
deviceFilePath + devPathLength,
|
||||
maxPathSize - devPathLength,
|
||||
kCFStringEncodingASCII ) )
|
||||
{
|
||||
// fprintf( stderr, "BSD path: %s\n", deviceFilePath );
|
||||
kernResult = KERN_SUCCESS;
|
||||
}
|
||||
CFRelease( deviceFilePathAsCFString );
|
||||
}
|
||||
}
|
||||
IOObjectRelease( nextMedia );
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
|
||||
static int OpenDrive( const char *deviceFilePath )
|
||||
{
|
||||
|
||||
int fileDescriptor;
|
||||
|
||||
fileDescriptor = open( deviceFilePath, O_RDONLY );
|
||||
if ( fileDescriptor == -1 )
|
||||
fprintf( stderr, "Error %d opening device %s.\n", errno, deviceFilePath );
|
||||
return fileDescriptor;
|
||||
|
||||
}
|
||||
|
||||
static struct _CDTOC * ReadTOC( const char * devpath ) {
|
||||
|
||||
struct _CDTOC * toc_p = NULL;
|
||||
io_iterator_t iterator = 0;
|
||||
io_registry_entry_t service = 0;
|
||||
CFDictionaryRef properties = 0;
|
||||
CFDataRef data = 0;
|
||||
mach_port_t port = 0;
|
||||
char * devname;
|
||||
|
||||
if (( devname = strrchr( devpath, '/' )) != NULL ) {
|
||||
++devname;
|
||||
}
|
||||
else {
|
||||
devname = (char *) devpath;
|
||||
}
|
||||
|
||||
if ( IOMasterPort(bootstrap_port, &port ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IOMasterPort failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( IOServiceGetMatchingServices( port, IOBSDNameMatching( port, 0, devname ),
|
||||
&iterator ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IOServiceGetMatchingServices failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
service = IOIteratorNext( iterator );
|
||||
|
||||
IOObjectRelease( iterator );
|
||||
|
||||
iterator = 0;
|
||||
|
||||
while ( service && !IOObjectConformsTo( service, "IOCDMedia" )) {
|
||||
if ( IORegistryEntryGetParentIterator( service, kIOServicePlane,
|
||||
&iterator ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
IOObjectRelease( service );
|
||||
service = IOIteratorNext( iterator );
|
||||
IOObjectRelease( iterator );
|
||||
|
||||
}
|
||||
|
||||
if ( service == NULL ) {
|
||||
fprintf( stderr, "CD media not found\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( IORegistryEntryCreateCFProperties( service, (__CFDictionary **) &properties,
|
||||
kCFAllocatorDefault,
|
||||
kNilOptions ) != KERN_SUCCESS ) {
|
||||
fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
data = (CFDataRef) CFDictionaryGetValue( properties, CFSTR("TOC") );
|
||||
if ( data == NULL ) {
|
||||
fprintf( stderr, "CFDictionaryGetValue failed\n" );
|
||||
goto Exit;
|
||||
}
|
||||
else {
|
||||
|
||||
CFRange range;
|
||||
CFIndex buflen;
|
||||
|
||||
buflen = CFDataGetLength( data ) + 1;
|
||||
range = CFRangeMake( 0, buflen );
|
||||
toc_p = (struct _CDTOC *) malloc( buflen );
|
||||
if ( toc_p == NULL ) {
|
||||
fprintf( stderr, "Out of memory\n" );
|
||||
goto Exit;
|
||||
}
|
||||
else {
|
||||
CFDataGetBytes( data, range, (unsigned char *) toc_p );
|
||||
}
|
||||
|
||||
/*
|
||||
fprintf( stderr, "Table of contents\n length %d first %d last %d\n",
|
||||
toc_p->length, toc_p->first_session, toc_p->last_session );
|
||||
*/
|
||||
|
||||
CFRelease( properties );
|
||||
|
||||
}
|
||||
|
||||
|
||||
Exit:
|
||||
|
||||
if ( service ) {
|
||||
IOObjectRelease( service );
|
||||
}
|
||||
|
||||
return toc_p;
|
||||
|
||||
}
|
||||
|
||||
static char CDDevicePath[ MAXPATHLEN ];
|
||||
|
||||
cdrom_interface::cdrom_interface(char *dev)
|
||||
{
|
||||
put("CD");
|
||||
settype(CDLOG);
|
||||
fd = -1; // File descriptor not yet allocated
|
||||
|
||||
if ( dev == NULL )
|
||||
path = NULL;
|
||||
else {
|
||||
path = strdup(dev);
|
||||
}
|
||||
using_file=0;
|
||||
}
|
||||
|
||||
void
|
||||
cdrom_interface::init(void) {
|
||||
BX_DEBUG(("cdrom_osx.cc,v 0.1 2001/12/5 sbrumbaugh scott@openosx.com"));
|
||||
BX_INFO(("file = '%s'",path));
|
||||
}
|
||||
|
||||
cdrom_interface::~cdrom_interface(void)
|
||||
{
|
||||
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (path)
|
||||
free(path);
|
||||
BX_DEBUG(("Exit"));
|
||||
|
||||
}
|
||||
|
||||
bx_bool
|
||||
cdrom_interface::insert_cdrom(char *dev)
|
||||
{
|
||||
|
||||
mach_port_t masterPort = NULL;
|
||||
io_iterator_t mediaIterator;
|
||||
kern_return_t kernResult;
|
||||
|
||||
BX_INFO(( "Insert CDROM" ));
|
||||
|
||||
kernResult = FindEjectableCDMedia( &mediaIterator, &masterPort );
|
||||
if ( kernResult != KERN_SUCCESS ) {
|
||||
BX_INFO (("Unable to find CDROM"));
|
||||
return false;
|
||||
}
|
||||
|
||||
kernResult = GetDeviceFilePath( mediaIterator, CDDevicePath, sizeof( CDDevicePath ) );
|
||||
if ( kernResult != KERN_SUCCESS ) {
|
||||
BX_INFO (("Unable to get CDROM device file path" ));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here a cdrom was found so see if we can read from it.
|
||||
// At this point a failure will result in panic.
|
||||
if ( strlen( CDDevicePath ) ) {
|
||||
|
||||
fd = OpenDrive( CDDevicePath );
|
||||
|
||||
if ( fd < 0 ) {
|
||||
BX_PANIC(( "Unable to open CDROM" ));
|
||||
}
|
||||
|
||||
// read a test track
|
||||
char buffer[2048];
|
||||
|
||||
if ( read( fd, buffer, 2048 ) == -1 ) {
|
||||
BX_PANIC(( "Unable to read from CDROM error %d", errno ));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BX_INFO(( "Found CD at %s opened on descriptor %d", CDDevicePath, fd ));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_interface::eject_cdrom()
|
||||
{
|
||||
|
||||
// Logically eject the CD. I suppose we could stick in
|
||||
// some ioctl() calls to really eject the CD as well.
|
||||
|
||||
BX_INFO(( "Eject" ));
|
||||
close(fd);
|
||||
fd = -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bx_bool
|
||||
cdrom_interface::read_toc(uint8* buf, int* length, bx_bool msf, int start_track)
|
||||
{
|
||||
// Read CD TOC. Returns false if start track is out of bounds.
|
||||
|
||||
BX_INFO(( "Read TOC - Not Implemented" ));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Find the size of the first data track on the cd. This has produced
|
||||
// the same results as the linux version on every cd I have tried, about
|
||||
// 5. The differences here seem to be that the entries in the TOC when
|
||||
// retrieved from the IOKit interface appear in a reversed order when
|
||||
// compared with the linux READTOCENTRY ioctl.
|
||||
uint32
|
||||
cdrom_interface::capacity()
|
||||
{
|
||||
|
||||
// Return CD-ROM capacity. I believe you want to return
|
||||
// the number of bytes of capacity the actual media has.
|
||||
|
||||
BX_INFO(( "Capacity" ));
|
||||
|
||||
struct _CDTOC * toc = ReadTOC( CDDevicePath );
|
||||
|
||||
if ( toc == NULL ) {
|
||||
BX_PANIC(( "capacity: Failed to read toc" ));
|
||||
}
|
||||
|
||||
size_t toc_entries = ( toc->length - 2 ) / sizeof( struct _CDTOC_Desc );
|
||||
|
||||
BX_DEBUG(( "reading %d toc entries\n", toc_entries ));
|
||||
|
||||
int start_sector = -1;
|
||||
int data_track = -1;
|
||||
|
||||
// Iterate through the list backward. Pick the first data track and
|
||||
// get the address of the immediately previous (or following depending
|
||||
// on how you look at it). The difference in the sector numbers
|
||||
// is returned as the sized of the data track.
|
||||
for ( int i=toc_entries - 1; i>=0; i-- ) {
|
||||
|
||||
BX_DEBUG(( "session %d ctl_adr %d tno %d point %d lba %d z %d p lba %d\n",
|
||||
(int)toc->trackdesc[i].session,
|
||||
(int)toc->trackdesc[i].ctrl_adr,
|
||||
(int)toc->trackdesc[i].tno,
|
||||
(int)toc->trackdesc[i].point,
|
||||
MSF_TO_LBA( toc->trackdesc[i].address ),
|
||||
(int)toc->trackdesc[i].zero,
|
||||
MSF_TO_LBA(toc->trackdesc[i].p )));
|
||||
|
||||
if ( start_sector != -1 ) {
|
||||
|
||||
start_sector = MSF_TO_LBA(toc->trackdesc[i].p) - start_sector;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (( toc->trackdesc[i].ctrl_adr >> 4) != 1 ) continue;
|
||||
|
||||
if ( toc->trackdesc[i].ctrl_adr & 0x04 ) {
|
||||
|
||||
data_track = toc->trackdesc[i].point;
|
||||
|
||||
start_sector = MSF_TO_LBA(toc->trackdesc[i].p);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free( toc );
|
||||
|
||||
if ( start_sector == -1 ) {
|
||||
start_sector = 0;
|
||||
}
|
||||
|
||||
BX_INFO(("first data track %d data size is %d", data_track, start_sector));
|
||||
|
||||
return start_sector;
|
||||
|
||||
}
|
||||
|
||||
#define CD_FRAMESIZE (2048)
|
||||
#define CD_SEEK_DISTANCE kCDSectorSizeWhole
|
||||
|
||||
// The seeks on the CD need to be measured with kCDSectorSizeWhole which is
|
||||
// defined to be 2352 or close. We then need to jump ahead 16 bytes to the
|
||||
// data and read out the next 2048 as the data.
|
||||
void
|
||||
cdrom_interface::read_block(uint8* buf, int lba)
|
||||
{
|
||||
// Read a single block from the CD
|
||||
|
||||
off_t pos;
|
||||
ssize_t n;
|
||||
|
||||
// This seek will leave us 16 bytes from the start of the data
|
||||
// hence the magic number.
|
||||
pos = lseek(fd, lba*CD_SEEK_DISTANCE + 16, SEEK_SET);
|
||||
if (pos < 0) {
|
||||
BX_PANIC(("cdrom: read_block: lseek returned error."));
|
||||
}
|
||||
n = read(fd, buf, CD_FRAMESIZE);
|
||||
|
||||
if (n != CD_FRAMESIZE) {
|
||||
BX_PANIC(("cdrom: read_block: read returned %d",
|
||||
(int) n));
|
||||
}
|
||||
|
||||
/*
|
||||
for (int i=0; i<CD_FRAMESIZE; i++) {
|
||||
printf (" %2X", buf[i] );
|
||||
}
|
||||
printf ("\n");
|
||||
*/
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user