diff options
Diffstat (limited to 'src/input/vcd/libcdio/_cdio_osx.c')
-rw-r--r-- | src/input/vcd/libcdio/_cdio_osx.c | 1199 |
1 files changed, 876 insertions, 323 deletions
diff --git a/src/input/vcd/libcdio/_cdio_osx.c b/src/input/vcd/libcdio/_cdio_osx.c index 3e479f76d..f754933c6 100644 --- a/src/input/vcd/libcdio/_cdio_osx.c +++ b/src/input/vcd/libcdio/_cdio_osx.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_osx.c,v 1.3 2004/10/20 05:04:00 athp Exp $ + $Id: _cdio_osx.c,v 1.4 2005/01/01 02:43:57 rockyb Exp $ Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com> from vcdimager code: @@ -9,6 +9,7 @@ Gildas Bazin <gbazin@netcourrier.com> Jon Lech Johansen <jon-vl@nanocrew.net> Derk-Jan Hartman <hartman at videolan.org> + Justin F. Hallett <thesin@southofheaven.org> 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 @@ -30,11 +31,12 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif -static const char _rcsid[] = "$Id: _cdio_osx.c,v 1.3 2004/10/20 05:04:00 athp Exp $"; +static const char _rcsid[] = "$Id: _cdio_osx.c,v 1.4 2005/01/01 02:43:57 rockyb Exp $"; +#include <cdio/logging.h> #include <cdio/sector.h> #include <cdio/util.h> #include "cdio_assert.h" @@ -43,6 +45,17 @@ static const char _rcsid[] = "$Id: _cdio_osx.c,v 1.3 2004/10/20 05:04:00 athp Ex #include <string.h> #ifdef HAVE_DARWIN_CDROM +#undef VERSION + +#include <CoreFoundation/CoreFoundation.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/storage/IOStorageDeviceCharacteristics.h> + +#include <mach/mach.h> +#include <Carbon/Carbon.h> +#include <IOKit/scsi-commands/SCSITaskLib.h> +#include <IOKit/IOCFPlugIn.h> +#include <mach/mach_error.h> #include <stdio.h> #include <stdlib.h> @@ -54,72 +67,575 @@ static const char _rcsid[] = "$Id: _cdio_osx.c,v 1.3 2004/10/20 05:04:00 athp Ex #include <sys/types.h> #include <sys/ioctl.h> + #include <paths.h> -#include <CoreFoundation/CFBase.h> -#include <CoreFoundation/CFString.h> -#include <CoreFoundation/CFNumber.h> +#include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> #include <IOKit/IOBSD.h> +#include <IOKit/scsi-commands/IOSCSIMultimediaCommandsDevice.h> #include <IOKit/storage/IOCDTypes.h> +#include <IOKit/storage/IODVDTypes.h> #include <IOKit/storage/IOMedia.h> #include <IOKit/storage/IOCDMedia.h> +#include <IOKit/storage/IODVDMedia.h> #include <IOKit/storage/IOCDMediaBSDClient.h> +#include <IOKit/storage/IODVDMediaBSDClient.h> +#include <IOKit/storage/IOStorageDeviceCharacteristics.h> + +#define kIOCDBlockStorageDeviceClassString "IOCDBlockStorageDevice" + +/* Note leadout is normally defined 0xAA, But on OSX 0xA0 is "lead in" while + 0xA2 is "lead out". Don't ask me why. */ +#define OSX_CDROM_LEADOUT_TRACK 0xA2 -#define TOTAL_TRACKS (_obj->num_tracks) +#define TOTAL_TRACKS (p_env->i_last_track - p_env->gen.i_first_track + 1) +#define CDROM_CDI_TRACK 0x1 +#define CDROM_XA_TRACK 0x2 + +typedef enum { + _AM_NONE, + _AM_OSX, +} access_mode_t; + +#define MAX_SERVICE_NAME 1000 typedef struct { /* Things common to all drivers like this. This must be first. */ generic_img_private_t gen; - enum { - _AM_NONE, - _AM_OSX, - } access_mode; + access_mode_t access_mode; /* Track information */ - bool toc_init; /* if true, info below is valid. */ CDTOC *pTOC; int i_descriptors; - track_t num_tracks; + track_t i_last_track; /* highest track number */ + track_t i_last_session; /* highest session number */ + track_t i_first_session; /* first session number */ lsn_t *pp_lba; + io_service_t MediaClass_service; + char psz_MediaClass_service[MAX_SERVICE_NAME]; + SCSITaskDeviceInterface **pp_scsiTaskDeviceInterface; } _img_private_t; -static void -_cdio_osx_free (void *env) { - _img_private_t *_obj = env; - if (NULL == _obj) return; - cdio_generic_free(_obj); - if (NULL != _obj->pp_lba) free((void *) _obj->pp_lba); - if (NULL != _obj->pTOC) free((void *) _obj->pTOC); +static bool read_toc_osx (void *p_user_data); + +/**** + * GetRegistryEntryProperties - Gets the registry entry properties for + * an io_service_t. + *****/ + +static CFMutableDictionaryRef +GetRegistryEntryProperties ( io_service_t service ) +{ + IOReturn err = kIOReturnSuccess; + CFMutableDictionaryRef dict = 0; + + err = IORegistryEntryCreateCFProperties (service, &dict, kCFAllocatorDefault, 0); + if ( err != kIOReturnSuccess ) + cdio_warn( "IORegistryEntryCreateCFProperties: 0x%08x", err ); + + return dict; } -/**************************************************************************** - cdio_getNumberOfTracks: get number of tracks in TOC - This is an internal routine and is called once per CD open. - ****************************************************************************/ -static track_t -_cdio_getNumberOfTracks( CDTOC *pTOC, int i_descriptors ) + +static bool +init_osx(_img_private_t *p_env) { + mach_port_t port; + char *psz_devname; + kern_return_t ret; + io_iterator_t iterator; + + p_env->gen.fd = open( p_env->gen.source_name, O_RDONLY | O_NONBLOCK ); + if (-1 == p_env->gen.fd) { + cdio_warn("Failed to open %s: %s", p_env->gen.source_name, + strerror(errno)); + return false; + } + + /* get the device name */ + psz_devname = strrchr( p_env->gen.source_name, '/'); + if( NULL != psz_devname ) + ++psz_devname; + else + psz_devname = p_env->gen.source_name; + + /* unraw the device name */ + if( *psz_devname == 'r' ) + ++psz_devname; + + /* get port for IOKit communication */ + ret = IOMasterPort( MACH_PORT_NULL, &port ); + + if( ret != KERN_SUCCESS ) + { + cdio_warn( "IOMasterPort: 0x%08x", ret ); + return false; + } + + ret = IOServiceGetMatchingServices( port, + IOBSDNameMatching(port, 0, psz_devname), + &iterator ); + + /* get service iterator for the device */ + if( ret != KERN_SUCCESS ) + { + cdio_warn( "IOServiceGetMatchingServices: 0x%08x", ret ); + return false; + } + + /* first service */ + p_env->MediaClass_service = IOIteratorNext( iterator ); + IOObjectRelease( iterator ); + + /* search for kIOCDMediaClass or kIOCDVDMediaClass */ + while( p_env->MediaClass_service && + (!IOObjectConformsTo(p_env->MediaClass_service, kIOCDMediaClass)) && + (!IOObjectConformsTo(p_env->MediaClass_service, kIODVDMediaClass)) ) + { + + ret = IORegistryEntryGetParentIterator( p_env->MediaClass_service, + kIOServicePlane, + &iterator ); + if( ret != KERN_SUCCESS ) + { + cdio_warn( "IORegistryEntryGetParentIterator: 0x%08x", ret ); + IOObjectRelease( p_env->MediaClass_service ); + return false; + } + + IOObjectRelease( p_env->MediaClass_service ); + p_env->MediaClass_service = IOIteratorNext( iterator ); + IOObjectRelease( iterator ); + } + + if ( 0 == p_env->MediaClass_service ) { + cdio_warn( "search for kIOCDMediaClass/kIODVDMediaClass came up empty" ); + return false; + } + + /* Save the name so we can compare against this in case we have to do + another scan. FIXME: this is hoaky and there's got to be a better + variable to test or way to do. + */ + IORegistryEntryGetPath(p_env->MediaClass_service, kIOServicePlane, + p_env->psz_MediaClass_service); + return true; +} + +/*! + Run a SCSI MMC command. + + cdio CD structure set by cdio_open(). + i_timeout time in milliseconds we will wait for the command + to complete. If this value is -1, use the default + time-out value. + p_buf Buffer for data, both sending and receiving + i_buf Size of buffer + e_direction direction the transfer is to go. + cdb CDB bytes. All values that are needed should be set on + input. We'll figure out what the right CDB length should be. + + We return true if command completed successfully and false if not. + */ +static int +run_scsi_cmd_osx( const void *p_user_data, + unsigned int i_timeout_ms, + unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb, + scsi_mmc_direction_t e_direction, + unsigned int i_buf, /*in/out*/ void *p_buf ) { - track_t track = CDIO_INVALID_TRACK; - int i; - int i_tracks = 0; - CDTOCDescriptor *pTrackDescriptors; - pTrackDescriptors = pTOC->descriptors; +#ifndef SCSI_MMC_FIXED + return 2; +#else + const _img_private_t *p_env = p_user_data; + SCSITaskDeviceInterface **sc; + SCSITaskInterface **cmd = NULL; + IOVirtualRange iov; + SCSI_Sense_Data senseData; + SCSITaskStatus status; + UInt64 bytesTransferred; + IOReturn ioReturnValue; + int ret = 0; + + if (NULL == p_user_data) return 2; + + /* Make sure pp_scsiTaskDeviceInterface is initialized. FIXME: The code + should probably be reorganized better for this. */ + if (!p_env->gen.toc_init) read_toc_osx (p_user_data) ; + + sc = p_env->pp_scsiTaskDeviceInterface; + + if (NULL == sc) return 3; + + cmd = (*sc)->CreateSCSITask(sc); + if (cmd == NULL) { + cdio_warn("Failed to create SCSI task"); + return -1; + } + + iov.address = (IOVirtualAddress) p_buf; + iov.length = i_buf; + + ioReturnValue = (*cmd)->SetCommandDescriptorBlock(cmd, (UInt8 *) p_cdb, + i_cdb); + if (ioReturnValue != kIOReturnSuccess) { + cdio_warn("SetCommandDescriptorBlock failed with status %x", + ioReturnValue); + return -1; + } + + ioReturnValue = (*cmd)->SetScatterGatherEntries(cmd, &iov, 1, i_buf, + (SCSI_MMC_DATA_READ == e_direction ) ? + kSCSIDataTransfer_FromTargetToInitiator : + kSCSIDataTransfer_FromInitiatorToTarget); + if (ioReturnValue != kIOReturnSuccess) { + cdio_warn("SetScatterGatherEntries failed with status %x", ioReturnValue); + return -1; + } + + ioReturnValue = (*cmd)->SetTimeoutDuration(cmd, i_timeout_ms ); + if (ioReturnValue != kIOReturnSuccess) { + cdio_warn("SetTimeoutDuration failed with status %x", ioReturnValue); + return -1; + } + + memset(&senseData, 0, sizeof(senseData)); - for( i = i_descriptors; i >= 0; i-- ) + ioReturnValue = (*cmd)->ExecuteTaskSync(cmd,&senseData, &status, & + bytesTransferred); + + if (ioReturnValue != kIOReturnSuccess) { + cdio_warn("Command execution failed with status %x", ioReturnValue); + return -1; + } + + if (cmd != NULL) { + (*cmd)->Release(cmd); + } + + return (ret); +#endif +} + +/*************************************************************************** + * GetDeviceIterator - Gets an io_iterator_t for our class type + ***************************************************************************/ + +static io_iterator_t +GetDeviceIterator ( const char * deviceClass ) +{ + + IOReturn err = kIOReturnSuccess; + io_iterator_t iterator = MACH_PORT_NULL; + + err = IOServiceGetMatchingServices ( kIOMasterPortDefault, + IOServiceMatching ( deviceClass ), + &iterator ); + check ( err == kIOReturnSuccess ); + + return iterator; + +} + +/*************************************************************************** + * GetFeaturesFlagsForDrive -Gets the bitfield which represents the + * features flags. + ***************************************************************************/ + +static bool +GetFeaturesFlagsForDrive ( CFDictionaryRef dict, + uint32_t *i_cdFlags, + uint32_t *i_dvdFlags ) +{ + CFDictionaryRef propertiesDict = 0; + CFNumberRef flagsNumberRef = 0; + + *i_cdFlags = 0; + *i_dvdFlags= 0; + + propertiesDict = ( CFDictionaryRef ) + CFDictionaryGetValue ( dict, + CFSTR ( kIOPropertyDeviceCharacteristicsKey ) ); + + if ( propertiesDict == 0 ) return false; + + /* Get the CD features */ + flagsNumberRef = ( CFNumberRef ) + CFDictionaryGetValue ( propertiesDict, + CFSTR ( kIOPropertySupportedCDFeatures ) ); + if ( flagsNumberRef != 0 ) { + CFNumberGetValue ( flagsNumberRef, kCFNumberLongType, i_cdFlags ); + } + + /* Get the DVD features */ + flagsNumberRef = ( CFNumberRef ) + CFDictionaryGetValue ( propertiesDict, + CFSTR ( kIOPropertySupportedDVDFeatures ) ); + if ( flagsNumberRef != 0 ) { + CFNumberGetValue ( flagsNumberRef, kCFNumberLongType, i_dvdFlags ); + } + + return true; +} + +/*! + Get disc type associated with the cd object. +*/ +static discmode_t +get_discmode_osx (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + char str[10]; + int32_t i_discmode = CDIO_DISC_MODE_ERROR; + CFDictionaryRef propertiesDict = 0; + CFStringRef data; + + propertiesDict = GetRegistryEntryProperties ( p_env->MediaClass_service ); + + if ( propertiesDict == 0 ) return i_discmode; + + data = ( CFStringRef ) + CFDictionaryGetValue ( propertiesDict, CFSTR ( kIODVDMediaTypeKey ) ); + + if( CFStringGetCString( data, str, sizeof(str), + kCFStringEncodingASCII ) ) { + if (0 == strncmp(str, "DVD+R", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_DVD_PR; + else if (0 == strncmp(str, "DVD+RW", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_DVD_PRW; + else if (0 == strncmp(str, "DVD-R", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_DVD_R; + else if (0 == strncmp(str, "DVD-RW", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_DVD_RW; + else if (0 == strncmp(str, "DVD-ROM", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_DVD_ROM; + else if (0 == strncmp(str, "DVD-RAM", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_DVD_RAM; + else if (0 == strncmp(str, "CD-ROM", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_CD_DATA; + else if (0 == strncmp(str, "CDR", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_CD_DATA; + else if (0 == strncmp(str, "CDRW", strlen(str)) ) + i_discmode = CDIO_DISC_MODE_CD_DATA; + //?? Handled by below? CFRelease( data ); + } + CFRelease( propertiesDict ); + if (CDIO_DISC_MODE_CD_DATA == i_discmode) { + /* Need to do more classification */ + return get_discmode_cd_generic(p_user_data); + } + return i_discmode; + +} + +static io_service_t +get_drive_service_osx(const _img_private_t *p_env) +{ + io_service_t service; + io_iterator_t service_iterator; + + service_iterator = GetDeviceIterator ( kIOCDBlockStorageDeviceClassString ); + + if( service_iterator == MACH_PORT_NULL ) return 0; + + service = IOIteratorNext( service_iterator ); + if( service == 0 ) return 0; + + do { - track = pTrackDescriptors[i].point; + char psz_service[MAX_SERVICE_NAME]; + IORegistryEntryGetPath(service, kIOServicePlane, psz_service); + psz_service[MAX_SERVICE_NAME-1] = '\0'; + + /* FIXME: This is all hoaky. Here we need info from a parent class, + psz_service of what we opened above. We are relying on the + fact that the name will be a substring of the name we + openned with. + */ + if (0 == strncmp(psz_service, p_env->psz_MediaClass_service, + strlen(psz_service))) { + /* Found our device */ + IOObjectRelease( service_iterator ); + return service; + } + + IOObjectRelease( service ); + + } while( ( service = IOIteratorNext( service_iterator ) ) != 0 ); - if( track > CDIO_CD_MAX_TRACKS || track < CDIO_CD_MIN_TRACK_NO ) - continue; + IOObjectRelease( service_iterator ); + return service; +} - i_tracks++; +static void +get_drive_cap_osx(const void *p_user_data, + /*out*/ cdio_drive_read_cap_t *p_read_cap, + /*out*/ cdio_drive_write_cap_t *p_write_cap, + /*out*/ cdio_drive_misc_cap_t *p_misc_cap) +{ + const _img_private_t *p_env = p_user_data; + uint32_t i_cdFlags; + uint32_t i_dvdFlags; + + io_service_t service = get_drive_service_osx(p_env); + + if( service == 0 ) goto err_exit; + + /* Found our device */ + { + CFDictionaryRef properties = GetRegistryEntryProperties ( service ); + + if (! GetFeaturesFlagsForDrive ( properties, &i_cdFlags, + &i_dvdFlags ) ) { + IOObjectRelease( service ); + goto err_exit; } + + /* Reader */ + + if ( 0 != (i_cdFlags & kCDFeaturesAnalogAudioMask) ) + *p_read_cap |= CDIO_DRIVE_CAP_READ_AUDIO; + + if ( 0 != (i_cdFlags & kCDFeaturesWriteOnceMask) ) + *p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_R; + + if ( 0 != (i_cdFlags & kCDFeaturesCDDAStreamAccurateMask) ) + *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_DA; + + if ( 0 != (i_dvdFlags & kDVDFeaturesReadStructuresMask) ) + *p_read_cap |= CDIO_DRIVE_CAP_READ_DVD_ROM; + + if ( 0 != (i_cdFlags & kCDFeaturesReWriteableMask) ) + *p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_RW; + + if ( 0 != (i_dvdFlags & kDVDFeaturesWriteOnceMask) ) + *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_R; + + if ( 0 != (i_dvdFlags & kDVDFeaturesRandomWriteableMask) ) + *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_RAM; + + if ( 0 != (i_dvdFlags & kDVDFeaturesReWriteableMask) ) + *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_RW; + + /*** + if ( 0 != (i_dvdFlags & kDVDFeaturesPlusRMask) ) + *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_PR; + + if ( 0 != (i_dvdFlags & kDVDFeaturesPlusRWMask ) + *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_PRW; + ***/ + + /* FIXME: fill out. For now assume CD-ROM is relatively modern. */ + *p_misc_cap = ( + CDIO_DRIVE_CAP_MISC_CLOSE_TRAY + | CDIO_DRIVE_CAP_MISC_EJECT + | CDIO_DRIVE_CAP_MISC_LOCK + | CDIO_DRIVE_CAP_MISC_SELECT_SPEED + | CDIO_DRIVE_CAP_MISC_MULTI_SESSION + | CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED + | CDIO_DRIVE_CAP_MISC_RESET + | CDIO_DRIVE_CAP_MCN + | CDIO_DRIVE_CAP_ISRC + ); + + IOObjectRelease( service ); + } + + return; + + err_exit: + *p_misc_cap = *p_write_cap = *p_read_cap = CDIO_DRIVE_CAP_UNKNOWN; + return; +} + +#if 1 +/**************************************************************************** + * GetDriveDescription - Gets drive description. + ****************************************************************************/ + +static bool +get_hwinfo_osx ( const CdIo *p_cdio, /*out*/ cdio_hwinfo_t *hw_info) +{ + _img_private_t *p_env = (_img_private_t *) p_cdio->env; + io_service_t service = get_drive_service_osx(p_env); + + if ( service == 0 ) return false; + + /* Found our device */ + { + CFStringRef vendor = NULL; + CFStringRef product = NULL; + CFStringRef revision = NULL; + + CFDictionaryRef properties = GetRegistryEntryProperties ( service ); + CFDictionaryRef deviceDict = ( CFDictionaryRef ) + CFDictionaryGetValue ( properties, + CFSTR ( kIOPropertyDeviceCharacteristicsKey ) ); + + if ( deviceDict == 0 ) return false; + + vendor = ( CFStringRef ) + CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyVendorNameKey ) ); + + if ( CFStringGetCString( vendor, + (char *) &(hw_info->psz_vendor), + sizeof(hw_info->psz_vendor), + kCFStringEncodingASCII ) ) + CFRelease( vendor ); + + product = ( CFStringRef ) + CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyProductNameKey ) ); + + if ( CFStringGetCString( product, + (char *) &(hw_info->psz_model), + sizeof(hw_info->psz_model), + kCFStringEncodingASCII ) ) + CFRelease( product ); + + revision = ( CFStringRef ) + CFDictionaryGetValue ( deviceDict, + CFSTR ( kIOPropertyProductRevisionLevelKey ) ); + + if ( CFStringGetCString( product, + (char *) &(hw_info->psz_revision), + sizeof(hw_info->psz_revision), + kCFStringEncodingASCII ) ) + CFRelease( revision ); + } + return true; + +} +#endif + +/*! + Return the media catalog number MCN. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +static const cdtext_t * +get_cdtext_osx (void *p_user_data, track_t i_track) +{ + return NULL; +} + +static void +_free_osx (void *p_user_data) { + _img_private_t *p_env = p_user_data; + if (NULL == p_env) return; + cdio_generic_free(p_env); + if (NULL != p_env->pp_lba) free((void *) p_env->pp_lba); + if (NULL != p_env->pTOC) free((void *) p_env->pTOC); + IOObjectRelease( p_env->MediaClass_service ); + + if (NULL != p_env->pp_scsiTaskDeviceInterface) + ( *(p_env->pp_scsiTaskDeviceInterface) )-> + Release ( (p_env->pp_scsiTaskDeviceInterface) ); - return( i_tracks ); } /*! @@ -128,10 +644,10 @@ _cdio_getNumberOfTracks( CDTOC *pTOC, int i_descriptors ) Returns 0 if no error. */ static int -_cdio_read_mode1_sectors (void *env, void *data, lsn_t lsn, - bool is_form2, unsigned int nblocks) +_get_read_mode1_sectors_osx (void *user_data, void *data, lsn_t lsn, + bool b_form2, unsigned int nblocks) { - _img_private_t *_obj = env; + _img_private_t *env = user_data; dk_cd_read_t cd_read; memset( &cd_read, 0, sizeof(cd_read) ); @@ -140,7 +656,7 @@ _cdio_read_mode1_sectors (void *env, void *data, lsn_t lsn, cd_read.buffer = data; cd_read.sectorType = kCDSectorTypeMode1; - if (is_form2) { + if (b_form2) { cd_read.offset = lsn * kCDSectorSizeMode2; cd_read.bufferLength = kCDSectorSizeMode2 * nblocks; } else { @@ -148,9 +664,9 @@ _cdio_read_mode1_sectors (void *env, void *data, lsn_t lsn, cd_read.bufferLength = kCDSectorSizeMode1 * nblocks; } - if( ioctl( _obj->gen.fd, DKIOCCDREAD, &cd_read ) == -1 ) + if( ioctl( env->gen.fd, DKIOCCDREAD, &cd_read ) == -1 ) { - cdio_error( "could not read block %d, %s", lsn, strerror(errno) ); + cdio_info( "could not read block %d, %s", lsn, strerror(errno) ); return -1; } return 0; @@ -163,10 +679,10 @@ _cdio_read_mode1_sectors (void *env, void *data, lsn_t lsn, Returns 0 if no error. */ static int -_cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, - bool is_form2, unsigned int nblocks) +_get_read_mode2_sectors_osx (void *user_data, void *data, lsn_t lsn, + bool b_form2, unsigned int nblocks) { - _img_private_t *_obj = env; + _img_private_t *env = user_data; dk_cd_read_t cd_read; memset( &cd_read, 0, sizeof(cd_read) ); @@ -174,7 +690,7 @@ _cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, cd_read.sectorArea = kCDSectorAreaUser; cd_read.buffer = data; - if (is_form2) { + if (b_form2) { cd_read.offset = lsn * kCDSectorSizeMode2Form2; cd_read.sectorType = kCDSectorTypeMode2Form2; cd_read.bufferLength = kCDSectorSizeMode2Form2 * nblocks; @@ -184,9 +700,9 @@ _cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, cd_read.bufferLength = kCDSectorSizeMode2Form1 * nblocks; } - if( ioctl( _obj->gen.fd, DKIOCCDREAD, &cd_read ) == -1 ) + if( ioctl( env->gen.fd, DKIOCCDREAD, &cd_read ) == -1 ) { - cdio_error( "could not read block %d, %s", lsn, strerror(errno) ); + cdio_info( "could not read block %d, %s", lsn, strerror(errno) ); return -1; } return 0; @@ -198,24 +714,24 @@ _cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, Returns 0 if no error. */ static int -_cdio_read_audio_sectors (void *env, void *data, lsn_t lsn, - unsigned int nblocks) +_get_read_audio_sectors_osx (void *user_data, void *data, lsn_t lsn, + unsigned int nblocks) { - _img_private_t *_obj = env; + _img_private_t *env = user_data; dk_cd_read_t cd_read; memset( &cd_read, 0, sizeof(cd_read) ); - cd_read.offset = lsn * kCDSectorSizeCDDA; - cd_read.sectorArea = kCDSectorAreaUser; - cd_read.sectorType = kCDSectorTypeCDDA; + cd_read.offset = lsn * kCDSectorSizeCDDA; + cd_read.sectorArea = kCDSectorAreaUser; + cd_read.sectorType = kCDSectorTypeCDDA; - cd_read.buffer = data; + cd_read.buffer = data; cd_read.bufferLength = kCDSectorSizeCDDA * nblocks; - if( ioctl( _obj->gen.fd, DKIOCCDREAD, &cd_read ) == -1 ) + if( ioctl( env->gen.fd, DKIOCCDREAD, &cd_read ) == -1 ) { - cdio_error( "could not read block %d", lsn ); + cdio_info( "could not read block %d", lsn ); return -1; } return 0; @@ -226,10 +742,10 @@ _cdio_read_audio_sectors (void *env, void *data, lsn_t lsn, from lsn. Returns 0 if no error. */ static int -_cdio_read_mode1_sector (void *env, void *data, lsn_t lsn, - bool is_form2) +_get_read_mode1_sector_osx (void *user_data, void *data, lsn_t lsn, + bool b_form2) { - return _cdio_read_mode1_sectors(env, data, lsn, is_form2, 1); + return _get_read_mode1_sectors_osx(user_data, data, lsn, b_form2, 1); } /*! @@ -237,35 +753,35 @@ _cdio_read_mode1_sector (void *env, void *data, lsn_t lsn, from lsn. Returns 0 if no error. */ static int -_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, - bool is_form2) +_get_read_mode2_sector_osx (void *user_data, void *data, lsn_t lsn, + bool b_form2) { - return _cdio_read_mode2_sectors(env, data, lsn, is_form2, 1); + return _get_read_mode2_sectors_osx(user_data, data, lsn, b_form2, 1); } /*! Set the key "arg" to "value" in source device. */ static int -_cdio_set_arg (void *env, const char key[], const char value[]) +_set_arg_osx (void *user_data, const char key[], const char value[]) { - _img_private_t *_obj = env; + _img_private_t *env = user_data; if (!strcmp (key, "source")) { if (!value) return -2; - free (_obj->gen.source_name); + free (env->gen.source_name); - _obj->gen.source_name = strdup (value); + env->gen.source_name = strdup (value); } else if (!strcmp (key, "access-mode")) { if (!strcmp(value, "OSX")) - _obj->access_mode = _AM_OSX; + env->access_mode = _AM_OSX; else - cdio_error ("unknown access type: %s. ignored.", value); + cdio_warn ("unknown access type: %s. ignored.", value); } else return -1; @@ -273,168 +789,194 @@ _cdio_set_arg (void *env, const char key[], const char value[]) return 0; } +#if 0 +static void TestDevice(_img_private_t *p_env, io_service_t service) +{ + SInt32 score; + HRESULT herr; + kern_return_t err; + IOCFPlugInInterface **plugInInterface = NULL; + MMCDeviceInterface **mmcInterface = NULL; + + /* Create the IOCFPlugIn interface so we can query it. */ + + err = IOCreatePlugInInterfaceForService ( service, + kIOMMCDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugInInterface, + &score ); + if ( err != noErr ) { + printf("IOCreatePlugInInterfaceForService returned %d\n", err); + return; + } + + /* Query the interface for the MMCDeviceInterface. */ + + herr = ( *plugInInterface )->QueryInterface ( plugInInterface, + CFUUIDGetUUIDBytes ( kIOMMCDeviceInterfaceID ), + ( LPVOID ) &mmcInterface ); + + if ( herr != S_OK ) { + printf("QueryInterface returned %ld\n", herr); + return; + } + + p_env->pp_scsiTaskDeviceInterface = + ( *mmcInterface )->GetSCSITaskDeviceInterface ( mmcInterface ); + + if ( NULL == p_env->pp_scsiTaskDeviceInterface ) { + printf("GetSCSITaskDeviceInterface returned NULL\n"); + return; + } + + ( *mmcInterface )->Release ( mmcInterface ); + IODestroyPlugInInterface ( plugInInterface ); +} +#endif + /*! Read and cache the CD's Track Table of Contents and track info. Return false if successful or true if an error. */ static bool -_cdio_read_toc (_img_private_t *_obj) +read_toc_osx (void *p_user_data) { - mach_port_t port; - char *psz_devname; - kern_return_t ret; - io_iterator_t iterator; - io_registry_entry_t service; - CFMutableDictionaryRef properties; + _img_private_t *p_env = p_user_data; + CFDictionaryRef propertiesDict = 0; CFDataRef data; - - _obj->gen.fd = open( _obj->gen.source_name, O_RDONLY | O_NONBLOCK ); - if (-1 == _obj->gen.fd) { - cdio_error("Failed to open %s: %s", _obj->gen.source_name, - strerror(errno)); + + /* create a CF dictionary containing the TOC */ + propertiesDict = GetRegistryEntryProperties( p_env->MediaClass_service ); + + if ( 0 == propertiesDict ) { return false; } - /* get the device name */ - if( ( psz_devname = strrchr( _obj->gen.source_name, '/') ) != NULL ) - ++psz_devname; - else - psz_devname = _obj->gen.source_name; - - /* unraw the device name */ - if( *psz_devname == 'r' ) - ++psz_devname; - - /* get port for IOKit communication */ - if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS ) - { - cdio_error( "IOMasterPort: 0x%08x", ret ); - return false; - } - - /* get service iterator for the device */ - if( ( ret = IOServiceGetMatchingServices( - port, IOBSDNameMatching( port, 0, psz_devname ), - &iterator ) ) != KERN_SUCCESS ) - { - cdio_error( "IOServiceGetMatchingServices: 0x%08x", ret ); - return false; - } - - /* first service */ - service = IOIteratorNext( iterator ); - IOObjectRelease( iterator ); - - /* search for kIOCDMediaClass */ - while( service && !IOObjectConformsTo( service, kIOCDMediaClass ) ) - { - - ret = IORegistryEntryGetParentIterator( service, kIOServicePlane, - &iterator ); - if( ret != KERN_SUCCESS ) - { - cdio_error( "IORegistryEntryGetParentIterator: 0x%08x", ret ); - IOObjectRelease( service ); - return false; - } - - IOObjectRelease( service ); - service = IOIteratorNext( iterator ); - IOObjectRelease( iterator ); - } - - if( service == 0 ) - { - cdio_error( "search for kIOCDMediaClass came up empty" ); - return false; - } - - /* create a CF dictionary containing the TOC */ - ret = IORegistryEntryCreateCFProperties( service, &properties, - kCFAllocatorDefault, kNilOptions ); - - if( ret != KERN_SUCCESS ) - { - cdio_error( "IORegistryEntryCreateCFProperties: 0x%08x", ret ); - IOObjectRelease( service ); - return false; - } - /* get the TOC from the dictionary */ - data = (CFDataRef) CFDictionaryGetValue( properties, + data = (CFDataRef) CFDictionaryGetValue( propertiesDict, CFSTR(kIOCDMediaTOCKey) ); - if( data != NULL ) - { - CFRange range; - CFIndex buf_len; - - buf_len = CFDataGetLength( data ) + 1; - range = CFRangeMake( 0, buf_len ); - - if( ( _obj->pTOC = (CDTOC *)malloc( buf_len ) ) != NULL ) { - CFDataGetBytes( data, range, (u_char *) _obj->pTOC ); - } else { - cdio_error( "Trouble allocating CDROM TOC" ); - return false; - } - } - else - { - cdio_error( "CFDictionaryGetValue failed" ); + if ( data != NULL ) { + CFRange range; + CFIndex buf_len; + + buf_len = CFDataGetLength( data ) + 1; + range = CFRangeMake( 0, buf_len ); + + if( ( p_env->pTOC = (CDTOC *)malloc( buf_len ) ) != NULL ) { + CFDataGetBytes( data, range, (u_char *) p_env->pTOC ); + } else { + cdio_warn( "Trouble allocating CDROM TOC" ); + return false; } - - CFRelease( properties ); - IOObjectRelease( service ); + } else { + cdio_warn( "Trouble reading TOC" ); + return false; + } - _obj->i_descriptors = CDTOCGetDescriptorCount ( _obj->pTOC ); - _obj->num_tracks = _cdio_getNumberOfTracks(_obj->pTOC, _obj->i_descriptors); + /* TestDevice(p_env, service); */ + CFRelease( propertiesDict ); - /* Read in starting sectors */ + p_env->i_descriptors = CDTOCGetDescriptorCount ( p_env->pTOC ); + + /* Read in starting sectors. There may be non-tracks mixed in with + the real tracks. So find the first and last track number by + scanning. Also find the lead-out track position. + */ { int i, i_leadout = -1; + CDTOCDescriptor *pTrackDescriptors; - track_t track; - int i_tracks; - _obj->pp_lba = malloc( (_obj->num_tracks + 1) * sizeof(int) ); - if( _obj->pp_lba == NULL ) + p_env->pp_lba = malloc( p_env->i_descriptors * sizeof(int) ); + if( p_env->pp_lba == NULL ) { - cdio_error("Out of memory in allocating track starting LSNs" ); - free( _obj->pTOC ); + cdio_warn("Out of memory in allocating track starting LSNs" ); + free( p_env->pTOC ); return false; } - pTrackDescriptors = _obj->pTOC->descriptors; + pTrackDescriptors = p_env->pTOC->descriptors; + + p_env->gen.i_first_track = CDIO_CD_MAX_TRACKS+1; + p_env->i_last_track = CDIO_CD_MIN_TRACK_NO; + p_env->i_first_session = CDIO_CD_MAX_TRACKS+1; + p_env->i_last_session = CDIO_CD_MIN_TRACK_NO; - for( i_tracks = 0, i = 0; i <= _obj->i_descriptors; i++ ) + for( i = 0; i <= p_env->i_descriptors; i++ ) { - track = pTrackDescriptors[i].point; + track_t i_track = pTrackDescriptors[i].point; + session_t i_session = pTrackDescriptors[i].session; + + cdio_debug( "point: %d, tno: %d, session: %d, adr: %d, control:%d, " + "address: %d:%d:%d, p: %d:%d:%d", + i_track, + pTrackDescriptors[i].tno, i_session, + pTrackDescriptors[i].adr, pTrackDescriptors[i].control, + pTrackDescriptors[i].address.minute, + pTrackDescriptors[i].address.second, + pTrackDescriptors[i].address.frame, + pTrackDescriptors[i].p.minute, + pTrackDescriptors[i].p.second, + pTrackDescriptors[i].p.frame ); + + /* track information has adr = 1 */ + if ( 0x01 != pTrackDescriptors[i].adr ) + continue; - if( track == 0xA2 ) - /* Note leadout should be 0xAA, But OSX seems to use 0xA2. */ + if( i_track == OSX_CDROM_LEADOUT_TRACK ) i_leadout = i; - - if( track > CDIO_CD_MAX_TRACKS || track < CDIO_CD_MIN_TRACK_NO ) + + if( i_track > CDIO_CD_MAX_TRACKS || i_track < CDIO_CD_MIN_TRACK_NO ) continue; + + if (p_env->gen.i_first_track > i_track) + p_env->gen.i_first_track = i_track; + + if (p_env->i_last_track < i_track) + p_env->i_last_track = i_track; - _obj->pp_lba[i_tracks++] = + if (p_env->i_first_session > i_session) + p_env->i_first_session = i_session; + + if (p_env->i_last_session < i_session) + p_env->i_last_session = i_session; + } + + /* Now that we know what the first track number is, we can make sure + index positions are ordered starting at 0. + */ + for( i = 0; i <= p_env->i_descriptors; i++ ) + { + track_t i_track = pTrackDescriptors[i].point; + + if( i_track > CDIO_CD_MAX_TRACKS || i_track < CDIO_CD_MIN_TRACK_NO ) + continue; + + /* Note what OSX calls a LBA we call an LSN. So below re we + really have have MSF -> LSN -> LBA. + */ + p_env->pp_lba[i_track - p_env->gen.i_first_track] = cdio_lsn_to_lba(CDConvertMSFToLBA( pTrackDescriptors[i].p )); } if( i_leadout == -1 ) { - cdio_error( "CD leadout not found" ); - free( _obj->pp_lba ); - free( (void *) _obj->pTOC ); + cdio_warn( "CD leadout not found" ); + free( p_env->pp_lba ); + free( (void *) p_env->pTOC ); return false; } - /* set leadout sector */ - _obj->pp_lba[i_tracks] = + /* Set leadout sector. + Note what OSX calls a LBA we call an LSN. So below re we + really have have MSF -> LSN -> LBA. + */ + p_env->pp_lba[TOTAL_TRACKS] = cdio_lsn_to_lba(CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p )); + p_env->gen.i_tracks = TOTAL_TRACKS; } - _obj->toc_init = true; + p_env->gen.toc_init = true; return( true ); @@ -442,24 +984,25 @@ _cdio_read_toc (_img_private_t *_obj) /*! Return the starting LSN track number - track_num in obj. Track numbers start at 1. + i_track in obj. Track numbers start at 1. The "leadout" track is specified either by - using track_num LEADOUT_TRACK or the total tracks+1. + using i_track LEADOUT_TRACK or the total tracks+1. False is returned if there is no track entry. */ static lsn_t -_cdio_get_track_lba(void *env, track_t track_num) +get_track_lba_osx(void *p_user_data, track_t i_track) { - _img_private_t *_obj = env; + _img_private_t *p_env = p_user_data; - if (!_obj->toc_init) _cdio_read_toc (_obj) ; + if (!p_env->gen.toc_init) read_toc_osx (p_env) ; + if (!p_env->gen.toc_init) return CDIO_INVALID_LSN; - if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = p_env->i_last_track+1; - if (track_num > TOTAL_TRACKS+1 || track_num == 0) { + if (i_track > p_env->i_last_track + 1 || i_track < p_env->gen.i_first_track) { return CDIO_INVALID_LSN; } else { - return _obj->pp_lba[track_num-1]; + return p_env->pp_lba[i_track - p_env->gen.i_first_track]; } } @@ -474,18 +1017,18 @@ _cdio_get_track_lba(void *env, track_t track_num) */ static int -_cdio_eject_media (void *env) { +_eject_media_osx (void *user_data) { - _img_private_t *_obj = env; + _img_private_t *p_env = user_data; FILE *p_eject; char *psz_disk; char sz_cmd[32]; - if( ( psz_disk = (char *)strstr( _obj->gen.source_name, "disk" ) ) != NULL && + if( ( psz_disk = (char *)strstr( p_env->gen.source_name, "disk" ) ) != NULL && strlen( psz_disk ) > 4 ) { -#define EJECT_CMD "/usr/sbin/disktool -e %s 0" +#define EJECT_CMD "/usr/sbin/hdiutil eject %s" snprintf( sz_cmd, sizeof(sz_cmd), EJECT_CMD, psz_disk ); #undef EJECT_CMD @@ -518,23 +1061,23 @@ _cdio_eject_media (void *env) { Return the size of the CD in logical block address (LBA) units. */ static uint32_t -_cdio_stat_size (void *env) +_stat_size_osx (void *user_data) { - return _cdio_get_track_lba(env, CDIO_CDROM_LEADOUT_TRACK); + return get_track_lba_osx(user_data, CDIO_CDROM_LEADOUT_TRACK); } /*! Return the value associated with the key "arg". */ static const char * -_cdio_get_arg (void *env, const char key[]) +_get_arg_osx (void *user_data, const char key[]) { - _img_private_t *_obj = env; + _img_private_t *p_env = user_data; if (!strcmp (key, "source")) { - return _obj->gen.source_name; + return p_env->gen.source_name; } else if (!strcmp (key, "access-mode")) { - switch (_obj->access_mode) { + switch (p_env->access_mode) { case _AM_OSX: return "OS X"; case _AM_NONE: @@ -545,101 +1088,67 @@ _cdio_get_arg (void *env, const char key[]) } /*! - Return the number of the first track. - CDIO_INVALID_TRACK is returned on error. -*/ -static track_t -_cdio_get_first_track_num(void *env) -{ - _img_private_t *_obj = env; - - if (!_obj->toc_init) _cdio_read_toc (_obj) ; - - { - track_t track = CDIO_INVALID_TRACK; - int i; - CDTOCDescriptor *pTrackDescriptors; - - pTrackDescriptors = _obj->pTOC->descriptors; - - for( i = 0; i < _obj->i_descriptors; i++ ) - { - track = pTrackDescriptors[i].point; - - if( track > CDIO_CD_MAX_TRACKS || track < CDIO_CD_MIN_TRACK_NO ) - continue; - return ( track ); - } - } - - return CDIO_INVALID_TRACK; -} - -/*! Return the media catalog number MCN. */ static char * -_cdio_get_mcn (void *env) { - _img_private_t *_obj = env; +get_mcn_osx (const void *user_data) { + const _img_private_t *p_env = user_data; dk_cd_read_mcn_t cd_read; memset( &cd_read, 0, sizeof(cd_read) ); - if( ioctl( _obj->gen.fd, DKIOCCDREADMCN, &cd_read ) < 0 ) + if( ioctl( p_env->gen.fd, DKIOCCDREADMCN, &cd_read ) < 0 ) { - cdio_error( "could not read MCN, %s", strerror(errno) ); + cdio_debug( "could not read MCN, %s", strerror(errno) ); return NULL; } return strdup((char*)cd_read.mcn); } -/*! - Return the number of tracks in the current medium. - CDIO_INVALID_TRACK is returned on error. - This is the externally called interface. -*/ -static track_t -_cdio_get_num_tracks(void *env) -{ - _img_private_t *_obj = env; - - if (!_obj->toc_init) _cdio_read_toc (_obj) ; - return( _obj->num_tracks ); -} - /*! Get format of track. */ static track_format_t -_cdio_get_track_format(void *env, track_t track_num) +get_track_format_osx(void *user_data, track_t i_track) { - _img_private_t *_obj = env; + _img_private_t *p_env = user_data; + dk_cd_read_track_info_t cd_read; CDTrackInfo a_track; - - if (!_obj->toc_init) _cdio_read_toc (_obj) ; - if (track_num > TOTAL_TRACKS || track_num == 0) + if (!p_env->gen.toc_init) read_toc_osx (p_env) ; + + if (i_track > p_env->i_last_track || i_track < p_env->gen.i_first_track) return TRACK_FORMAT_ERROR; - dk_cd_read_track_info_t cd_read; memset( &cd_read, 0, sizeof(cd_read) ); - cd_read.address = track_num; + cd_read.address = i_track; cd_read.addressType = kCDTrackInfoAddressTypeTrackNumber; cd_read.buffer = &a_track; cd_read.bufferLength = sizeof(CDTrackInfo); - if( ioctl( _obj->gen.fd, DKIOCCDREADTRACKINFO, &cd_read ) == -1 ) + if( ioctl( p_env->gen.fd, DKIOCCDREADTRACKINFO, &cd_read ) == -1 ) { - cdio_error( "could not read trackinfo for track %d", track_num ); - return -1; + cdio_warn( "could not read trackinfo for track %d", i_track ); + return TRACK_FORMAT_ERROR; } - cdio_warn( "trackinfo trackMode: %x dataMode: %x", a_track.trackMode, a_track.dataMode ); + cdio_debug( "%d: trackinfo trackMode: %x dataMode: %x", i_track, a_track.trackMode, a_track.dataMode ); + + if (a_track.trackMode == CDIO_CDROM_DATA_TRACK) { + if (a_track.dataMode == CDROM_CDI_TRACK) { + return TRACK_FORMAT_CDI; + } else if (a_track.dataMode == CDROM_XA_TRACK) { + return TRACK_FORMAT_XA; + } else { + return TRACK_FORMAT_DATA; + } + } else { + return TRACK_FORMAT_AUDIO; + } - return TRACK_FORMAT_AUDIO; } /*! @@ -651,25 +1160,34 @@ _cdio_get_track_format(void *env, track_t track_num) FIXME: there's gotta be a better design for this and get_track_format? */ static bool -_cdio_get_track_green(void *env, track_t track_num) +get_track_green_osx(void *user_data, track_t i_track) { + _img_private_t *p_env = user_data; + CDTrackInfo a_track; -#if 0 - if (!_obj->toc_init) _cdio_read_toc (_obj) ; - - if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + if (!p_env->gen.toc_init) read_toc_osx (p_env) ; - if (track_num > TOTAL_TRACKS+1 || track_num == 0) + if ( i_track > p_env->i_last_track || i_track < p_env->gen.i_first_track ) return false; - /* FIXME: Dunno if this is the right way, but it's what - I was using in cdinfo for a while. - */ - return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0); -#else - /* FIXME! Figure out how to do. */ - return true; -#endif + else { + + dk_cd_read_track_info_t cd_read; + + memset( &cd_read, 0, sizeof(cd_read) ); + + cd_read.address = i_track; + cd_read.addressType = kCDTrackInfoAddressTypeTrackNumber; + + cd_read.buffer = &a_track; + cd_read.bufferLength = sizeof(CDTrackInfo); + + if( ioctl( p_env->gen.fd, DKIOCCDREADTRACKINFO, &cd_read ) == -1 ) { + cdio_warn( "could not read trackinfo for track %d", i_track ); + return false; + } + return ((a_track.trackMode & CDIO_CDROM_DATA_TRACK) != 0); + } } #endif /* HAVE_DARWIN_CDROM */ @@ -694,13 +1212,13 @@ cdio_get_devices_osx(void) kern_result = IOMasterPort( MACH_PORT_NULL, &master_port ); if( kern_result != KERN_SUCCESS ) { - return( nil ); + return( NULL ); } classes_to_match = IOServiceMatching( kIOCDMediaClass ); if( classes_to_match == NULL ) { - return( nil ); + return( NULL ); } CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaEjectableKey), @@ -711,7 +1229,7 @@ cdio_get_devices_osx(void) &media_iterator ); if( kern_result != KERN_SUCCESS ) { - return( nil ); + return( NULL ); } next_media = IOIteratorNext( media_iterator ); @@ -744,7 +1262,7 @@ cdio_get_devices_osx(void) CFRelease( str_bsd_path ); IOObjectRelease( next_media ); IOObjectRelease( media_iterator ); - cdio_add_device_list(&drives, psz_buf, &num_drives); + cdio_add_device_list(&drives, strdup(psz_buf), &num_drives); } CFRelease( str_bsd_path ); @@ -776,13 +1294,13 @@ cdio_get_default_device_osx(void) kern_result = IOMasterPort( MACH_PORT_NULL, &master_port ); if( kern_result != KERN_SUCCESS ) { - return( nil ); + return( NULL ); } classes_to_match = IOServiceMatching( kIOCDMediaClass ); if( classes_to_match == NULL ) { - return( nil ); + return( NULL ); } CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaEjectableKey), @@ -793,7 +1311,7 @@ cdio_get_default_device_osx(void) &media_iterator ); if( kern_result != KERN_SUCCESS ) { - return( nil ); + return( NULL ); } next_media = IOIteratorNext( media_iterator ); @@ -845,55 +1363,90 @@ cdio_get_default_device_osx(void) ones to set that up. */ CdIo * -cdio_open_osx (const char *orig_source_name) +cdio_open_am_osx (const char *psz_source_name, const char *psz_access_mode) +{ + + if (psz_access_mode != NULL) + cdio_warn ("there is only one access mode for OS X. Arg %s ignored", + psz_access_mode); + return cdio_open_osx(psz_source_name); +} + + +/*! + Initialization routine. This is the only thing that doesn't + get called via a function pointer. In fact *we* are the + ones to set that up. + */ +CdIo * +cdio_open_osx (const char *psz_orig_source) { #ifdef HAVE_DARWIN_CDROM CdIo *ret; _img_private_t *_data; - char *source_name; + char *psz_source; cdio_funcs _funcs = { - .eject_media = _cdio_eject_media, - .free = _cdio_osx_free, - .get_arg = _cdio_get_arg, + .eject_media = _eject_media_osx, + .free = _free_osx, + .get_arg = _get_arg_osx, + .get_cdtext = get_cdtext_osx, .get_default_device = cdio_get_default_device_osx, .get_devices = cdio_get_devices_osx, - .get_first_track_num= _cdio_get_first_track_num, - .get_mcn = _cdio_get_mcn, - .get_num_tracks = _cdio_get_num_tracks, - .get_track_format = _cdio_get_track_format, - .get_track_green = _cdio_get_track_green, - .get_track_lba = _cdio_get_track_lba, + .get_discmode = get_discmode_osx, + .get_drive_cap = get_drive_cap_osx, + .get_first_track_num= get_first_track_num_generic, + .get_hwinfo = get_hwinfo_osx, + .get_mcn = get_mcn_osx, + .get_num_tracks = get_num_tracks_generic, + .get_track_format = get_track_format_osx, + .get_track_green = get_track_green_osx, + .get_track_lba = get_track_lba_osx, .get_track_msf = NULL, .lseek = cdio_generic_lseek, .read = cdio_generic_read, - .read_audio_sectors = _cdio_read_audio_sectors, - .read_mode1_sector = _cdio_read_mode1_sector, - .read_mode1_sectors = _cdio_read_mode1_sectors, - .read_mode2_sector = _cdio_read_mode2_sector, - .read_mode2_sectors = _cdio_read_mode2_sectors, - .set_arg = _cdio_set_arg, - .stat_size = _cdio_stat_size + .read_audio_sectors = _get_read_audio_sectors_osx, + .read_mode1_sector = _get_read_mode1_sector_osx, + .read_mode1_sectors = _get_read_mode1_sectors_osx, + .read_mode2_sector = _get_read_mode2_sector_osx, + .read_mode2_sectors = _get_read_mode2_sectors_osx, + .read_toc = read_toc_osx, + .run_scsi_mmc_cmd = run_scsi_cmd_osx, + .set_arg = _set_arg_osx, + .stat_size = _stat_size_osx }; _data = _cdio_malloc (sizeof (_img_private_t)); _data->access_mode = _AM_OSX; - _data->gen.init = false; - _data->gen.fd = -1; - - if (NULL == orig_source_name) { - source_name=cdio_get_default_device_linux(); - if (NULL == source_name) return NULL; - _cdio_set_arg(_data, "source", source_name); - free(source_name); - } else - _cdio_set_arg(_data, "source", orig_source_name); - - ret = cdio_new (_data, &_funcs); + _data->MediaClass_service = 0; + _data->gen.init = false; + _data->gen.fd = -1; + _data->gen.toc_init = false; + _data->gen.b_cdtext_init = false; + _data->gen.b_cdtext_error = false; + + if (NULL == psz_orig_source) { + psz_source=cdio_get_default_device_osx(); + if (NULL == psz_source) return NULL; + _set_arg_osx(_data, "source", psz_source); + free(psz_source); + } else { + if (cdio_is_device_generic(psz_orig_source)) + _set_arg_osx(_data, "source", psz_orig_source); + else { + /* The below would be okay if all device drivers worked this way. */ +#if 0 + cdio_info ("source %s is a not a device", psz_orig_source); +#endif + return NULL; + } + } + + ret = cdio_new ((void *)_data, &_funcs); if (ret == NULL) return NULL; - if (cdio_generic_init(_data)) + if (cdio_generic_init(_data) && init_osx(_data)) return ret; else { cdio_generic_free (_data); |