|
Packit |
dd8086 |
/*
|
|
Packit |
dd8086 |
Copyright (C) 2003-2006, 2008, 2010-2012, 2014-2015, 2017
|
|
Packit |
dd8086 |
Rocky Bernstein <rocky@gnu.org>
|
|
Packit |
dd8086 |
from vcdimager code:
|
|
Packit |
dd8086 |
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
|
Packit |
dd8086 |
and VideoLAN code Copyright (C) 1998-2001 VideoLAN
|
|
Packit |
dd8086 |
Authors: Johan Bilien <jobi@via.ecp.fr>
|
|
Packit |
dd8086 |
Gildas Bazin <gbazin@netcourrier.com>
|
|
Packit |
dd8086 |
Jon Lech Johansen <jon-vl@nanocrew.net>
|
|
Packit |
dd8086 |
Derk-Jan Hartman <hartman at videolan.org>
|
|
Packit |
dd8086 |
Justin F. Hallett <thesin@southofheaven.org>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
This program is free software: you can redistribute it and/or modify
|
|
Packit |
dd8086 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
dd8086 |
the Free Software Foundation, either version 3 of the License, or
|
|
Packit |
dd8086 |
(at your option) any later version.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
dd8086 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
dd8086 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
dd8086 |
GNU General Public License for more details.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
You should have received a copy of the GNU General Public License
|
|
Packit |
dd8086 |
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* This file contains OSX-specific code and implements low-level
|
|
Packit |
dd8086 |
control of the CD drive.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
dd8086 |
# include "config.h"
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_STDBOOL_H
|
|
Packit |
dd8086 |
# include <stdbool.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <cdio/logging.h>
|
|
Packit |
dd8086 |
#include <cdio/sector.h>
|
|
Packit |
dd8086 |
#include <cdio/util.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* For SCSI TR_* enumerations */
|
|
Packit |
dd8086 |
typedef enum {
|
|
Packit |
dd8086 |
TR_OK = 0,
|
|
Packit |
dd8086 |
TR_EWRITE = 1 /**< Error writing packet command (transport) */,
|
|
Packit |
dd8086 |
TR_EREAD = 2 /**< Error reading packet data (transport) */,
|
|
Packit |
dd8086 |
TR_UNDERRUN = 3 /**< Read underrun */,
|
|
Packit |
dd8086 |
TR_OVERRUN = 4 /**< Read overrun */,
|
|
Packit |
dd8086 |
TR_ILLEGAL = 5 /**< Illegal/rejected request */,
|
|
Packit |
dd8086 |
TR_MEDIUM = 6 /**< Medium error */,
|
|
Packit |
dd8086 |
TR_BUSY = 7 /**< Device busy */,
|
|
Packit |
dd8086 |
TR_NOTREADY = 8 /**< Device not ready */,
|
|
Packit |
dd8086 |
TR_FAULT = 9 /**< Device failure */,
|
|
Packit |
dd8086 |
TR_UNKNOWN = 10 /**< Unspecified error */,
|
|
Packit |
dd8086 |
TR_STREAMING = 11 /**< loss of streaming */,
|
|
Packit |
dd8086 |
} transport_error_t;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include "cdio_assert.h"
|
|
Packit |
dd8086 |
#include "cdio_private.h"
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <string.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_DARWIN_CDROM
|
|
Packit |
dd8086 |
#undef VERSION
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <CoreFoundation/CoreFoundation.h>
|
|
Packit |
dd8086 |
#include <IOKit/IOKitLib.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <mach/mach.h>
|
|
Packit |
dd8086 |
#include <Carbon/Carbon.h>
|
|
Packit |
dd8086 |
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1030
|
|
Packit |
dd8086 |
# include <IOKit/scsi/SCSITaskLib.h>
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
# include <IOKit/scsi-commands/SCSITaskLib.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
#include <IOKit/IOCFPlugIn.h>
|
|
Packit |
dd8086 |
#include <mach/mach_error.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <stdio.h>
|
|
Packit |
dd8086 |
#include <stdlib.h>
|
|
Packit |
dd8086 |
#include <errno.h>
|
|
Packit |
dd8086 |
#include <unistd.h>
|
|
Packit |
dd8086 |
#include <fcntl.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <sys/stat.h>
|
|
Packit |
dd8086 |
#include <sys/types.h>
|
|
Packit |
dd8086 |
#include <sys/ioctl.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <paths.h>
|
|
Packit |
dd8086 |
#include <CoreFoundation/CoreFoundation.h>
|
|
Packit |
dd8086 |
#include <IOKit/IOKitLib.h>
|
|
Packit |
dd8086 |
#include <IOKit/IOBSD.h>
|
|
Packit |
dd8086 |
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1030
|
|
Packit |
dd8086 |
# include <IOKit/scsi/IOSCSIMultimediaCommandsDevice.h>
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
# include <IOKit/scsi-commands/IOSCSIMultimediaCommandsDevice.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOCDTypes.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IODVDTypes.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOMedia.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOCDMedia.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IODVDMedia.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOCDMediaBSDClient.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IODVDMediaBSDClient.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOBlockStorageDevice.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOBDTypes.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOBDMedia.h>
|
|
Packit |
dd8086 |
#include <IOKit/storage/IOBDMediaBSDClient.h>
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
#define kIOBDMediaClass "IOBDMedia" // It does not hurt, simplyfies rest of code
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_DISKARBITRATION
|
|
Packit |
dd8086 |
#include <DiskArbitration/DiskArbitration.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* FIXME */
|
|
Packit |
dd8086 |
#define MAX_BIG_BUFF_SIZE 65535
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#define kIOCDBlockStorageDeviceClassString "IOCDBlockStorageDevice"
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Note leadout is normally defined 0xAA, But on OSX 0xA0 is "lead in" while
|
|
Packit |
dd8086 |
0xA2 is "lead out". I don't understand the distinction, and therefore
|
|
Packit |
dd8086 |
something could be wrong. */
|
|
Packit |
dd8086 |
#define OSX_CDROM_LEADOUT_TRACK 0xA2
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#define TOTAL_TRACKS (p_env->i_last_track - p_env->gen.i_first_track + 1)
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#define CDROM_CDI_TRACK 0x1
|
|
Packit |
dd8086 |
#define CDROM_XA_TRACK 0x2
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
typedef enum {
|
|
Packit |
dd8086 |
_AM_NONE,
|
|
Packit |
dd8086 |
_AM_OSX,
|
|
Packit |
dd8086 |
} access_mode_t;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#define MAX_SERVICE_NAME 1000
|
|
Packit |
dd8086 |
typedef struct {
|
|
Packit |
dd8086 |
/* Things common to all drivers like this.
|
|
Packit |
dd8086 |
This must be first. */
|
|
Packit |
dd8086 |
generic_img_private_t gen;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
access_mode_t access_mode;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Track information */
|
|
Packit |
dd8086 |
CDTOC *pTOC;
|
|
Packit |
dd8086 |
int i_descriptors;
|
|
Packit |
dd8086 |
track_t i_last_track; /* highest track number */
|
|
Packit |
dd8086 |
track_t i_last_session; /* highest session number */
|
|
Packit |
dd8086 |
track_t i_first_session; /* first session number */
|
|
Packit |
dd8086 |
lsn_t *pp_lba;
|
|
Packit |
dd8086 |
io_service_t MediaClass_service;
|
|
Packit |
dd8086 |
char psz_MediaClass_service[MAX_SERVICE_NAME];
|
|
Packit |
dd8086 |
SCSITaskDeviceInterface **pp_scsiTaskDeviceInterface;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
// io_service_t obj;
|
|
Packit |
dd8086 |
// SCSITaskDeviceInterface **scsi;
|
|
Packit |
dd8086 |
SCSITaskInterface **scsi_task;
|
|
Packit |
dd8086 |
MMCDeviceInterface **mmc;
|
|
Packit |
dd8086 |
IOCFPlugInInterface **plugin;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
SCSI_Sense_Data sense;
|
|
Packit |
dd8086 |
SCSITaskStatus status;
|
|
Packit |
dd8086 |
UInt64 realized_len;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
} _img_private_t;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static bool read_toc_osx (void *p_user_data);
|
|
Packit |
dd8086 |
static track_format_t get_track_format_osx(void *p_user_data,
|
|
Packit |
dd8086 |
track_t i_track);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
* GetRegistryEntryProperties - Gets the registry entry properties for
|
|
Packit |
dd8086 |
* an io_service_t.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static CFMutableDictionaryRef
|
|
Packit |
dd8086 |
GetRegistryEntryProperties ( io_service_t service )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
IOReturn err = kIOReturnSuccess;
|
|
Packit |
dd8086 |
CFMutableDictionaryRef dict = 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
err = IORegistryEntryCreateCFProperties (service, &dict,
|
|
Packit |
dd8086 |
kCFAllocatorDefault, 0);
|
|
Packit |
dd8086 |
if ( err != kIOReturnSuccess )
|
|
Packit |
dd8086 |
cdio_warn( "IORegistryEntryCreateCFProperties: 0x%08x", err );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return dict;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
* ProbeStorageDevices - Probe devices to detect changes.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static bool
|
|
Packit |
dd8086 |
ProbeStorageDevices()
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
io_service_t next_service;
|
|
Packit |
dd8086 |
mach_port_t master_port;
|
|
Packit |
dd8086 |
kern_return_t kern_result;
|
|
Packit |
dd8086 |
io_iterator_t service_iterator;
|
|
Packit |
dd8086 |
CFMutableDictionaryRef classes_to_match;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
|
|
Packit |
dd8086 |
if( kern_result != KERN_SUCCESS )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
classes_to_match = IOServiceMatching( kIOBlockStorageDeviceClass );
|
|
Packit |
dd8086 |
if( classes_to_match == NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
kern_result = IOServiceGetMatchingServices( master_port,
|
|
Packit |
dd8086 |
classes_to_match,
|
|
Packit |
dd8086 |
&service_iterator );
|
|
Packit |
dd8086 |
if( kern_result != KERN_SUCCESS )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
next_service = IOIteratorNext( service_iterator );
|
|
Packit |
dd8086 |
if( next_service != 0 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
do
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
IOServiceRequestProbe( next_service, 0 );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
IOObjectRelease( next_service );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
} while( ( next_service = IOIteratorNext( service_iterator ) ) != 0 );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
IOObjectRelease( service_iterator );
|
|
Packit |
dd8086 |
return true;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef GET_SCSI_FIXED
|
|
Packit |
dd8086 |
static bool
|
|
Packit |
dd8086 |
get_scsi(_img_private_t *p_env)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
SInt32 score;
|
|
Packit |
dd8086 |
kern_return_t err;
|
|
Packit |
dd8086 |
HRESULT herr;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
err = IOCreatePlugInInterfaceForService(p_env->MediaClass_service,
|
|
Packit |
dd8086 |
kIOMMCDeviceUserClientTypeID,
|
|
Packit |
dd8086 |
kIOCFPlugInInterfaceID,
|
|
Packit |
dd8086 |
&p_env->plugin,
|
|
Packit |
dd8086 |
&score);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (err != noErr) {
|
|
Packit |
dd8086 |
fprintf(stderr, "Error %x accessing MMC plugin.\n", err);
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
herr = (*p_env->plugin) ->
|
|
Packit |
dd8086 |
QueryInterface(p_env->plugin, CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID),
|
|
Packit |
dd8086 |
(void *)&p_env->mmc);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (herr != S_OK) {
|
|
Packit |
dd8086 |
fprintf(stderr, "Error %x accessing MMC interface.\n", (int) herr);
|
|
Packit |
dd8086 |
IODestroyPlugInInterface(p_env->plugin);
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->pp_scsiTaskDeviceInterface =
|
|
Packit |
dd8086 |
(*p_env->mmc)->GetSCSITaskDeviceInterface(p_env->mmc);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env->pp_scsiTaskDeviceInterface) {
|
|
Packit |
dd8086 |
fprintf(stderr,
|
|
Packit |
dd8086 |
"Could not get SCSITaskkDevice interface from MMC interface.\n");
|
|
Packit |
dd8086 |
(*p_env->mmc)->Release(p_env->mmc);
|
|
Packit |
dd8086 |
IODestroyPlugInInterface(p_env->plugin);
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
err = (*p_env->pp_scsiTaskDeviceInterface)->
|
|
Packit |
dd8086 |
ObtainExclusiveAccess(p_env->pp_scsiTaskDeviceInterface);
|
|
Packit |
dd8086 |
if (err != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
fprintf(stderr, "Could not obtain exclusive access to the device (%x).\n",
|
|
Packit |
dd8086 |
err);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (err == kIOReturnBusy)
|
|
Packit |
dd8086 |
fprintf(stderr, "The volume is already mounted.\n");
|
|
Packit |
dd8086 |
else if (err == kIOReturnExclusiveAccess)
|
|
Packit |
dd8086 |
fprintf(stderr, "Another application already has exclusive access "
|
|
Packit |
dd8086 |
"to this device.\n");
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
fprintf(stderr, "I don't know why.\n");
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
(*p_env->pp_scsiTaskDeviceInterface)->
|
|
Packit |
dd8086 |
Release(p_env->pp_scsiTaskDeviceInterface);
|
|
Packit |
dd8086 |
(*p_env->mmc)->Release(p_env->mmc);
|
|
Packit |
dd8086 |
IODestroyPlugInInterface(p_env->plugin);
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->scsi_task =
|
|
Packit |
dd8086 |
(*p_env->pp_scsiTaskDeviceInterface) ->
|
|
Packit |
dd8086 |
CreateSCSITask(p_env->pp_scsiTaskDeviceInterface);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env->scsi_task) {
|
|
Packit |
dd8086 |
fprintf(stderr, "Could not create a SCSITask interface.\n");
|
|
Packit |
dd8086 |
(*p_env->pp_scsiTaskDeviceInterface)->
|
|
Packit |
dd8086 |
ReleaseExclusiveAccess(p_env->pp_scsiTaskDeviceInterface);
|
|
Packit |
dd8086 |
(*p_env->pp_scsiTaskDeviceInterface)->
|
|
Packit |
dd8086 |
Release(p_env->pp_scsiTaskDeviceInterface);
|
|
Packit |
dd8086 |
(*p_env->mmc)->Release(p_env->mmc);
|
|
Packit |
dd8086 |
IODestroyPlugInInterface(p_env->plugin);
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return true;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static bool
|
|
Packit |
dd8086 |
init_osx(_img_private_t *p_env) {
|
|
Packit |
dd8086 |
char *psz_devname;
|
|
Packit |
dd8086 |
kern_return_t ret;
|
|
Packit |
dd8086 |
io_iterator_t iterator;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Only open if not already opened. Otherwise, too many descriptors
|
|
Packit |
dd8086 |
are holding the device busy. */
|
|
Packit |
dd8086 |
if (-1 == p_env->gen.fd)
|
|
Packit |
dd8086 |
p_env->gen.fd = open( p_env->gen.source_name, O_RDONLY | O_NONBLOCK );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (-1 == p_env->gen.fd) {
|
|
Packit |
dd8086 |
cdio_warn("Failed to open %s: %s", p_env->gen.source_name,
|
|
Packit |
dd8086 |
strerror(errno));
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Get the device name. */
|
|
Packit |
dd8086 |
psz_devname = strrchr( p_env->gen.source_name, '/');
|
|
Packit |
dd8086 |
if( NULL != psz_devname )
|
|
Packit |
dd8086 |
++psz_devname;
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
psz_devname = p_env->gen.source_name;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Unraw the device name. */
|
|
Packit |
dd8086 |
if( *psz_devname == 'r' )
|
|
Packit |
dd8086 |
++psz_devname;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ret = IOServiceGetMatchingServices( kIOMasterPortDefault,
|
|
Packit |
dd8086 |
IOBSDNameMatching(kIOMasterPortDefault,
|
|
Packit |
dd8086 |
0, psz_devname),
|
|
Packit |
dd8086 |
&iterator );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Get service iterator for the device. */
|
|
Packit |
dd8086 |
if( ret != KERN_SUCCESS )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_warn( "IOServiceGetMatchingServices: 0x%08x", ret );
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* first service */
|
|
Packit |
dd8086 |
p_env->MediaClass_service = IOIteratorNext( iterator );
|
|
Packit |
dd8086 |
IOObjectRelease( iterator );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* search for kIOCDMediaClass or kIODVDMediaClass or kIOBDMediaClass */
|
|
Packit |
dd8086 |
while( p_env->MediaClass_service &&
|
|
Packit |
dd8086 |
(!IOObjectConformsTo(p_env->MediaClass_service, kIOCDMediaClass)) &&
|
|
Packit |
dd8086 |
(!IOObjectConformsTo(p_env->MediaClass_service, kIODVDMediaClass)) &&
|
|
Packit |
dd8086 |
(!IOObjectConformsTo(p_env->MediaClass_service, kIOBDMediaClass)) )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ret = IORegistryEntryGetParentIterator( p_env->MediaClass_service,
|
|
Packit |
dd8086 |
kIOServicePlane,
|
|
Packit |
dd8086 |
&iterator );
|
|
Packit |
dd8086 |
if( ret != KERN_SUCCESS )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_warn( "IORegistryEntryGetParentIterator: 0x%08x", ret );
|
|
Packit |
dd8086 |
IOObjectRelease( p_env->MediaClass_service );
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
IOObjectRelease( p_env->MediaClass_service );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->MediaClass_service = IOIteratorNext( iterator );
|
|
Packit |
dd8086 |
IOObjectRelease( iterator );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 == p_env->MediaClass_service ) {
|
|
Packit |
dd8086 |
cdio_warn( "search for kIOCDMediaClass/kIODVDMediaClass/kIOBDMediaClass came up empty" );
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Save the name so we can compare against this in case we have to do
|
|
Packit |
dd8086 |
another scan. FIXME: this is hoaky and there's got to be a better
|
|
Packit |
dd8086 |
variable to test or way to do.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
IORegistryEntryGetPath(p_env->MediaClass_service, kIOServicePlane,
|
|
Packit |
dd8086 |
p_env->psz_MediaClass_service);
|
|
Packit |
dd8086 |
#ifdef GET_SCSI_FIXED
|
|
Packit |
dd8086 |
return get_scsi(p_env);
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
return true;
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Run a SCSI MMC command.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdio CD structure set by cdio_open().
|
|
Packit |
dd8086 |
i_timeout time in milliseconds we will wait for the command
|
|
Packit |
dd8086 |
to complete. If this value is -1, use the default
|
|
Packit |
dd8086 |
time-out value.
|
|
Packit |
dd8086 |
p_buf Buffer for data, both sending and receiving
|
|
Packit |
dd8086 |
i_buf Size of buffer
|
|
Packit |
dd8086 |
e_direction direction the transfer is to go.
|
|
Packit |
dd8086 |
cdb CDB bytes. All values that are needed should be set on
|
|
Packit |
dd8086 |
input. We'll figure out what the right CDB length should be.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
We return true if command completed successfully and false if not.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
#if 1
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* process a complete scsi command. */
|
|
Packit |
dd8086 |
static int
|
|
Packit |
dd8086 |
run_mmc_cmd_osx( void *p_user_data,
|
|
Packit |
dd8086 |
unsigned int i_timeout_ms,
|
|
Packit |
dd8086 |
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
|
|
Packit |
dd8086 |
cdio_mmc_direction_t e_direction,
|
|
Packit |
dd8086 |
unsigned int i_buf, /*in/out*/ void *p_buf )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
uint8_t cmdbuf[16];
|
|
Packit |
dd8086 |
UInt8 dir;
|
|
Packit |
dd8086 |
IOVirtualRange buf;
|
|
Packit |
dd8086 |
IOReturn ret;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env->scsi_task) return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->gen.scsi_mmc_sense_valid = 0;
|
|
Packit |
dd8086 |
memcpy(cmdbuf, p_cdb, i_cdb);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
dir =
|
|
Packit |
dd8086 |
(SCSI_MMC_DATA_READ == e_direction)
|
|
Packit |
dd8086 |
? kSCSIDataTransfer_FromTargetToInitiator :
|
|
Packit |
dd8086 |
(SCSI_MMC_DATA_WRITE == e_direction)
|
|
Packit |
dd8086 |
? kSCSIDataTransfer_FromInitiatorToTarget
|
|
Packit |
dd8086 |
: kSCSIDataTransfer_NoDataTransfer;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!i_buf)
|
|
Packit |
dd8086 |
dir = kSCSIDataTransfer_NoDataTransfer;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_buf > MAX_BIG_BUFF_SIZE) {
|
|
Packit |
dd8086 |
fprintf(stderr, "Excessive request size: %d bytes\n", i_buf);
|
|
Packit |
dd8086 |
return TR_ILLEGAL;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
buf.address = (IOVirtualAddress)p_buf;
|
|
Packit |
dd8086 |
buf.length = i_buf;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ret = (*p_env->scsi_task)->SetCommandDescriptorBlock(p_env->scsi_task,
|
|
Packit |
dd8086 |
cmdbuf, i_cdb);
|
|
Packit |
dd8086 |
if (ret != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
fprintf(stderr, "SetCommandDescriptorBlock: %x\n", ret);
|
|
Packit |
dd8086 |
return TR_UNKNOWN;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ret = (*p_env->scsi_task)->SetScatterGatherEntries(p_env->scsi_task, &buf, 1,
|
|
Packit |
dd8086 |
i_buf, dir);
|
|
Packit |
dd8086 |
if (ret != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
fprintf(stderr, "SetScatterGatherEntries: %x\n", ret);
|
|
Packit |
dd8086 |
return TR_UNKNOWN;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ret = (*p_env->scsi_task)->ExecuteTaskSync(p_env->scsi_task, &p_env->sense,
|
|
Packit |
dd8086 |
&p_env->status,
|
|
Packit |
dd8086 |
&p_env->realized_len);
|
|
Packit |
dd8086 |
if (ret != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
fprintf(stderr, "ExecuteTaskSync: %x\n", ret);
|
|
Packit |
dd8086 |
return TR_UNKNOWN;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->status != kSCSITaskStatus_GOOD) {
|
|
Packit |
dd8086 |
int i;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
fprintf(stderr, "SCSI status: %x\n", p_env->status);
|
|
Packit |
dd8086 |
fprintf(stderr, "Sense: %x %x %x\n",
|
|
Packit |
dd8086 |
p_env->sense.SENSE_KEY,
|
|
Packit |
dd8086 |
p_env->sense.ADDITIONAL_SENSE_CODE,
|
|
Packit |
dd8086 |
p_env->sense.ADDITIONAL_SENSE_CODE_QUALIFIER);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
for (i = 0; i < i_cdb; i++)
|
|
Packit |
dd8086 |
fprintf(stderr, "%02x ", cmdbuf[i]);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
fprintf(stderr, "\n");
|
|
Packit |
dd8086 |
memcpy((void *) p_env->gen.scsi_mmc_sense, &p_env->sense, kSenseDefaultSize);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return TR_UNKNOWN;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->sense.VALID_RESPONSE_CODE) {
|
|
Packit |
dd8086 |
char key = p_env->sense.SENSE_KEY & 0xf;
|
|
Packit |
dd8086 |
char ASC = p_env->sense.ADDITIONAL_SENSE_CODE;
|
|
Packit |
dd8086 |
char ASCQ = p_env->sense.ADDITIONAL_SENSE_CODE_QUALIFIER;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
switch (key) {
|
|
Packit |
dd8086 |
case 0:
|
|
Packit |
dd8086 |
if (errno == 0)
|
|
Packit |
dd8086 |
errno = EIO;
|
|
Packit |
dd8086 |
return (TR_UNKNOWN);
|
|
Packit |
dd8086 |
case 1:
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
case 2:
|
|
Packit |
dd8086 |
if (errno == 0)
|
|
Packit |
dd8086 |
errno = EBUSY;
|
|
Packit |
dd8086 |
return (TR_BUSY);
|
|
Packit |
dd8086 |
case 3:
|
|
Packit |
dd8086 |
if (ASC == 0x0C && ASCQ == 0x09) {
|
|
Packit |
dd8086 |
/* loss of streaming */
|
|
Packit |
dd8086 |
if (errno == 0)
|
|
Packit |
dd8086 |
errno = EIO;
|
|
Packit |
dd8086 |
return (TR_STREAMING);
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
if (errno == 0)
|
|
Packit |
dd8086 |
errno = EIO;
|
|
Packit |
dd8086 |
return (TR_MEDIUM);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
case 4:
|
|
Packit |
dd8086 |
if (errno == 0)
|
|
Packit |
dd8086 |
errno = EIO;
|
|
Packit |
dd8086 |
return (TR_FAULT);
|
|
Packit |
dd8086 |
case 5:
|
|
Packit |
dd8086 |
if (errno == 0)
|
|
Packit |
dd8086 |
errno = EINVAL;
|
|
Packit |
dd8086 |
return (TR_ILLEGAL);
|
|
Packit |
dd8086 |
default:
|
|
Packit |
dd8086 |
if (errno == 0)
|
|
Packit |
dd8086 |
errno = EIO;
|
|
Packit |
dd8086 |
return (TR_UNKNOWN);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
errno = 0;
|
|
Packit |
dd8086 |
return (0);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#if 0
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Run a SCSI MMC command.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdio CD structure set by cdio_open().
|
|
Packit |
dd8086 |
i_timeout time in milliseconds we will wait for the command
|
|
Packit |
dd8086 |
to complete. If this value is -1, use the default
|
|
Packit |
dd8086 |
time-out value.
|
|
Packit |
dd8086 |
p_buf Buffer for data, both sending and receiving
|
|
Packit |
dd8086 |
i_buf Size of buffer
|
|
Packit |
dd8086 |
e_direction direction the transfer is to go.
|
|
Packit |
dd8086 |
cdb CDB bytes. All values that are needed should be set on
|
|
Packit |
dd8086 |
input. We'll figure out what the right CDB length should be.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
We return true if command completed successfully and false if not.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static int
|
|
Packit |
dd8086 |
run_mmc_cmd_osx( const void *p_user_data,
|
|
Packit |
dd8086 |
unsigned int i_timeout_ms,
|
|
Packit |
dd8086 |
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
|
|
Packit |
dd8086 |
cdio_mmc_direction_t e_direction,
|
|
Packit |
dd8086 |
unsigned int i_buf, /*in/out*/ void *p_buf )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifndef SCSI_MMC_FIXED
|
|
Packit |
dd8086 |
return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
const _img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
SCSITaskDeviceInterface **sc;
|
|
Packit |
dd8086 |
SCSITaskInterface **cmd = NULL;
|
|
Packit |
dd8086 |
IOVirtualRange iov;
|
|
Packit |
dd8086 |
SCSI_Sense_Data senseData;
|
|
Packit |
dd8086 |
SCSITaskStatus status;
|
|
Packit |
dd8086 |
UInt64 bytesTransferred;
|
|
Packit |
dd8086 |
IOReturn ioReturnValue;
|
|
Packit |
dd8086 |
int ret = 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (NULL == p_user_data) return 2;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Make sure pp_scsiTaskDeviceInterface is initialized. FIXME: The code
|
|
Packit |
dd8086 |
should probably be reorganized better for this. */
|
|
Packit |
dd8086 |
if (!p_env->gen.toc_init) read_toc_osx (p_user_data) ;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
sc = p_env->pp_scsiTaskDeviceInterface;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (NULL == sc) return 3;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cmd = (*sc)->CreateSCSITask(sc);
|
|
Packit |
dd8086 |
if (cmd == NULL) {
|
|
Packit |
dd8086 |
cdio_warn("Failed to create SCSI task");
|
|
Packit |
dd8086 |
return -1;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
iov.address = (IOVirtualAddress) p_buf;
|
|
Packit |
dd8086 |
iov.length = i_buf;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ioReturnValue = (*cmd)->SetCommandDescriptorBlock(cmd, (UInt8 *) p_cdb,
|
|
Packit |
dd8086 |
i_cdb);
|
|
Packit |
dd8086 |
if (ioReturnValue != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
cdio_warn("SetCommandDescriptorBlock failed with status %x",
|
|
Packit |
dd8086 |
ioReturnValue);
|
|
Packit |
dd8086 |
return -1;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ioReturnValue = (*cmd)->SetScatterGatherEntries(cmd, &iov, 1, i_buf,
|
|
Packit |
dd8086 |
(SCSI_MMC_DATA_READ == e_direction ) ?
|
|
Packit |
dd8086 |
kSCSIDataTransfer_FromTargetToInitiator :
|
|
Packit |
dd8086 |
kSCSIDataTransfer_FromInitiatorToTarget);
|
|
Packit |
dd8086 |
if (ioReturnValue != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
cdio_warn("SetScatterGatherEntries failed with status %x", ioReturnValue);
|
|
Packit |
dd8086 |
return -1;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ioReturnValue = (*cmd)->SetTimeoutDuration(cmd, i_timeout_ms );
|
|
Packit |
dd8086 |
if (ioReturnValue != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
cdio_warn("SetTimeoutDuration failed with status %x", ioReturnValue);
|
|
Packit |
dd8086 |
return -1;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset(&senseData, 0, sizeof(senseData));
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ioReturnValue = (*cmd)->ExecuteTaskSync(cmd,&senseData, &status, &
|
|
Packit |
dd8086 |
bytesTransferred);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (ioReturnValue != kIOReturnSuccess) {
|
|
Packit |
dd8086 |
cdio_warn("Command execution failed with status %x", ioReturnValue);
|
|
Packit |
dd8086 |
return -1;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (cmd != NULL) {
|
|
Packit |
dd8086 |
(*cmd)->Release(cmd);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return (ret);
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
#endif /* 0*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/***************************************************************************
|
|
Packit |
dd8086 |
* GetDeviceIterator - Gets an io_iterator_t for our class type
|
|
Packit |
dd8086 |
***************************************************************************/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static io_iterator_t
|
|
Packit |
dd8086 |
GetDeviceIterator ( const char * deviceClass )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
IOReturn err = kIOReturnSuccess;
|
|
Packit |
dd8086 |
io_iterator_t iterator = MACH_PORT_NULL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
err = IOServiceGetMatchingServices ( kIOMasterPortDefault,
|
|
Packit |
dd8086 |
IOServiceMatching ( deviceClass ),
|
|
Packit |
dd8086 |
&iterator );
|
|
Packit |
dd8086 |
cdio_assert ( err == kIOReturnSuccess );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return iterator;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/***************************************************************************
|
|
Packit |
dd8086 |
* GetFeaturesFlagsForDrive -Gets the bitfield which represents the
|
|
Packit |
dd8086 |
* features flags.
|
|
Packit |
dd8086 |
***************************************************************************/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static bool
|
|
Packit |
dd8086 |
GetFeaturesFlagsForDrive ( CFDictionaryRef dict,
|
|
Packit |
dd8086 |
uint32_t *i_cdFlags,
|
|
Packit |
dd8086 |
uint32_t *i_dvdFlags )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
CFDictionaryRef propertiesDict = 0;
|
|
Packit |
dd8086 |
CFNumberRef flagsNumberRef = 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*i_cdFlags = 0;
|
|
Packit |
dd8086 |
*i_dvdFlags= 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
propertiesDict = ( CFDictionaryRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( dict,
|
|
Packit |
dd8086 |
CFSTR ( kIOPropertyDeviceCharacteristicsKey ) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( propertiesDict == 0 ) return false;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Get the CD features */
|
|
Packit |
dd8086 |
flagsNumberRef = ( CFNumberRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( propertiesDict,
|
|
Packit |
dd8086 |
CFSTR ( kIOPropertySupportedCDFeatures ) );
|
|
Packit |
dd8086 |
if ( flagsNumberRef != 0 ) {
|
|
Packit |
dd8086 |
CFNumberGetValue ( flagsNumberRef, kCFNumberLongType, i_cdFlags );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Get the DVD features */
|
|
Packit |
dd8086 |
flagsNumberRef = ( CFNumberRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( propertiesDict,
|
|
Packit |
dd8086 |
CFSTR ( kIOPropertySupportedDVDFeatures ) );
|
|
Packit |
dd8086 |
if ( flagsNumberRef != 0 ) {
|
|
Packit |
dd8086 |
CFNumberGetValue ( flagsNumberRef, kCFNumberLongType, i_dvdFlags );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return true;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get disc type associated with the cd object.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static discmode_t
|
|
Packit |
dd8086 |
get_discmode_osx (void *p_user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
char str[10];
|
|
Packit |
dd8086 |
int32_t i_discmode = CDIO_DISC_MODE_ERROR;
|
|
Packit |
dd8086 |
CFDictionaryRef propertiesDict = 0;
|
|
Packit |
dd8086 |
CFStringRef data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
propertiesDict = GetRegistryEntryProperties ( p_env->MediaClass_service );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( propertiesDict == 0 ) return i_discmode;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
data = ( CFStringRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( propertiesDict, CFSTR ( kIODVDMediaTypeKey ) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( CFStringGetCString( data, str, sizeof(str),
|
|
Packit |
dd8086 |
kCFStringEncodingASCII ) ) {
|
|
Packit |
dd8086 |
if (0 == strncmp(str, "DVD+R", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_DVD_PR;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "DVD+RW", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_DVD_PRW;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "DVD-R", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_DVD_R;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "DVD-RW", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_DVD_RW;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "DVD-ROM", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_DVD_ROM;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "DVD-RAM", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_DVD_RAM;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "CD-ROM", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_CD_DATA;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "CDR", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_CD_DATA;
|
|
Packit |
dd8086 |
else if (0 == strncmp(str, "CDRW", strlen(str)) )
|
|
Packit |
dd8086 |
i_discmode = CDIO_DISC_MODE_CD_DATA;
|
|
Packit |
dd8086 |
//?? Handled by below? CFRelease( data );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
CFRelease( propertiesDict );
|
|
Packit |
dd8086 |
if (CDIO_DISC_MODE_CD_DATA == i_discmode) {
|
|
Packit |
dd8086 |
/* Need to do more classification */
|
|
Packit |
dd8086 |
return get_discmode_cd_generic(p_user_data);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return i_discmode;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static io_service_t
|
|
Packit |
dd8086 |
get_drive_service_osx(const _img_private_t *p_env)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
io_service_t service;
|
|
Packit |
dd8086 |
io_iterator_t service_iterator;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
service_iterator = GetDeviceIterator ( kIOCDBlockStorageDeviceClassString );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( service_iterator == MACH_PORT_NULL ) return 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
service = IOIteratorNext( service_iterator );
|
|
Packit |
dd8086 |
if( service == 0 ) return 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
do
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
char psz_service[MAX_SERVICE_NAME];
|
|
Packit |
dd8086 |
IORegistryEntryGetPath(service, kIOServicePlane, psz_service);
|
|
Packit |
dd8086 |
psz_service[MAX_SERVICE_NAME-1] = '\0';
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* FIXME: This is all hoaky. Here we need info from a parent class,
|
|
Packit |
dd8086 |
psz_service of what we opened above. We are relying on the
|
|
Packit |
dd8086 |
fact that the name will be a substring of the name we
|
|
Packit |
dd8086 |
openned with.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
if (0 == strncmp(psz_service, p_env->psz_MediaClass_service,
|
|
Packit |
dd8086 |
strlen(psz_service))) {
|
|
Packit |
dd8086 |
/* Found our device */
|
|
Packit |
dd8086 |
IOObjectRelease( service_iterator );
|
|
Packit |
dd8086 |
return service;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
IOObjectRelease( service );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
} while( ( service = IOIteratorNext( service_iterator ) ) != 0 );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
IOObjectRelease( service_iterator );
|
|
Packit |
dd8086 |
return service;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static void
|
|
Packit |
dd8086 |
get_drive_cap_osx(const void *p_user_data,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_read_cap_t *p_read_cap,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_write_cap_t *p_write_cap,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_misc_cap_t *p_misc_cap)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
const _img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
uint32_t i_cdFlags;
|
|
Packit |
dd8086 |
uint32_t i_dvdFlags;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
io_service_t service = get_drive_service_osx(p_env);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( service == 0 ) goto err_exit;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Found our device */
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
CFDictionaryRef properties = GetRegistryEntryProperties ( service );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (! GetFeaturesFlagsForDrive ( properties, &i_cdFlags,
|
|
Packit |
dd8086 |
&i_dvdFlags ) ) {
|
|
Packit |
dd8086 |
IOObjectRelease( service );
|
|
Packit |
dd8086 |
goto err_exit;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Reader */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_cdFlags & kCDFeaturesAnalogAudioMask) )
|
|
Packit |
dd8086 |
*p_read_cap |= CDIO_DRIVE_CAP_READ_AUDIO;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_cdFlags & kCDFeaturesWriteOnceMask) )
|
|
Packit |
dd8086 |
*p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_R;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_cdFlags & kCDFeaturesCDDAStreamAccurateMask) )
|
|
Packit |
dd8086 |
*p_read_cap |= CDIO_DRIVE_CAP_READ_CD_DA;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_dvdFlags & kDVDFeaturesReadStructuresMask) )
|
|
Packit |
dd8086 |
*p_read_cap |= CDIO_DRIVE_CAP_READ_DVD_ROM;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_cdFlags & kCDFeaturesReWriteableMask) )
|
|
Packit |
dd8086 |
*p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_RW;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_dvdFlags & kDVDFeaturesWriteOnceMask) )
|
|
Packit |
dd8086 |
*p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_R;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_dvdFlags & kDVDFeaturesRandomWriteableMask) )
|
|
Packit |
dd8086 |
*p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_RAM;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_dvdFlags & kDVDFeaturesReWriteableMask) )
|
|
Packit |
dd8086 |
*p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_RW;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/***
|
|
Packit |
dd8086 |
if ( 0 != (i_dvdFlags & kDVDFeaturesPlusRMask) )
|
|
Packit |
dd8086 |
*p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_PR;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 != (i_dvdFlags & kDVDFeaturesPlusRWMask )
|
|
Packit |
dd8086 |
*p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_PRW;
|
|
Packit |
dd8086 |
***/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* FIXME: fill out. For now assume CD-ROM is relatively modern. */
|
|
Packit |
dd8086 |
*p_misc_cap = (
|
|
Packit |
dd8086 |
CDIO_DRIVE_CAP_MISC_CLOSE_TRAY
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_MISC_EJECT
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_MISC_LOCK
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_MISC_SELECT_SPEED
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_MISC_MULTI_SESSION
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_MISC_RESET
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_READ_MCN
|
|
Packit |
dd8086 |
| CDIO_DRIVE_CAP_READ_ISRC
|
|
Packit |
dd8086 |
);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
IOObjectRelease( service );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
err_exit:
|
|
Packit |
dd8086 |
*p_misc_cap = *p_write_cap = *p_read_cap = CDIO_DRIVE_CAP_UNKNOWN;
|
|
Packit |
dd8086 |
return;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#if 1
|
|
Packit |
dd8086 |
/****************************************************************************
|
|
Packit |
dd8086 |
* GetDriveDescription - Gets drive description.
|
|
Packit |
dd8086 |
****************************************************************************/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static bool
|
|
Packit |
dd8086 |
get_hwinfo_osx ( const CdIo_t *p_cdio, /*out*/ cdio_hwinfo_t *hw_info)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = (_img_private_t *) p_cdio->env;
|
|
Packit |
dd8086 |
io_service_t service = get_drive_service_osx(p_env);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( service == 0 ) return false;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Found our device */
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
CFStringRef vendor = NULL;
|
|
Packit |
dd8086 |
CFStringRef product = NULL;
|
|
Packit |
dd8086 |
CFStringRef revision = NULL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CFDictionaryRef properties = GetRegistryEntryProperties ( service );
|
|
Packit |
dd8086 |
CFDictionaryRef deviceDict = ( CFDictionaryRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( properties,
|
|
Packit |
dd8086 |
CFSTR ( kIOPropertyDeviceCharacteristicsKey ) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( deviceDict == 0 ) return false;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
vendor = ( CFStringRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyVendorNameKey ) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( CFStringGetCString( vendor,
|
|
Packit |
dd8086 |
(char *) &(hw_info->psz_vendor),
|
|
Packit |
dd8086 |
sizeof(hw_info->psz_vendor),
|
|
Packit |
dd8086 |
kCFStringEncodingASCII ) )
|
|
Packit |
dd8086 |
CFRelease( vendor );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
product = ( CFStringRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyProductNameKey ) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( CFStringGetCString( product,
|
|
Packit |
dd8086 |
(char *) &(hw_info->psz_model),
|
|
Packit |
dd8086 |
sizeof(hw_info->psz_model),
|
|
Packit |
dd8086 |
kCFStringEncodingASCII ) )
|
|
Packit |
dd8086 |
CFRelease( product );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
revision = ( CFStringRef )
|
|
Packit |
dd8086 |
CFDictionaryGetValue ( deviceDict,
|
|
Packit |
dd8086 |
CFSTR ( kIOPropertyProductRevisionLevelKey ) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( CFStringGetCString( revision,
|
|
Packit |
dd8086 |
(char *) &(hw_info->psz_revision),
|
|
Packit |
dd8086 |
sizeof(hw_info->psz_revision),
|
|
Packit |
dd8086 |
kCFStringEncodingASCII ) )
|
|
Packit |
dd8086 |
CFRelease( revision );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return true;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static void
|
|
Packit |
dd8086 |
_free_osx (void *p_user_data) {
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
if (NULL == p_env) return;
|
|
Packit |
dd8086 |
if (p_env->gen.fd != -1)
|
|
Packit |
dd8086 |
close(p_env->gen.fd);
|
|
Packit |
dd8086 |
if (p_env->MediaClass_service)
|
|
Packit |
dd8086 |
IOObjectRelease( p_env->MediaClass_service );
|
|
Packit |
dd8086 |
cdio_generic_free(p_env);
|
|
Packit |
dd8086 |
if (NULL != p_env->pp_lba) free((void *) p_env->pp_lba);
|
|
Packit |
dd8086 |
if (NULL != p_env->pTOC) free((void *) p_env->pTOC);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->scsi_task)
|
|
Packit |
dd8086 |
(*p_env->scsi_task)->Release(p_env->scsi_task);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->pp_scsiTaskDeviceInterface)
|
|
Packit |
dd8086 |
(*p_env->pp_scsiTaskDeviceInterface) ->
|
|
Packit |
dd8086 |
ReleaseExclusiveAccess(p_env->pp_scsiTaskDeviceInterface);
|
|
Packit |
dd8086 |
if (p_env->pp_scsiTaskDeviceInterface)
|
|
Packit |
dd8086 |
(*p_env->pp_scsiTaskDeviceInterface) ->
|
|
Packit |
dd8086 |
Release ( p_env->pp_scsiTaskDeviceInterface );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->mmc)
|
|
Packit |
dd8086 |
(*p_env->mmc)->Release(p_env->mmc);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->plugin)
|
|
Packit |
dd8086 |
IODestroyPlugInInterface(p_env->plugin);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Reads i_blocks of data sectors from cd device into p_data starting
|
|
Packit |
dd8086 |
from i_lsn.
|
|
Packit |
dd8086 |
Returns DRIVER_OP_SUCCESS if no error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
read_data_sectors_osx (void *p_user_data, void *p_data, lsn_t i_lsn,
|
|
Packit |
dd8086 |
uint16_t i_blocksize, uint32_t i_blocks)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_user_data) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
dk_cd_read_t cd_read;
|
|
Packit |
dd8086 |
track_t i_track = cdio_get_track(p_env->gen.cdio, i_lsn);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.sectorArea = kCDSectorAreaUser;
|
|
Packit |
dd8086 |
cd_read.buffer = p_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* FIXME: Do I have to put use get_track_green_osx? */
|
|
Packit |
dd8086 |
switch(get_track_format_osx(p_user_data, i_track)) {
|
|
Packit |
dd8086 |
case TRACK_FORMAT_CDI:
|
|
Packit |
dd8086 |
case TRACK_FORMAT_DATA:
|
|
Packit |
dd8086 |
cd_read.sectorType = kCDSectorTypeMode1;
|
|
Packit |
dd8086 |
cd_read.offset = i_lsn * kCDSectorSizeMode1;
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
case TRACK_FORMAT_XA:
|
|
Packit |
dd8086 |
cd_read.sectorType = kCDSectorTypeMode2;
|
|
Packit |
dd8086 |
cd_read.offset = i_lsn * kCDSectorSizeMode2;
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
default:
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.bufferLength = i_blocksize * i_blocks;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( p_env->gen.fd, DKIOCCDREAD, &cd_read ) == -1 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_info( "could not read block %d, %s", i_lsn, strerror(errno) );
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Reads i_blocks of mode2 form2 sectors from cd device into data starting
|
|
Packit |
dd8086 |
from i_lsn.
|
|
Packit |
dd8086 |
Returns 0 if no error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
read_mode1_sectors_osx (void *p_user_data, void *p_data, lsn_t i_lsn,
|
|
Packit |
dd8086 |
bool b_form2, uint32_t i_blocks)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
dk_cd_read_t cd_read;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.sectorArea = kCDSectorAreaUser;
|
|
Packit |
dd8086 |
cd_read.buffer = p_data;
|
|
Packit |
dd8086 |
cd_read.sectorType = kCDSectorTypeMode1;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (b_form2) {
|
|
Packit |
dd8086 |
cd_read.offset = i_lsn * kCDSectorSizeMode2;
|
|
Packit |
dd8086 |
cd_read.bufferLength = kCDSectorSizeMode2 * i_blocks;
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
cd_read.offset = i_lsn * kCDSectorSizeMode1;
|
|
Packit |
dd8086 |
cd_read.bufferLength = kCDSectorSizeMode1 * i_blocks;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( p_env->gen.fd, DKIOCCDREAD, &cd_read ) == -1 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_info( "could not read block %d, %s", i_lsn, strerror(errno) );
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Reads i_blocks of mode2 form2 sectors from cd device into data starting
|
|
Packit |
dd8086 |
from lsn.
|
|
Packit |
dd8086 |
Returns DRIVER_OP_SUCCESS if no error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
read_mode2_sectors_osx (void *p_user_data, void *p_data, lsn_t i_lsn,
|
|
Packit |
dd8086 |
bool b_form2, uint32_t i_blocks)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
dk_cd_read_t cd_read;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.sectorArea = kCDSectorAreaUser;
|
|
Packit |
dd8086 |
cd_read.buffer = p_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (b_form2) {
|
|
Packit |
dd8086 |
cd_read.offset = i_lsn * kCDSectorSizeMode2Form2;
|
|
Packit |
dd8086 |
cd_read.sectorType = kCDSectorTypeMode2Form2;
|
|
Packit |
dd8086 |
cd_read.bufferLength = kCDSectorSizeMode2Form2 * i_blocks;
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
cd_read.offset = i_lsn * kCDSectorSizeMode2Form1;
|
|
Packit |
dd8086 |
cd_read.sectorType = kCDSectorTypeMode2Form1;
|
|
Packit |
dd8086 |
cd_read.bufferLength = kCDSectorSizeMode2Form1 * i_blocks;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( p_env->gen.fd, DKIOCCDREAD, &cd_read ) == -1 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_info( "could not read block %d, %s", i_lsn, strerror(errno) );
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Reads a single audio sector from CD device into p_data starting from lsn.
|
|
Packit |
dd8086 |
Returns 0 if no error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static int
|
|
Packit |
dd8086 |
read_audio_sectors_osx (void *user_data, void *p_data, lsn_t lsn,
|
|
Packit |
dd8086 |
unsigned int i_blocks)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *env = user_data;
|
|
Packit |
dd8086 |
dk_cd_read_t cd_read;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.offset = lsn * kCDSectorSizeCDDA;
|
|
Packit |
dd8086 |
cd_read.sectorArea = kCDSectorAreaUser;
|
|
Packit |
dd8086 |
cd_read.sectorType = kCDSectorTypeCDDA;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.buffer = p_data;
|
|
Packit |
dd8086 |
cd_read.bufferLength = kCDSectorSizeCDDA * i_blocks;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( env->gen.fd, DKIOCCDREAD, &cd_read ) == -1 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_info( "could not read block %d\n%s", lsn,
|
|
Packit |
dd8086 |
strerror(errno));
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Reads a single mode2 sector from cd device into p_data starting
|
|
Packit |
dd8086 |
from lsn. Returns 0 if no error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
read_mode1_sector_osx (void *p_user_data, void *p_data, lsn_t i_lsn,
|
|
Packit |
dd8086 |
bool b_form2)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return read_mode1_sectors_osx(p_user_data, p_data, i_lsn, b_form2, 1);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Reads a single mode2 sector from cd device into p_data starting
|
|
Packit |
dd8086 |
from lsn. Returns 0 if no error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
read_mode2_sector_osx (void *p_user_data, void *p_data, lsn_t i_lsn,
|
|
Packit |
dd8086 |
bool b_form2)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return read_mode2_sectors_osx(p_user_data, p_data, i_lsn, b_form2, 1);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Set the key "arg" to "value" in source device.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
_set_arg_osx (void *p_user_data, const char key[], const char value[])
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!strcmp (key, "source"))
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if (!value) return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
free (p_env->gen.source_name);
|
|
Packit |
dd8086 |
p_env->gen.source_name = strdup (value);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
else if (!strcmp (key, "access-mode"))
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if (!strcmp(value, "OSX"))
|
|
Packit |
dd8086 |
p_env->access_mode = _AM_OSX;
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
cdio_warn ("unknown access type: %s. ignored.", value);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
else return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#if 0
|
|
Packit |
dd8086 |
static void
|
|
Packit |
dd8086 |
TestDevice(_img_private_t *p_env, io_service_t service)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
SInt32 score;
|
|
Packit |
dd8086 |
HRESULT herr;
|
|
Packit |
dd8086 |
kern_return_t err;
|
|
Packit |
dd8086 |
IOCFPlugInInterface **plugInInterface = NULL;
|
|
Packit |
dd8086 |
MMCDeviceInterface **mmcInterface = NULL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Create the IOCFPlugIn interface so we can query it. */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
err = IOCreatePlugInInterfaceForService ( service,
|
|
Packit |
dd8086 |
kIOMMCDeviceUserClientTypeID,
|
|
Packit |
dd8086 |
kIOCFPlugInInterfaceID,
|
|
Packit |
dd8086 |
&plugInInterface,
|
|
Packit |
dd8086 |
&score );
|
|
Packit |
dd8086 |
if ( err != noErr ) {
|
|
Packit |
dd8086 |
printf("IOCreatePlugInInterfaceForService returned %d\n", err);
|
|
Packit |
dd8086 |
return;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Query the interface for the MMCDeviceInterface. */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
herr = ( *plugInInterface )->QueryInterface ( plugInInterface,
|
|
Packit |
dd8086 |
CFUUIDGetUUIDBytes ( kIOMMCDeviceInterfaceID ),
|
|
Packit |
dd8086 |
( LPVOID ) &mmcInterface );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( herr != S_OK ) {
|
|
Packit |
dd8086 |
printf("QueryInterface returned %ld\n", herr);
|
|
Packit |
dd8086 |
return;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->pp_scsiTaskDeviceInterface =
|
|
Packit |
dd8086 |
( *mmcInterface )->GetSCSITaskDeviceInterface ( mmcInterface );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( NULL == p_env->pp_scsiTaskDeviceInterface ) {
|
|
Packit |
dd8086 |
printf("GetSCSITaskDeviceInterface returned NULL\n");
|
|
Packit |
dd8086 |
return;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
( *mmcInterface )->Release ( mmcInterface );
|
|
Packit |
dd8086 |
IODestroyPlugInInterface ( plugInInterface );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Read and cache the CD's Track Table of Contents and track info.
|
|
Packit |
dd8086 |
Return false if successful or true if an error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static bool
|
|
Packit |
dd8086 |
read_toc_osx (void *p_user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
CFDictionaryRef propertiesDict = 0;
|
|
Packit |
dd8086 |
CFDataRef data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* create a CF dictionary containing the TOC */
|
|
Packit |
dd8086 |
propertiesDict = GetRegistryEntryProperties( p_env->MediaClass_service );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( 0 == propertiesDict ) {
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* get the TOC from the dictionary */
|
|
Packit |
dd8086 |
data = (CFDataRef) CFDictionaryGetValue( propertiesDict,
|
|
Packit |
dd8086 |
CFSTR(kIOCDMediaTOCKey) );
|
|
Packit |
dd8086 |
if ( data != NULL ) {
|
|
Packit |
dd8086 |
CFRange range;
|
|
Packit |
dd8086 |
CFIndex buf_len;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
buf_len = CFDataGetLength( data ) + 1;
|
|
Packit |
dd8086 |
range = CFRangeMake( 0, buf_len );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ( p_env->pTOC = (CDTOC *)malloc( buf_len ) ) != NULL ) {
|
|
Packit |
dd8086 |
CFDataGetBytes( data, range, (u_char *) p_env->pTOC );
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
cdio_warn( "Trouble allocating CDROM TOC" );
|
|
Packit |
dd8086 |
CFRelease( propertiesDict );
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
cdio_warn( "Trouble reading TOC" );
|
|
Packit |
dd8086 |
CFRelease( propertiesDict );
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* TestDevice(p_env, service); */
|
|
Packit |
dd8086 |
CFRelease( propertiesDict );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->i_descriptors = CDTOCGetDescriptorCount ( p_env->pTOC );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Read in starting sectors. There may be non-tracks mixed in with
|
|
Packit |
dd8086 |
the real tracks. So find the first and last track number by
|
|
Packit |
dd8086 |
scanning. Also find the lead-out track position.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
int i, i_leadout = -1;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDTOCDescriptor *pTrackDescriptors;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->pp_lba = malloc( p_env->i_descriptors * sizeof(int) );
|
|
Packit |
dd8086 |
if( p_env->pp_lba == NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_warn("Out of memory in allocating track starting LSNs" );
|
|
Packit |
dd8086 |
free( p_env->pTOC );
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
pTrackDescriptors = p_env->pTOC->descriptors;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->gen.i_first_track = CDIO_CD_MAX_TRACKS+1;
|
|
Packit |
dd8086 |
p_env->i_last_track = CDIO_CD_MIN_TRACK_NO;
|
|
Packit |
dd8086 |
p_env->i_first_session = CDIO_CD_MAX_TRACKS+1;
|
|
Packit |
dd8086 |
p_env->i_last_session = CDIO_CD_MIN_TRACK_NO;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
for( i = 0; i < p_env->i_descriptors; i++ )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
track_t i_track = pTrackDescriptors[i].point;
|
|
Packit |
dd8086 |
session_t i_session = pTrackDescriptors[i].session;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdio_debug( "point: %d, tno: %d, session: %d, adr: %d, control:%d, "
|
|
Packit |
dd8086 |
"address: %d:%d:%d, p: %d:%d:%d",
|
|
Packit |
dd8086 |
i_track,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].tno, i_session,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].adr, pTrackDescriptors[i].control,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].address.minute,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].address.second,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].address.frame,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].p.minute,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].p.second,
|
|
Packit |
dd8086 |
pTrackDescriptors[i].p.frame );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* track information has adr = 1 */
|
|
Packit |
dd8086 |
if ( 0x01 != pTrackDescriptors[i].adr )
|
|
Packit |
dd8086 |
continue;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( i_track == OSX_CDROM_LEADOUT_TRACK )
|
|
Packit |
dd8086 |
i_leadout = i;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( i_track > CDIO_CD_MAX_TRACKS || i_track < CDIO_CD_MIN_TRACK_NO )
|
|
Packit |
dd8086 |
continue;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->gen.i_first_track > i_track)
|
|
Packit |
dd8086 |
p_env->gen.i_first_track = i_track;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->i_last_track < i_track)
|
|
Packit |
dd8086 |
p_env->i_last_track = i_track;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->i_first_session > i_session)
|
|
Packit |
dd8086 |
p_env->i_first_session = i_session;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->i_last_session < i_session)
|
|
Packit |
dd8086 |
p_env->i_last_session = i_session;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Now that we know what the first track number is, we can make sure
|
|
Packit |
dd8086 |
index positions are ordered starting at 0.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
for( i = 0; i < p_env->i_descriptors; i++ )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
track_t i_track = pTrackDescriptors[i].point;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( i_track > CDIO_CD_MAX_TRACKS || i_track < CDIO_CD_MIN_TRACK_NO )
|
|
Packit |
dd8086 |
continue;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Note what OSX calls a LBA we call an LSN. So below re we
|
|
Packit |
dd8086 |
really have have MSF -> LSN -> LBA.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
p_env->pp_lba[i_track - p_env->gen.i_first_track] =
|
|
Packit |
dd8086 |
cdio_lsn_to_lba(CDConvertMSFToLBA( pTrackDescriptors[i].p ));
|
|
Packit |
dd8086 |
set_track_flags(&(p_env->gen.track_flags[i_track]),
|
|
Packit |
dd8086 |
pTrackDescriptors[i].control);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( i_leadout == -1 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_warn( "CD leadout not found" );
|
|
Packit |
dd8086 |
free( p_env->pp_lba );
|
|
Packit |
dd8086 |
free( (void *) p_env->pTOC );
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Set leadout sector.
|
|
Packit |
dd8086 |
Note what OSX calls a LBA we call an LSN. So below re we
|
|
Packit |
dd8086 |
really have have MSF -> LSN -> LBA.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
p_env->pp_lba[TOTAL_TRACKS] =
|
|
Packit |
dd8086 |
cdio_lsn_to_lba(CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p ));
|
|
Packit |
dd8086 |
p_env->gen.i_tracks = TOTAL_TRACKS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
p_env->gen.toc_init = true;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return( true );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the starting LSN track number
|
|
Packit |
dd8086 |
i_track in obj. Track numbers start at 1.
|
|
Packit |
dd8086 |
The "leadout" track is specified either by
|
|
Packit |
dd8086 |
using i_track LEADOUT_TRACK or the total tracks+1.
|
|
Packit |
dd8086 |
False is returned if there is no track entry.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static lsn_t
|
|
Packit |
dd8086 |
get_track_lba_osx(void *p_user_data, track_t i_track)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env->gen.toc_init) read_toc_osx (p_env) ;
|
|
Packit |
dd8086 |
if (!p_env->gen.toc_init) return CDIO_INVALID_LSN;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = p_env->i_last_track+1;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_track > p_env->i_last_track + 1 || i_track < p_env->gen.i_first_track) {
|
|
Packit |
dd8086 |
return CDIO_INVALID_LSN;
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
return p_env->pp_lba[i_track - p_env->gen.i_first_track];
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Eject media . Return DRIVER_OP_SUCCESS if successful.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
The only way to cleanly unmount the disc under MacOS X (before
|
|
Packit |
dd8086 |
Tiger) is to use the 'disktool' command line utility. It uses the
|
|
Packit |
dd8086 |
non-public DiskArbitration API, which can not be used by Cocoa or
|
|
Packit |
dd8086 |
Carbon applications.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Since Tiger (MacOS X 10.4), DiskArbitration is a public framework
|
|
Packit |
dd8086 |
and we can use it as needed.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifndef HAVE_DISKARBITRATION
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
_eject_media_osx (void *user_data) {
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
_img_private_t *p_env = user_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
FILE *p_file;
|
|
Packit |
dd8086 |
char *psz_drive;
|
|
Packit |
dd8086 |
char sz_cmd[32];
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ( psz_drive = (char *)strstr( p_env->gen.source_name, "disk" ) ) != NULL &&
|
|
Packit |
dd8086 |
strlen( psz_drive ) > 4 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
#define EJECT_CMD "/usr/sbin/hdiutil eject %s"
|
|
Packit |
dd8086 |
snprintf( sz_cmd, sizeof(sz_cmd), EJECT_CMD, psz_drive );
|
|
Packit |
dd8086 |
#undef EJECT_CMD
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ( p_file = popen( sz_cmd, "r" ) ) != NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
char psz_result[0x200];
|
|
Packit |
dd8086 |
int i_ret = fread( psz_result, 1, sizeof(psz_result) - 1, p_file );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( i_ret == 0 && ferror( p_file ) != 0 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
pclose( p_file );
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
pclose( p_file );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
psz_result[ i_ret ] = 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( strstr( psz_result, "Disk Ejected" ) != NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
#else /* HAVE_DISKARBITRATION */
|
|
Packit |
dd8086 |
typedef struct dacontext_s {
|
|
Packit |
dd8086 |
int result;
|
|
Packit |
dd8086 |
Boolean completed;
|
|
Packit |
dd8086 |
DASessionRef session;
|
|
Packit |
dd8086 |
CFRunLoopRef runloop;
|
|
Packit |
dd8086 |
CFRunLoopSourceRef cancel;
|
|
Packit |
dd8086 |
} dacontext_t;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static void cancel_runloop(void *info) { /* do nothing */ }
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static CFRunLoopSourceContext cancelRunLoopSourceContext = {
|
|
Packit |
dd8086 |
.perform = cancel_runloop
|
|
Packit |
dd8086 |
};
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static void media_eject_callback(DADiskRef disk, DADissenterRef dissenter, void *context)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
dacontext_t *dacontext = (dacontext_t *)context;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( dissenter )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
CFStringRef status = DADissenterGetStatusString(dissenter);
|
|
Packit |
dd8086 |
if (status)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
size_t cstr_size = CFStringGetLength(status);
|
|
Packit |
dd8086 |
char *cstr = malloc(cstr_size);
|
|
Packit |
dd8086 |
if ( CFStringGetCString( status,
|
|
Packit |
dd8086 |
cstr, cstr_size,
|
|
Packit |
dd8086 |
kCFStringEncodingASCII ) )
|
|
Packit |
dd8086 |
CFRelease( status );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdio_warn("%s", cstr);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
free(cstr);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
dacontext->result = (dissenter ? DRIVER_OP_ERROR : DRIVER_OP_SUCCESS);
|
|
Packit |
dd8086 |
dacontext->completed = TRUE;
|
|
Packit |
dd8086 |
CFRunLoopSourceSignal(dacontext->cancel);
|
|
Packit |
dd8086 |
CFRunLoopWakeUp(dacontext->runloop);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static void media_unmount_callback(DADiskRef disk, DADissenterRef dissenter, void *context)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
dacontext_t *dacontext = (dacontext_t *)context;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!dissenter) {
|
|
Packit |
dd8086 |
DADiskEject(disk, kDADiskEjectOptionDefault, media_eject_callback, context);
|
|
Packit |
dd8086 |
dacontext->result = dacontext->result == DRIVER_OP_UNINIT ? DRIVER_OP_SUCCESS : dacontext->result;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
else {
|
|
Packit |
dd8086 |
dacontext->result = DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
dacontext->completed = TRUE;
|
|
Packit |
dd8086 |
CFRunLoopSourceSignal(dacontext->cancel);
|
|
Packit |
dd8086 |
CFRunLoopWakeUp(dacontext->runloop);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
static driver_return_code_t
|
|
Packit |
dd8086 |
_eject_media_osx (void *user_data) {
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
_img_private_t *p_env = user_data;
|
|
Packit |
dd8086 |
char *psz_drive;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
DADiskRef disk;
|
|
Packit |
dd8086 |
dacontext_t dacontext;
|
|
Packit |
dd8086 |
CFDictionaryRef description;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ( psz_drive = (char *)strstr( p_env->gen.source_name, "disk" ) ) == NULL ||
|
|
Packit |
dd8086 |
strlen( psz_drive ) <= 4 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (p_env->gen.fd != -1)
|
|
Packit |
dd8086 |
close(p_env->gen.fd);
|
|
Packit |
dd8086 |
p_env->gen.fd = -1;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
dacontext.result = DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
dacontext.completed = FALSE;
|
|
Packit |
dd8086 |
dacontext.runloop = CFRunLoopGetCurrent();
|
|
Packit |
dd8086 |
dacontext.cancel = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &cancelRunLoopSourceContext);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!dacontext.cancel)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!(dacontext.session = DASessionCreate(kCFAllocatorDefault)))
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
CFRelease(dacontext.cancel);
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ((disk = DADiskCreateFromBSDName(kCFAllocatorDefault, dacontext.session, psz_drive)) != NULL)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if ((description = DADiskCopyDescription(disk)) != NULL)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
/* Does the device need to be unmounted first? */
|
|
Packit |
dd8086 |
DASessionScheduleWithRunLoop(dacontext.session, dacontext.runloop, kCFRunLoopDefaultMode);
|
|
Packit |
dd8086 |
CFRunLoopAddSource(dacontext.runloop, dacontext.cancel, kCFRunLoopDefaultMode);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (CFDictionaryGetValueIfPresent(description, kDADiskDescriptionVolumePathKey, NULL))
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
DADiskUnmount(disk, kDADiskUnmountOptionWhole, media_unmount_callback, &dacontext);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
DADiskEject(disk, kDADiskEjectOptionDefault, media_eject_callback, &dacontext);
|
|
Packit |
dd8086 |
dacontext.result = dacontext.result == DRIVER_OP_UNINIT ? DRIVER_OP_SUCCESS : dacontext.result;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
while (!dacontext.completed)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 30.0, TRUE) == kCFRunLoopRunTimedOut) break; /* timeout after 30 seconds */
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
CFRunLoopRemoveSource(dacontext.runloop, dacontext.cancel, kCFRunLoopDefaultMode);
|
|
Packit |
dd8086 |
DASessionUnscheduleFromRunLoop(dacontext.session, dacontext.runloop, kCFRunLoopDefaultMode);
|
|
Packit |
dd8086 |
CFRelease(description);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
CFRelease(disk);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CFRunLoopSourceInvalidate(dacontext.cancel);
|
|
Packit |
dd8086 |
CFRelease(dacontext.cancel);
|
|
Packit |
dd8086 |
CFRelease(dacontext.session);
|
|
Packit |
dd8086 |
return dacontext.result;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the size of the CD in logical block address (LBA) units.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static lsn_t
|
|
Packit |
dd8086 |
get_disc_last_lsn_osx (void *user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return get_track_lba_osx(user_data, CDIO_CDROM_LEADOUT_TRACK);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the value associated with the key "arg".
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static const char *
|
|
Packit |
dd8086 |
_get_arg_osx (void *user_data, const char key[])
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = user_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!strcmp (key, "source")) {
|
|
Packit |
dd8086 |
return p_env->gen.source_name;
|
|
Packit |
dd8086 |
} else if (!strcmp (key, "access-mode")) {
|
|
Packit |
dd8086 |
switch (p_env->access_mode) {
|
|
Packit |
dd8086 |
case _AM_OSX:
|
|
Packit |
dd8086 |
return "OS X";
|
|
Packit |
dd8086 |
case _AM_NONE:
|
|
Packit |
dd8086 |
return "no access method";
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the media catalog number MCN.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static char *
|
|
Packit |
dd8086 |
get_mcn_osx (const void *user_data) {
|
|
Packit |
dd8086 |
const _img_private_t *p_env = user_data;
|
|
Packit |
dd8086 |
dk_cd_read_mcn_t cd_read;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( p_env->gen.fd, DKIOCCDREADMCN, &cd_read ) < 0 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_debug( "could not read MCN, %s", strerror(errno) );
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return strdup((char*)cd_read.mcn);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the international standard recording code ISRC.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static char *
|
|
Packit |
dd8086 |
get_track_isrc_osx (const void *user_data, track_t i_track) {
|
|
Packit |
dd8086 |
const _img_private_t *p_env = user_data;
|
|
Packit |
dd8086 |
dk_cd_read_isrc_t cd_read;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.track = i_track;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( p_env->gen.fd, DKIOCCDREADISRC, &cd_read ) < 0 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_debug( "could not read ISRC, %s", strerror(errno) );
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return strdup((char*)cd_read.isrc);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get format of track.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static track_format_t
|
|
Packit |
dd8086 |
get_track_format_osx(void *p_user_data, track_t i_track)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
dk_cd_read_track_info_t cd_read;
|
|
Packit |
dd8086 |
CDTrackInfo a_track;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env->gen.toc_init) read_toc_osx (p_env) ;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_track > p_env->i_last_track || i_track < p_env->gen.i_first_track)
|
|
Packit |
dd8086 |
return TRACK_FORMAT_ERROR;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.address = i_track;
|
|
Packit |
dd8086 |
cd_read.addressType = kCDTrackInfoAddressTypeTrackNumber;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.buffer = &a_track;
|
|
Packit |
dd8086 |
cd_read.bufferLength = sizeof(CDTrackInfo);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( p_env->gen.fd, DKIOCCDREADTRACKINFO, &cd_read ) == -1 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_warn( "could not read trackinfo for track %d:\n%s", i_track,
|
|
Packit |
dd8086 |
strerror(errno));
|
|
Packit |
dd8086 |
return TRACK_FORMAT_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdio_debug( "%d: trackinfo trackMode: %x dataMode: %x", i_track,
|
|
Packit |
dd8086 |
a_track.trackMode, a_track.dataMode );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (a_track.trackMode == CDIO_CDROM_DATA_TRACK) {
|
|
Packit |
dd8086 |
if (a_track.dataMode == CDROM_CDI_TRACK) {
|
|
Packit |
dd8086 |
return TRACK_FORMAT_CDI;
|
|
Packit |
dd8086 |
} else if (a_track.dataMode == CDROM_XA_TRACK) {
|
|
Packit |
dd8086 |
return TRACK_FORMAT_XA;
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
return TRACK_FORMAT_DATA;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
return TRACK_FORMAT_AUDIO;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return true if we have XA data (green, mode2 form1) or
|
|
Packit |
dd8086 |
XA data (green, mode2 form2). That is track begins:
|
|
Packit |
dd8086 |
sync - header - subheader
|
|
Packit |
dd8086 |
12 4 - 8
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
FIXME: there's gotta be a better design for this and get_track_format?
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
static bool
|
|
Packit |
dd8086 |
get_track_green_osx(void *p_user_data, track_t i_track)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
CDTrackInfo a_track;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env->gen.toc_init) read_toc_osx (p_env) ;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( i_track > p_env->i_last_track || i_track < p_env->gen.i_first_track )
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
else {
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
dk_cd_read_track_info_t cd_read;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset( &cd_read, 0, sizeof(cd_read) );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.address = i_track;
|
|
Packit |
dd8086 |
cd_read.addressType = kCDTrackInfoAddressTypeTrackNumber;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cd_read.buffer = &a_track;
|
|
Packit |
dd8086 |
cd_read.bufferLength = sizeof(CDTrackInfo);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ioctl( p_env->gen.fd, DKIOCCDREADTRACKINFO, &cd_read ) == -1 ) {
|
|
Packit |
dd8086 |
cdio_warn( "could not read trackinfo for track %d:\n%s", i_track,
|
|
Packit |
dd8086 |
strerror(errno));
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return ((a_track.trackMode & CDIO_CDROM_DATA_TRACK) != 0);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Set CD-ROM drive speed */
|
|
Packit |
dd8086 |
static int
|
|
Packit |
dd8086 |
set_speed_osx (void *p_user_data, int i_speed)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
const _img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env) return -1;
|
|
Packit |
dd8086 |
return ioctl(p_env->gen.fd, DKIOCCDSETSPEED, i_speed);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#endif /* HAVE_DARWIN_CDROM */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Close tray on CD-ROM.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param psz_drive the CD-ROM drive to be closed.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* FIXME: We don't use the device name because we don't how
|
|
Packit |
dd8086 |
to.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
#define CLOSE_TRAY_CMD "/usr/sbin/drutil tray close"
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
close_tray_osx (const char *psz_drive)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
#ifdef HAVE_DARWIN_CDROM
|
|
Packit |
dd8086 |
FILE *p_file;
|
|
Packit |
dd8086 |
char sz_cmd[80];
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( !psz_drive) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Right now we really aren't making use of snprintf, but
|
|
Packit |
dd8086 |
possibly someday we will.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
snprintf( sz_cmd, sizeof(sz_cmd), CLOSE_TRAY_CMD );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( ( p_file = popen( sz_cmd, "r" ) ) != NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
char psz_result[0x200];
|
|
Packit |
dd8086 |
int i_ret = fread( psz_result, 1, sizeof(psz_result) - 1, p_file );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( i_ret == 0 && ferror( p_file ) != 0 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
pclose( p_file );
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
pclose( p_file );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
psz_result[ i_ret ] = 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( 0 == i_ret )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
return DRIVER_OP_NO_DRIVER;
|
|
Packit |
dd8086 |
#endif /*HAVE_DARWIN_CDROM*/
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return a string containing the default CD device if none is specified.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
char **
|
|
Packit |
dd8086 |
cdio_get_devices_osx(void)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
#ifndef HAVE_DARWIN_CDROM
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
io_object_t next_media;
|
|
Packit |
dd8086 |
mach_port_t master_port;
|
|
Packit |
dd8086 |
kern_return_t kern_result;
|
|
Packit |
dd8086 |
io_iterator_t media_iterator;
|
|
Packit |
dd8086 |
CFMutableDictionaryRef classes_to_match;
|
|
Packit |
dd8086 |
char **drives = NULL;
|
|
Packit |
dd8086 |
unsigned int num_drives=0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Probe devices to get up to date information. */
|
|
Packit |
dd8086 |
ProbeStorageDevices();
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
|
|
Packit |
dd8086 |
if( kern_result != KERN_SUCCESS )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return( NULL );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
classes_to_match = IOServiceMatching( kIOMediaClass );
|
|
Packit |
dd8086 |
if( classes_to_match == NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return( NULL );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaEjectableKey),
|
|
Packit |
dd8086 |
kCFBooleanTrue );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaWholeKey),
|
|
Packit |
dd8086 |
kCFBooleanTrue );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
kern_result = IOServiceGetMatchingServices( master_port,
|
|
Packit |
dd8086 |
classes_to_match,
|
|
Packit |
dd8086 |
&media_iterator );
|
|
Packit |
dd8086 |
if( kern_result != KERN_SUCCESS )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return( NULL );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
next_media = IOIteratorNext( media_iterator );
|
|
Packit |
dd8086 |
if( next_media != 0 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
char psz_buf[0x32];
|
|
Packit |
dd8086 |
size_t dev_path_length;
|
|
Packit |
dd8086 |
CFTypeRef str_bsd_path;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
do
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
str_bsd_path =
|
|
Packit |
dd8086 |
IORegistryEntryCreateCFProperty( next_media,
|
|
Packit |
dd8086 |
CFSTR( kIOBSDNameKey ),
|
|
Packit |
dd8086 |
kCFAllocatorDefault,
|
|
Packit |
dd8086 |
0 );
|
|
Packit |
dd8086 |
if( str_bsd_path == NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
IOObjectRelease( next_media );
|
|
Packit |
dd8086 |
continue;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Below, by appending 'r' to the BSD node name, we indicate
|
|
Packit |
dd8086 |
a raw disk. Raw disks receive I/O requests directly and
|
|
Packit |
dd8086 |
don't go through a buffer cache. */
|
|
Packit |
dd8086 |
snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
|
|
Packit |
dd8086 |
dev_path_length = strlen( psz_buf );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( CFStringGetCString( str_bsd_path,
|
|
Packit |
dd8086 |
(char*)&psz_buf + dev_path_length,
|
|
Packit |
dd8086 |
sizeof(psz_buf) - dev_path_length,
|
|
Packit |
dd8086 |
kCFStringEncodingASCII ) )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
cdio_add_device_list(&drives, strdup(psz_buf), &num_drives);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
CFRelease( str_bsd_path );
|
|
Packit |
dd8086 |
IOObjectRelease( next_media );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
} while( ( next_media = IOIteratorNext( media_iterator ) ) != 0 );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
IOObjectRelease( media_iterator );
|
|
Packit |
dd8086 |
cdio_add_device_list(&drives, NULL, &num_drives);
|
|
Packit |
dd8086 |
return drives;
|
|
Packit |
dd8086 |
#endif /* HAVE_DARWIN_CDROM */
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return a string containing the default CD device if none is specified.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
char *
|
|
Packit |
dd8086 |
cdio_get_default_device_osx(void)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
#ifndef HAVE_DARWIN_CDROM
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
io_object_t next_media;
|
|
Packit |
dd8086 |
kern_return_t kern_result;
|
|
Packit |
dd8086 |
io_iterator_t media_iterator;
|
|
Packit |
dd8086 |
CFMutableDictionaryRef classes_to_match;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Probe devices to get up to date information. */
|
|
Packit |
dd8086 |
ProbeStorageDevices();
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
classes_to_match = IOServiceMatching( kIOMediaClass );
|
|
Packit |
dd8086 |
if( classes_to_match == NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return( NULL );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaEjectableKey),
|
|
Packit |
dd8086 |
kCFBooleanTrue );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaWholeKey),
|
|
Packit |
dd8086 |
kCFBooleanTrue );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
kern_result = IOServiceGetMatchingServices( kIOMasterPortDefault,
|
|
Packit |
dd8086 |
classes_to_match,
|
|
Packit |
dd8086 |
&media_iterator );
|
|
Packit |
dd8086 |
if( kern_result != KERN_SUCCESS )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return( NULL );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
next_media = IOIteratorNext( media_iterator );
|
|
Packit |
dd8086 |
if( next_media != 0 )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
char psz_buf[0x32];
|
|
Packit |
dd8086 |
size_t dev_path_length;
|
|
Packit |
dd8086 |
CFTypeRef str_bsd_path;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
do
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
/* Skip other removable media, like USB flash memory keys: */
|
|
Packit |
dd8086 |
if (!IOObjectConformsTo(next_media, kIODVDMediaClass) &&
|
|
Packit |
dd8086 |
!IOObjectConformsTo(next_media, kIOCDMediaClass) &&
|
|
Packit |
dd8086 |
!IOObjectConformsTo(next_media, kIOBDMediaClass))
|
|
Packit |
dd8086 |
continue;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
str_bsd_path = IORegistryEntryCreateCFProperty( next_media,
|
|
Packit |
dd8086 |
CFSTR( kIOBSDNameKey ),
|
|
Packit |
dd8086 |
kCFAllocatorDefault,
|
|
Packit |
dd8086 |
0 );
|
|
Packit |
dd8086 |
if( str_bsd_path == NULL )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
IOObjectRelease( next_media );
|
|
Packit |
dd8086 |
continue;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
|
|
Packit |
dd8086 |
dev_path_length = strlen( psz_buf );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if( CFStringGetCString( str_bsd_path,
|
|
Packit |
dd8086 |
(char*)&psz_buf + dev_path_length,
|
|
Packit |
dd8086 |
sizeof(psz_buf) - dev_path_length,
|
|
Packit |
dd8086 |
kCFStringEncodingASCII ) )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
CFRelease( str_bsd_path );
|
|
Packit |
dd8086 |
IOObjectRelease( next_media );
|
|
Packit |
dd8086 |
IOObjectRelease( media_iterator );
|
|
Packit |
dd8086 |
return strdup( psz_buf );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CFRelease( str_bsd_path );
|
|
Packit |
dd8086 |
IOObjectRelease( next_media );
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
} while( ( next_media = IOIteratorNext( media_iterator ) ) != 0 );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
IOObjectRelease( media_iterator );
|
|
Packit |
dd8086 |
cdio_warn ("cdio_get_default_device() - No CD/DVD/BD media - returning NULL");
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
#endif /* HAVE_DARWIN_CDROM */
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Initialization routine. This is the only thing that doesn't
|
|
Packit |
dd8086 |
get called via a function pointer. In fact *we* are the
|
|
Packit |
dd8086 |
ones to set that up.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
CdIo_t *
|
|
Packit |
dd8086 |
cdio_open_am_osx (const char *psz_source_name, const char *psz_access_mode)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (psz_access_mode != NULL)
|
|
Packit |
dd8086 |
cdio_warn ("there is only one access mode for OS X. Arg %s ignored",
|
|
Packit |
dd8086 |
psz_access_mode);
|
|
Packit |
dd8086 |
return cdio_open_osx(psz_source_name);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Initialization routine. This is the only thing that doesn't
|
|
Packit |
dd8086 |
get called via a function pointer. In fact *we* are the
|
|
Packit |
dd8086 |
ones to set that up.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
CdIo_t *
|
|
Packit |
dd8086 |
cdio_open_osx (const char *psz_orig_source)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
#ifdef HAVE_DARWIN_CDROM
|
|
Packit |
dd8086 |
CdIo_t *ret;
|
|
Packit |
dd8086 |
_img_private_t *_data;
|
|
Packit |
dd8086 |
char *psz_source;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdio_funcs_t _funcs = {
|
|
Packit |
dd8086 |
.eject_media = _eject_media_osx,
|
|
Packit |
dd8086 |
.free = _free_osx,
|
|
Packit |
dd8086 |
.get_arg = _get_arg_osx,
|
|
Packit |
dd8086 |
.get_cdtext = get_cdtext_generic,
|
|
Packit |
dd8086 |
.get_cdtext_raw = read_cdtext_generic,
|
|
Packit |
dd8086 |
.get_default_device = cdio_get_default_device_osx,
|
|
Packit |
dd8086 |
.get_devices = cdio_get_devices_osx,
|
|
Packit |
dd8086 |
.get_disc_last_lsn = get_disc_last_lsn_osx,
|
|
Packit |
dd8086 |
.get_discmode = get_discmode_osx,
|
|
Packit |
dd8086 |
.get_drive_cap = get_drive_cap_osx,
|
|
Packit |
dd8086 |
.get_first_track_num = get_first_track_num_generic,
|
|
Packit |
dd8086 |
.get_hwinfo = get_hwinfo_osx,
|
|
Packit |
dd8086 |
.get_mcn = get_mcn_osx,
|
|
Packit |
dd8086 |
.get_num_tracks = get_num_tracks_generic,
|
|
Packit |
dd8086 |
.get_track_channels = get_track_channels_generic,
|
|
Packit |
dd8086 |
.get_track_copy_permit = get_track_copy_permit_generic,
|
|
Packit |
dd8086 |
.get_track_format = get_track_format_osx,
|
|
Packit |
dd8086 |
.get_track_green = get_track_green_osx,
|
|
Packit |
dd8086 |
.get_track_lba = get_track_lba_osx,
|
|
Packit |
dd8086 |
.get_track_msf = NULL,
|
|
Packit |
dd8086 |
.get_track_preemphasis = get_track_preemphasis_generic,
|
|
Packit |
dd8086 |
.get_track_isrc = get_track_isrc_osx,
|
|
Packit |
dd8086 |
.lseek = cdio_generic_lseek,
|
|
Packit |
dd8086 |
.read = cdio_generic_read,
|
|
Packit |
dd8086 |
.read_audio_sectors = read_audio_sectors_osx,
|
|
Packit |
dd8086 |
.read_data_sectors = read_data_sectors_osx,
|
|
Packit |
dd8086 |
.read_mode1_sector = read_mode1_sector_osx,
|
|
Packit |
dd8086 |
.read_mode1_sectors = read_mode1_sectors_osx,
|
|
Packit |
dd8086 |
.read_mode2_sector = read_mode2_sector_osx,
|
|
Packit |
dd8086 |
.read_mode2_sectors = read_mode2_sectors_osx,
|
|
Packit |
dd8086 |
.read_toc = read_toc_osx,
|
|
Packit |
dd8086 |
.run_mmc_cmd = run_mmc_cmd_osx,
|
|
Packit |
dd8086 |
.set_arg = _set_arg_osx,
|
|
Packit |
dd8086 |
.set_speed = set_speed_osx,
|
|
Packit |
dd8086 |
};
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
_data = calloc (1, sizeof (_img_private_t));
|
|
Packit |
dd8086 |
_data->access_mode = _AM_OSX;
|
|
Packit |
dd8086 |
_data->MediaClass_service = 0;
|
|
Packit |
dd8086 |
_data->gen.init = false;
|
|
Packit |
dd8086 |
_data->gen.fd = -1;
|
|
Packit |
dd8086 |
_data->gen.toc_init = false;
|
|
Packit |
dd8086 |
_data->gen.b_cdtext_error = false;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (NULL == psz_orig_source) {
|
|
Packit |
dd8086 |
psz_source=cdio_get_default_device_osx();
|
|
Packit |
dd8086 |
if (NULL == psz_source) {
|
|
Packit |
dd8086 |
goto error_exit;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
_set_arg_osx(_data, "source", psz_source);
|
|
Packit |
dd8086 |
free(psz_source);
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
if (cdio_is_device_generic(psz_orig_source))
|
|
Packit |
dd8086 |
_set_arg_osx(_data, "source", psz_orig_source);
|
|
Packit |
dd8086 |
else {
|
|
Packit |
dd8086 |
/* The below would be okay if all device drivers worked this way. */
|
|
Packit |
dd8086 |
#if 0
|
|
Packit |
dd8086 |
cdio_info ("source %s is a not a device", psz_orig_source);
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
goto error_exit;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ret = cdio_new ((void *)_data, &_funcs);
|
|
Packit |
dd8086 |
if (ret == NULL)
|
|
Packit |
dd8086 |
goto error_exit;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
ret->driver_id = DRIVER_OSX;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (cdio_generic_init(_data, O_RDONLY | O_NONBLOCK) && init_osx(_data)) {
|
|
Packit |
dd8086 |
return ret;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
free(ret);
|
|
Packit |
dd8086 |
error_exit:
|
|
Packit |
dd8086 |
cdio_generic_free(_data);
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
#endif /* HAVE_DARWIN_CDROM */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
bool
|
|
Packit |
dd8086 |
cdio_have_osx (void)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
#ifdef HAVE_DARWIN_CDROM
|
|
Packit |
dd8086 |
return true;
|
|
Packit |
dd8086 |
#else
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
#endif /* HAVE_DARWIN_CDROM */
|
|
Packit |
dd8086 |
}
|